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 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
306 e = new EnumConstant (e, expr_type);
311 throw new Exception ("Can not constant fold: " + Oper.ToString());
314 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
316 eclass = ExprClass.Value;
318 TypeSpec expr_type = expr.Type;
319 Expression best_expr;
321 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
324 // Primitive types first
326 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
327 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
328 if (best_expr == null)
331 type = best_expr.Type;
337 // E operator ~(E x);
339 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
340 return ResolveEnumOperator (ec, expr, predefined);
342 return ResolveUserType (ec, expr, predefined);
345 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
347 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
348 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
349 if (best_expr == null)
353 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (best_expr.Type), underlying_type);
355 return EmptyCast.Create (this, type);
358 public override bool ContainsEmitWithAwait ()
360 return Expr.ContainsEmitWithAwait ();
363 public override Expression CreateExpressionTree (ResolveContext ec)
365 return CreateExpressionTree (ec, null);
368 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
372 case Operator.AddressOf:
373 Error_PointerInsideExpressionTree (ec);
375 case Operator.UnaryNegation:
376 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
377 method_name = "NegateChecked";
379 method_name = "Negate";
381 case Operator.OnesComplement:
382 case Operator.LogicalNot:
385 case Operator.UnaryPlus:
386 method_name = "UnaryPlus";
389 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
392 Arguments args = new Arguments (2);
393 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
395 args.Add (new Argument (user_op));
397 return CreateExpressionFactoryCall (ec, method_name, args);
400 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
402 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
405 // 7.6.1 Unary plus operator
407 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
408 types.Int, types.UInt,
409 types.Long, types.ULong,
410 types.Float, types.Double,
415 // 7.6.2 Unary minus operator
417 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
418 types.Int, types.Long,
419 types.Float, types.Double,
424 // 7.6.3 Logical negation operator
426 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
431 // 7.6.4 Bitwise complement operator
433 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
434 types.Int, types.UInt,
435 types.Long, types.ULong
438 return predefined_operators;
442 // Unary numeric promotions
444 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
446 TypeSpec expr_type = expr.Type;
447 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
448 switch (expr_type.BuiltinType) {
449 case BuiltinTypeSpec.Type.Byte:
450 case BuiltinTypeSpec.Type.SByte:
451 case BuiltinTypeSpec.Type.Short:
452 case BuiltinTypeSpec.Type.UShort:
453 case BuiltinTypeSpec.Type.Char:
454 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
458 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
459 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
464 protected override Expression DoResolve (ResolveContext ec)
466 if (Oper == Operator.AddressOf) {
467 return ResolveAddressOf (ec);
470 Expr = Expr.Resolve (ec);
474 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
475 Arguments args = new Arguments (1);
476 args.Add (new Argument (Expr));
477 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
480 if (Expr.Type.IsNullableType)
481 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
484 // Attempt to use a constant folding operation.
486 Constant cexpr = Expr as Constant;
488 cexpr = TryReduceConstant (ec, cexpr);
493 Expression expr = ResolveOperator (ec, Expr);
495 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
498 // Reduce unary operator on predefined types
500 if (expr == this && Oper == Operator.UnaryPlus)
506 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
511 public override void Emit (EmitContext ec)
513 EmitOperator (ec, type);
516 protected void EmitOperator (EmitContext ec, TypeSpec type)
519 case Operator.UnaryPlus:
523 case Operator.UnaryNegation:
524 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
525 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
526 Expr = Expr.EmitToField (ec);
529 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
530 ec.Emit (OpCodes.Conv_U8);
532 ec.Emit (OpCodes.Sub_Ovf);
535 ec.Emit (OpCodes.Neg);
540 case Operator.LogicalNot:
543 ec.Emit (OpCodes.Ceq);
546 case Operator.OnesComplement:
548 ec.Emit (OpCodes.Not);
551 case Operator.AddressOf:
552 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
556 throw new Exception ("This should not happen: Operator = "
561 // Same trick as in Binary expression
563 if (enum_conversion != null)
564 enum_conversion.Emit (ec);
567 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
569 if (Oper == Operator.LogicalNot)
570 Expr.EmitBranchable (ec, target, !on_true);
572 base.EmitBranchable (ec, target, on_true);
575 public override void EmitSideEffect (EmitContext ec)
577 Expr.EmitSideEffect (ec);
580 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
582 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
583 oper, type.GetSignatureForError ());
586 public override void FlowAnalysis (FlowAnalysisContext fc)
588 if (Oper == Operator.AddressOf) {
589 var vr = Expr as VariableReference;
590 if (vr != null && vr.VariableInfo != null)
591 fc.SetVariableAssigned (vr.VariableInfo);
596 Expr.FlowAnalysis (fc);
598 if (Oper == Operator.LogicalNot) {
599 var temp = fc.DefiniteAssignmentOnTrue;
600 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
601 fc.DefiniteAssignmentOnFalse = temp;
606 // Converts operator to System.Linq.Expressions.ExpressionType enum name
608 string GetOperatorExpressionTypeName ()
611 case Operator.OnesComplement:
612 return "OnesComplement";
613 case Operator.LogicalNot:
615 case Operator.UnaryNegation:
617 case Operator.UnaryPlus:
620 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
624 static bool IsFloat (TypeSpec t)
626 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
630 // Returns a stringified representation of the Operator
632 public static string OperName (Operator oper)
635 case Operator.UnaryPlus:
637 case Operator.UnaryNegation:
639 case Operator.LogicalNot:
641 case Operator.OnesComplement:
643 case Operator.AddressOf:
647 throw new NotImplementedException (oper.ToString ());
650 public override SLE.Expression MakeExpression (BuilderContext ctx)
652 var expr = Expr.MakeExpression (ctx);
653 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
656 case Operator.UnaryNegation:
657 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
658 case Operator.LogicalNot:
659 return SLE.Expression.Not (expr);
660 #if NET_4_0 || MONODROID
661 case Operator.OnesComplement:
662 return SLE.Expression.OnesComplement (expr);
665 throw new NotImplementedException (Oper.ToString ());
669 Expression ResolveAddressOf (ResolveContext ec)
672 UnsafeError (ec, loc);
674 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
675 if (Expr == null || Expr.eclass != ExprClass.Variable) {
676 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
680 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
684 IVariableReference vr = Expr as IVariableReference;
687 is_fixed = vr.IsFixed;
688 vr.SetHasAddressTaken ();
691 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
694 IFixedExpression fe = Expr as IFixedExpression;
695 is_fixed = fe != null && fe.IsFixed;
698 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
699 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
702 type = PointerContainer.MakeType (ec.Module, Expr.Type);
703 eclass = ExprClass.Value;
707 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
709 expr = DoNumericPromotion (rc, Oper, expr);
710 TypeSpec expr_type = expr.Type;
711 foreach (TypeSpec t in predefined) {
719 // Perform user-operator overload resolution
721 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
723 CSharp.Operator.OpType op_type;
725 case Operator.LogicalNot:
726 op_type = CSharp.Operator.OpType.LogicalNot; break;
727 case Operator.OnesComplement:
728 op_type = CSharp.Operator.OpType.OnesComplement; break;
729 case Operator.UnaryNegation:
730 op_type = CSharp.Operator.OpType.UnaryNegation; break;
731 case Operator.UnaryPlus:
732 op_type = CSharp.Operator.OpType.UnaryPlus; break;
734 throw new InternalErrorException (Oper.ToString ());
737 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
741 Arguments args = new Arguments (1);
742 args.Add (new Argument (expr));
744 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
745 var oper = res.ResolveOperator (ec, ref args);
750 Expr = args [0].Expr;
751 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
755 // Unary user type overload resolution
757 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
759 Expression best_expr = ResolveUserOperator (ec, expr);
760 if (best_expr != null)
763 foreach (TypeSpec t in predefined) {
764 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
765 if (oper_expr == null)
768 if (oper_expr == ErrorExpression.Instance)
772 // decimal type is predefined but has user-operators
774 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
775 oper_expr = ResolveUserType (ec, oper_expr, predefined);
777 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
779 if (oper_expr == null)
782 if (best_expr == null) {
783 best_expr = oper_expr;
787 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
789 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
790 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
792 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
799 best_expr = oper_expr;
802 if (best_expr == null)
806 // HACK: Decimal user-operator is included in standard operators
808 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
812 type = best_expr.Type;
816 protected override void CloneTo (CloneContext clonectx, Expression t)
818 Unary target = (Unary) t;
820 target.Expr = Expr.Clone (clonectx);
823 public override object Accept (StructuralVisitor visitor)
825 return visitor.Visit (this);
831 // Unary operators are turned into Indirection expressions
832 // after semantic analysis (this is so we can take the address
833 // of an indirection).
835 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
837 LocalTemporary temporary;
840 public Indirection (Expression expr, Location l)
846 public Expression Expr {
852 public bool IsFixed {
856 public override Location StartLocation {
858 return expr.StartLocation;
862 protected override void CloneTo (CloneContext clonectx, Expression t)
864 Indirection target = (Indirection) t;
865 target.expr = expr.Clone (clonectx);
868 public override bool ContainsEmitWithAwait ()
870 throw new NotImplementedException ();
873 public override Expression CreateExpressionTree (ResolveContext ec)
875 Error_PointerInsideExpressionTree (ec);
879 public override void Emit (EmitContext ec)
884 ec.EmitLoadFromPtr (Type);
887 public void Emit (EmitContext ec, bool leave_copy)
891 ec.Emit (OpCodes.Dup);
892 temporary = new LocalTemporary (expr.Type);
893 temporary.Store (ec);
897 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
899 prepared = isCompound;
904 ec.Emit (OpCodes.Dup);
908 ec.Emit (OpCodes.Dup);
909 temporary = new LocalTemporary (source.Type);
910 temporary.Store (ec);
913 ec.EmitStoreFromPtr (type);
915 if (temporary != null) {
917 temporary.Release (ec);
921 public void AddressOf (EmitContext ec, AddressOp Mode)
926 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
928 return DoResolve (ec);
931 protected override Expression DoResolve (ResolveContext ec)
933 expr = expr.Resolve (ec);
938 UnsafeError (ec, loc);
940 var pc = expr.Type as PointerContainer;
943 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
949 if (type.Kind == MemberKind.Void) {
950 Error_VoidPointerOperation (ec);
954 eclass = ExprClass.Variable;
958 public override object Accept (StructuralVisitor visitor)
960 return visitor.Visit (this);
965 /// Unary Mutator expressions (pre and post ++ and --)
969 /// UnaryMutator implements ++ and -- expressions. It derives from
970 /// ExpressionStatement becuase the pre/post increment/decrement
971 /// operators can be used in a statement context.
973 /// FIXME: Idea, we could split this up in two classes, one simpler
974 /// for the common case, and one with the extra fields for more complex
975 /// classes (indexers require temporary access; overloaded require method)
978 public class UnaryMutator : ExpressionStatement
980 class DynamicPostMutator : Expression, IAssignMethod
985 public DynamicPostMutator (Expression expr)
988 this.type = expr.Type;
989 this.loc = expr.Location;
992 public override Expression CreateExpressionTree (ResolveContext ec)
994 throw new NotImplementedException ("ET");
997 protected override Expression DoResolve (ResolveContext rc)
999 eclass = expr.eclass;
1003 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1005 expr.DoResolveLValue (ec, right_side);
1006 return DoResolve (ec);
1009 public override void Emit (EmitContext ec)
1014 public void Emit (EmitContext ec, bool leave_copy)
1016 throw new NotImplementedException ();
1020 // Emits target assignment using unmodified source value
1022 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1025 // Allocate temporary variable to keep original value before it's modified
1027 temp = new LocalTemporary (type);
1031 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1042 public enum Mode : byte {
1049 PreDecrement = IsDecrement,
1050 PostIncrement = IsPost,
1051 PostDecrement = IsPost | IsDecrement
1055 bool is_expr, recurse;
1057 protected Expression expr;
1059 // Holds the real operation
1060 Expression operation;
1062 public UnaryMutator (Mode m, Expression e, Location loc)
1069 public Mode UnaryMutatorMode {
1075 public Expression Expr {
1081 public override Location StartLocation {
1083 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1087 public override bool ContainsEmitWithAwait ()
1089 return expr.ContainsEmitWithAwait ();
1092 public override Expression CreateExpressionTree (ResolveContext ec)
1094 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1097 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1100 // Predefined ++ and -- operators exist for the following types:
1101 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1103 return new TypeSpec[] {
1119 protected override Expression DoResolve (ResolveContext ec)
1121 expr = expr.Resolve (ec);
1126 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1128 // Handle postfix unary operators using local
1129 // temporary variable
1131 if ((mode & Mode.IsPost) != 0)
1132 expr = new DynamicPostMutator (expr);
1134 Arguments args = new Arguments (1);
1135 args.Add (new Argument (expr));
1136 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1139 if (expr.Type.IsNullableType)
1140 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1142 return DoResolveOperation (ec);
1145 protected Expression DoResolveOperation (ResolveContext ec)
1147 eclass = ExprClass.Value;
1150 if (expr is RuntimeValueExpression) {
1153 // Use itself at the top of the stack
1154 operation = new EmptyExpression (type);
1158 // The operand of the prefix/postfix increment decrement operators
1159 // should be an expression that is classified as a variable,
1160 // a property access or an indexer access
1162 // TODO: Move to parser, expr is ATypeNameExpression
1163 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1164 expr = expr.ResolveLValue (ec, expr);
1166 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1170 // Step 1: Try to find a user operator, it has priority over predefined ones
1172 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1173 var methods = MemberCache.GetUserOperator (type, user_op, false);
1175 if (methods != null) {
1176 Arguments args = new Arguments (1);
1177 args.Add (new Argument (expr));
1179 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1180 var method = res.ResolveOperator (ec, ref args);
1184 args[0].Expr = operation;
1185 operation = new UserOperatorCall (method, args, null, loc);
1186 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1191 // Step 2: Try predefined types
1194 Expression source = null;
1195 bool primitive_type;
1198 // Predefined without user conversion first for speed-up
1200 // Predefined ++ and -- operators exist for the following types:
1201 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1203 switch (type.BuiltinType) {
1204 case BuiltinTypeSpec.Type.Byte:
1205 case BuiltinTypeSpec.Type.SByte:
1206 case BuiltinTypeSpec.Type.Short:
1207 case BuiltinTypeSpec.Type.UShort:
1208 case BuiltinTypeSpec.Type.Int:
1209 case BuiltinTypeSpec.Type.UInt:
1210 case BuiltinTypeSpec.Type.Long:
1211 case BuiltinTypeSpec.Type.ULong:
1212 case BuiltinTypeSpec.Type.Char:
1213 case BuiltinTypeSpec.Type.Float:
1214 case BuiltinTypeSpec.Type.Double:
1215 case BuiltinTypeSpec.Type.Decimal:
1217 primitive_type = true;
1220 primitive_type = false;
1222 // ++/-- on pointer variables of all types except void*
1223 if (type.IsPointer) {
1224 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1225 Error_VoidPointerOperation (ec);
1231 Expression best_source = null;
1232 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1233 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1235 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1239 if (best_source == null) {
1240 best_source = source;
1244 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1249 best_source = source;
1253 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1257 source = best_source;
1260 // ++/-- on enum types
1261 if (source == null && type.IsEnum)
1264 if (source == null) {
1265 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1272 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1273 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1274 operation = new Binary (op, source, one);
1275 operation = operation.Resolve (ec);
1276 if (operation == null)
1277 throw new NotImplementedException ("should not be reached");
1279 if (operation.Type != type) {
1281 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1283 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1289 void EmitCode (EmitContext ec, bool is_expr)
1292 this.is_expr = is_expr;
1293 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1296 public override void Emit (EmitContext ec)
1299 // We use recurse to allow ourselfs to be the source
1300 // of an assignment. This little hack prevents us from
1301 // having to allocate another expression
1304 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1312 EmitCode (ec, true);
1315 protected virtual void EmitOperation (EmitContext ec)
1317 operation.Emit (ec);
1320 public override void EmitStatement (EmitContext ec)
1322 EmitCode (ec, false);
1325 public override void FlowAnalysis (FlowAnalysisContext fc)
1327 expr.FlowAnalysis (fc);
1331 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1333 string GetOperatorExpressionTypeName ()
1335 return IsDecrement ? "Decrement" : "Increment";
1339 get { return (mode & Mode.IsDecrement) != 0; }
1343 #if NET_4_0 || MONODROID
1344 public override SLE.Expression MakeExpression (BuilderContext ctx)
1346 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1347 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1348 return SLE.Expression.Assign (target, source);
1352 public static string OperName (Mode oper)
1354 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1357 protected override void CloneTo (CloneContext clonectx, Expression t)
1359 UnaryMutator target = (UnaryMutator) t;
1361 target.expr = expr.Clone (clonectx);
1364 public override object Accept (StructuralVisitor visitor)
1366 return visitor.Visit (this);
1372 // Base class for the `is' and `as' operators
1374 public abstract class Probe : Expression
1376 public Expression ProbeType;
1377 protected Expression expr;
1378 protected TypeSpec probe_type_expr;
1380 protected Probe (Expression expr, Expression probe_type, Location l)
1382 ProbeType = probe_type;
1387 public Expression Expr {
1393 public override bool ContainsEmitWithAwait ()
1395 return expr.ContainsEmitWithAwait ();
1398 protected override Expression DoResolve (ResolveContext ec)
1400 probe_type_expr = ProbeType.ResolveAsType (ec);
1401 if (probe_type_expr == null)
1404 expr = expr.Resolve (ec);
1408 if (probe_type_expr.IsStatic) {
1409 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1413 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1414 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1419 if (expr.Type == InternalType.AnonymousMethod) {
1420 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1428 public override void FlowAnalysis (FlowAnalysisContext fc)
1430 expr.FlowAnalysis (fc);
1433 protected abstract string OperatorName { get; }
1435 protected override void CloneTo (CloneContext clonectx, Expression t)
1437 Probe target = (Probe) t;
1439 target.expr = expr.Clone (clonectx);
1440 target.ProbeType = ProbeType.Clone (clonectx);
1446 /// Implementation of the `is' operator.
1448 public class Is : Probe
1450 Nullable.Unwrap expr_unwrap;
1452 public Is (Expression expr, Expression probe_type, Location l)
1453 : base (expr, probe_type, l)
1457 protected override string OperatorName {
1458 get { return "is"; }
1461 public override Expression CreateExpressionTree (ResolveContext ec)
1463 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1464 expr.CreateExpressionTree (ec),
1465 new TypeOf (probe_type_expr, loc));
1467 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1470 public override void Emit (EmitContext ec)
1472 if (expr_unwrap != null) {
1473 expr_unwrap.EmitCheck (ec);
1479 // Only to make verifier happy
1480 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1481 ec.Emit (OpCodes.Box, expr.Type);
1483 ec.Emit (OpCodes.Isinst, probe_type_expr);
1485 ec.Emit (OpCodes.Cgt_Un);
1488 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1490 if (expr_unwrap != null) {
1491 expr_unwrap.EmitCheck (ec);
1494 ec.Emit (OpCodes.Isinst, probe_type_expr);
1496 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1499 Expression CreateConstantResult (ResolveContext ec, bool result)
1502 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1503 probe_type_expr.GetSignatureForError ());
1505 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1506 probe_type_expr.GetSignatureForError ());
1508 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, result, loc), this);
1511 protected override Expression DoResolve (ResolveContext ec)
1513 if (base.DoResolve (ec) == null)
1516 TypeSpec d = expr.Type;
1517 bool d_is_nullable = false;
1520 // If E is a method group or the null literal, or if the type of E is a reference
1521 // type or a nullable type and the value of E is null, the result is false
1523 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1524 return CreateConstantResult (ec, false);
1526 if (d.IsNullableType) {
1527 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1528 if (!ut.IsGenericParameter) {
1530 d_is_nullable = true;
1534 type = ec.BuiltinTypes.Bool;
1535 eclass = ExprClass.Value;
1536 TypeSpec t = probe_type_expr;
1537 bool t_is_nullable = false;
1538 if (t.IsNullableType) {
1539 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1540 if (!ut.IsGenericParameter) {
1542 t_is_nullable = true;
1549 // D and T are the same value types but D can be null
1551 if (d_is_nullable && !t_is_nullable) {
1552 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1557 // The result is true if D and T are the same value types
1559 return CreateConstantResult (ec, true);
1562 var tp = d as TypeParameterSpec;
1564 return ResolveGenericParameter (ec, t, tp);
1567 // An unboxing conversion exists
1569 if (Convert.ExplicitReferenceConversionExists (d, t))
1573 // open generic type
1575 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1578 var tps = t as TypeParameterSpec;
1580 return ResolveGenericParameter (ec, d, tps);
1582 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1583 ec.Report.Warning (1981, 3, loc,
1584 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1585 OperatorName, t.GetSignatureForError ());
1588 if (TypeManager.IsGenericParameter (d))
1589 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1591 if (TypeSpec.IsValueType (d)) {
1592 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1593 if (d_is_nullable && !t_is_nullable) {
1594 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1598 return CreateConstantResult (ec, true);
1601 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1602 var c = expr as Constant;
1604 return CreateConstantResult (ec, !c.IsNull);
1607 // Do not optimize for imported type
1609 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1610 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1615 // Turn is check into simple null check for implicitly convertible reference types
1617 return ReducedExpression.Create (
1618 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1622 if (Convert.ExplicitReferenceConversionExists (d, t))
1626 // open generic type
1628 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1633 return CreateConstantResult (ec, false);
1636 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1638 if (t.IsReferenceType) {
1640 return CreateConstantResult (ec, false);
1643 if (expr.Type.IsGenericParameter) {
1644 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1645 return CreateConstantResult (ec, true);
1647 expr = new BoxedCast (expr, d);
1653 public override object Accept (StructuralVisitor visitor)
1655 return visitor.Visit (this);
1660 /// Implementation of the `as' operator.
1662 public class As : Probe {
1663 Expression resolved_type;
1665 public As (Expression expr, Expression probe_type, Location l)
1666 : base (expr, probe_type, l)
1670 protected override string OperatorName {
1671 get { return "as"; }
1674 public override Expression CreateExpressionTree (ResolveContext ec)
1676 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1677 expr.CreateExpressionTree (ec),
1678 new TypeOf (probe_type_expr, loc));
1680 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1683 public override void Emit (EmitContext ec)
1687 ec.Emit (OpCodes.Isinst, type);
1689 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1690 ec.Emit (OpCodes.Unbox_Any, type);
1693 protected override Expression DoResolve (ResolveContext ec)
1695 if (resolved_type == null) {
1696 resolved_type = base.DoResolve (ec);
1698 if (resolved_type == null)
1702 type = probe_type_expr;
1703 eclass = ExprClass.Value;
1704 TypeSpec etype = expr.Type;
1706 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1707 if (TypeManager.IsGenericParameter (type)) {
1708 ec.Report.Error (413, loc,
1709 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1710 probe_type_expr.GetSignatureForError ());
1712 ec.Report.Error (77, loc,
1713 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1714 type.GetSignatureForError ());
1719 if (expr.IsNull && type.IsNullableType) {
1720 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1723 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1724 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1728 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1730 e = EmptyCast.Create (e, type);
1731 return ReducedExpression.Create (e, this).Resolve (ec);
1734 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1735 if (TypeManager.IsGenericParameter (etype))
1736 expr = new BoxedCast (expr, etype);
1741 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1742 expr = new BoxedCast (expr, etype);
1746 if (etype != InternalType.ErrorType) {
1747 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1748 etype.GetSignatureForError (), type.GetSignatureForError ());
1754 public override object Accept (StructuralVisitor visitor)
1756 return visitor.Visit (this);
1761 // This represents a typecast in the source language.
1763 public class Cast : ShimExpression {
1764 Expression target_type;
1766 public Cast (Expression cast_type, Expression expr, Location loc)
1769 this.target_type = cast_type;
1773 public Expression TargetType {
1774 get { return target_type; }
1777 protected override Expression DoResolve (ResolveContext ec)
1779 expr = expr.Resolve (ec);
1783 type = target_type.ResolveAsType (ec);
1787 if (type.IsStatic) {
1788 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
1792 if (type.IsPointer && !ec.IsUnsafe) {
1793 UnsafeError (ec, loc);
1796 eclass = ExprClass.Value;
1798 Constant c = expr as Constant;
1800 c = c.Reduce (ec, type);
1805 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1807 return EmptyCast.Create (res, type);
1812 protected override void CloneTo (CloneContext clonectx, Expression t)
1814 Cast target = (Cast) t;
1816 target.target_type = target_type.Clone (clonectx);
1817 target.expr = expr.Clone (clonectx);
1820 public override object Accept (StructuralVisitor visitor)
1822 return visitor.Visit (this);
1826 public class ImplicitCast : ShimExpression
1830 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1833 this.loc = expr.Location;
1835 this.arrayAccess = arrayAccess;
1838 protected override Expression DoResolve (ResolveContext ec)
1840 expr = expr.Resolve (ec);
1845 expr = ConvertExpressionToArrayIndex (ec, expr);
1847 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1854 // C# 2.0 Default value expression
1856 public class DefaultValueExpression : Expression
1860 public DefaultValueExpression (Expression expr, Location loc)
1866 public Expression Expr {
1872 public override bool IsSideEffectFree {
1878 public override bool ContainsEmitWithAwait ()
1883 public override Expression CreateExpressionTree (ResolveContext ec)
1885 Arguments args = new Arguments (2);
1886 args.Add (new Argument (this));
1887 args.Add (new Argument (new TypeOf (type, loc)));
1888 return CreateExpressionFactoryCall (ec, "Constant", args);
1891 protected override Expression DoResolve (ResolveContext ec)
1893 type = expr.ResolveAsType (ec);
1897 if (type.IsStatic) {
1898 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1902 return new NullLiteral (Location).ConvertImplicitly (type);
1904 if (TypeSpec.IsReferenceType (type))
1905 return new NullConstant (type, loc);
1907 Constant c = New.Constantify (type, expr.Location);
1911 eclass = ExprClass.Variable;
1915 public override void Emit (EmitContext ec)
1917 LocalTemporary temp_storage = new LocalTemporary(type);
1919 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1920 ec.Emit(OpCodes.Initobj, type);
1921 temp_storage.Emit(ec);
1922 temp_storage.Release (ec);
1925 #if (NET_4_0 || MONODROID) && !STATIC
1926 public override SLE.Expression MakeExpression (BuilderContext ctx)
1928 return SLE.Expression.Default (type.GetMetaInfo ());
1932 protected override void CloneTo (CloneContext clonectx, Expression t)
1934 DefaultValueExpression target = (DefaultValueExpression) t;
1936 target.expr = expr.Clone (clonectx);
1939 public override object Accept (StructuralVisitor visitor)
1941 return visitor.Visit (this);
1946 /// Binary operators
1948 public class Binary : Expression, IDynamicBinder
1950 public class PredefinedOperator
1952 protected readonly TypeSpec left;
1953 protected readonly TypeSpec right;
1954 protected readonly TypeSpec left_unwrap;
1955 protected readonly TypeSpec right_unwrap;
1956 public readonly Operator OperatorsMask;
1957 public TypeSpec ReturnType;
1959 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1960 : this (ltype, rtype, op_mask, ltype)
1964 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1965 : this (type, type, op_mask, return_type)
1969 public PredefinedOperator (TypeSpec type, Operator op_mask)
1970 : this (type, type, op_mask, type)
1974 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1976 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1977 throw new InternalErrorException ("Only masked values can be used");
1979 if ((op_mask & Operator.NullableMask) != 0) {
1980 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
1981 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
1983 left_unwrap = ltype;
1984 right_unwrap = rtype;
1989 this.OperatorsMask = op_mask;
1990 this.ReturnType = return_type;
1993 public bool IsLifted {
1995 return (OperatorsMask & Operator.NullableMask) != 0;
1999 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2003 var left_expr = b.left;
2004 var right_expr = b.right;
2006 b.type = ReturnType;
2009 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2010 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2011 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2014 if (right_expr.IsNull) {
2015 if ((b.oper & Operator.EqualityMask) != 0) {
2016 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2017 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2018 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2019 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2020 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2022 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2023 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2025 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2026 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2028 return b.CreateLiftedValueTypeResult (rc, left);
2030 } else if (left_expr.IsNull) {
2031 if ((b.oper & Operator.EqualityMask) != 0) {
2032 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2033 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2034 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2035 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2036 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2038 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2039 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2041 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2042 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2044 return b.CreateLiftedValueTypeResult (rc, right);
2050 // A user operators does not support multiple user conversions, but decimal type
2051 // is considered to be predefined type therefore we apply predefined operators rules
2052 // and then look for decimal user-operator implementation
2054 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2055 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2056 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2058 return b.ResolveUserOperator (rc, b.left, b.right);
2061 c = right_expr as Constant;
2063 if (c.IsDefaultValue) {
2067 // (expr + 0) to expr
2068 // (expr - 0) to expr
2069 // (bool? | false) to bool?
2071 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2072 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2073 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2074 return ReducedExpression.Create (b.left, b).Resolve (rc);
2078 // Optimizes (value &/&& 0) to 0
2080 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2081 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2082 return ReducedExpression.Create (side_effect, b);
2086 // Optimizes (bool? & true) to bool?
2088 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2089 return ReducedExpression.Create (b.left, b).Resolve (rc);
2093 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2094 return ReducedExpression.Create (b.left, b).Resolve (rc);
2096 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2097 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2101 c = b.left as Constant;
2103 if (c.IsDefaultValue) {
2107 // (0 + expr) to expr
2108 // (false | bool?) to bool?
2110 if (b.oper == Operator.Addition ||
2111 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2112 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2113 return ReducedExpression.Create (b.right, b).Resolve (rc);
2117 // Optimizes (false && expr) to false
2119 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2120 // No rhs side-effects
2121 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2122 return ReducedExpression.Create (c, b);
2126 // Optimizes (0 & value) to 0
2128 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2129 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2130 return ReducedExpression.Create (side_effect, b);
2134 // Optimizes (true & bool?) to bool?
2136 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2137 return ReducedExpression.Create (b.right, b).Resolve (rc);
2141 // Optimizes (true || expr) to true
2143 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2144 // No rhs side-effects
2145 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2146 return ReducedExpression.Create (c, b);
2150 if (b.oper == Operator.Multiply && c.IsOneInteger)
2151 return ReducedExpression.Create (b.right, b).Resolve (rc);
2155 var lifted = new Nullable.LiftedBinaryOperator (b);
2157 TypeSpec ltype, rtype;
2158 if (b.left.Type.IsNullableType) {
2159 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2160 ltype = left_unwrap;
2165 if (b.right.Type.IsNullableType) {
2166 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2167 rtype = right_unwrap;
2172 lifted.Left = b.left.IsNull ?
2174 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2176 lifted.Right = b.right.IsNull ?
2178 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2180 return lifted.Resolve (rc);
2183 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2184 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2189 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2192 // We are dealing with primitive types only
2194 return left == ltype && ltype == rtype;
2197 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2200 if (left == lexpr.Type && right == rexpr.Type)
2203 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2204 Convert.ImplicitConversionExists (ec, rexpr, right);
2207 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2209 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2210 return best_operator;
2212 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2216 if (left != null && best_operator.left != null) {
2217 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2221 // When second argument is same as the first one, the result is same
2223 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2224 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2227 if (result == 0 || result > 2)
2230 return result == 1 ? best_operator : this;
2234 sealed class PredefinedStringOperator : PredefinedOperator
2236 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2237 : base (type, type, op_mask, retType)
2241 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2242 : base (ltype, rtype, op_mask, retType)
2246 public override Expression ConvertResult (ResolveContext ec, Binary b)
2249 // Use original expression for nullable arguments
2251 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2253 b.left = unwrap.Original;
2255 unwrap = b.right as Nullable.Unwrap;
2257 b.right = unwrap.Original;
2259 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2260 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2263 // Start a new concat expression using converted expression
2265 return StringConcat.Create (ec, b.left, b.right, b.loc);
2269 sealed class PredefinedEqualityOperator : PredefinedOperator
2271 MethodSpec equal_method, inequal_method;
2273 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
2274 : base (arg, arg, Operator.EqualityMask, retType)
2278 public override Expression ConvertResult (ResolveContext ec, Binary b)
2280 b.type = ReturnType;
2282 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2283 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2285 Arguments args = new Arguments (2);
2286 args.Add (new Argument (b.left));
2287 args.Add (new Argument (b.right));
2290 if (b.oper == Operator.Equality) {
2291 if (equal_method == null) {
2292 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2293 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2294 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2295 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2297 throw new NotImplementedException (left.GetSignatureForError ());
2300 method = equal_method;
2302 if (inequal_method == null) {
2303 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2304 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2305 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2306 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2308 throw new NotImplementedException (left.GetSignatureForError ());
2311 method = inequal_method;
2314 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2318 class PredefinedPointerOperator : PredefinedOperator
2320 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2321 : base (ltype, rtype, op_mask)
2325 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2326 : base (ltype, rtype, op_mask, retType)
2330 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2331 : base (type, op_mask, return_type)
2335 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2338 if (!lexpr.Type.IsPointer)
2341 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2345 if (right == null) {
2346 if (!rexpr.Type.IsPointer)
2349 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2356 public override Expression ConvertResult (ResolveContext ec, Binary b)
2359 b.left = EmptyCast.Create (b.left, left);
2360 } else if (right != null) {
2361 b.right = EmptyCast.Create (b.right, right);
2364 TypeSpec r_type = ReturnType;
2365 Expression left_arg, right_arg;
2366 if (r_type == null) {
2369 right_arg = b.right;
2370 r_type = b.left.Type;
2374 r_type = b.right.Type;
2378 right_arg = b.right;
2381 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2386 public enum Operator {
2387 Multiply = 0 | ArithmeticMask,
2388 Division = 1 | ArithmeticMask,
2389 Modulus = 2 | ArithmeticMask,
2390 Addition = 3 | ArithmeticMask | AdditionMask,
2391 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2393 LeftShift = 5 | ShiftMask,
2394 RightShift = 6 | ShiftMask,
2396 LessThan = 7 | ComparisonMask | RelationalMask,
2397 GreaterThan = 8 | ComparisonMask | RelationalMask,
2398 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2399 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2400 Equality = 11 | ComparisonMask | EqualityMask,
2401 Inequality = 12 | ComparisonMask | EqualityMask,
2403 BitwiseAnd = 13 | BitwiseMask,
2404 ExclusiveOr = 14 | BitwiseMask,
2405 BitwiseOr = 15 | BitwiseMask,
2407 LogicalAnd = 16 | LogicalMask,
2408 LogicalOr = 17 | LogicalMask,
2413 ValuesOnlyMask = ArithmeticMask - 1,
2414 ArithmeticMask = 1 << 5,
2416 ComparisonMask = 1 << 7,
2417 EqualityMask = 1 << 8,
2418 BitwiseMask = 1 << 9,
2419 LogicalMask = 1 << 10,
2420 AdditionMask = 1 << 11,
2421 SubtractionMask = 1 << 12,
2422 RelationalMask = 1 << 13,
2424 DecomposedMask = 1 << 19,
2425 NullableMask = 1 << 20,
2435 readonly Operator oper;
2436 Expression left, right;
2438 ConvCast.Mode enum_conversion;
2440 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
2441 : this (oper, left, right)
2444 state |= State.Compound;
2447 public Binary (Operator oper, Expression left, Expression right)
2452 this.loc = left.Location;
2457 public bool IsCompound {
2459 return (state & State.Compound) != 0;
2463 public Operator Oper {
2469 public Expression Left {
2475 public Expression Right {
2481 public override Location StartLocation {
2483 return left.StartLocation;
2490 /// Returns a stringified representation of the Operator
2492 string OperName (Operator oper)
2496 case Operator.Multiply:
2499 case Operator.Division:
2502 case Operator.Modulus:
2505 case Operator.Addition:
2508 case Operator.Subtraction:
2511 case Operator.LeftShift:
2514 case Operator.RightShift:
2517 case Operator.LessThan:
2520 case Operator.GreaterThan:
2523 case Operator.LessThanOrEqual:
2526 case Operator.GreaterThanOrEqual:
2529 case Operator.Equality:
2532 case Operator.Inequality:
2535 case Operator.BitwiseAnd:
2538 case Operator.BitwiseOr:
2541 case Operator.ExclusiveOr:
2544 case Operator.LogicalOr:
2547 case Operator.LogicalAnd:
2551 s = oper.ToString ();
2561 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2563 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2566 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2568 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
2572 l = left.Type.GetSignatureForError ();
2573 r = right.Type.GetSignatureForError ();
2575 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2579 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2581 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2584 public override void FlowAnalysis (FlowAnalysisContext fc)
2586 if ((oper & Operator.LogicalMask) == 0) {
2587 left.FlowAnalysis (fc);
2588 right.FlowAnalysis (fc);
2593 // Optimized version when on-true/on-false data are not needed
2595 bool set_on_true_false;
2596 if (fc.DefiniteAssignmentOnTrue == null && fc.DefiniteAssignmentOnFalse == null) {
2597 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignment;
2598 set_on_true_false = false;
2600 set_on_true_false = true;
2603 left.FlowAnalysis (fc);
2604 var left_fc = fc.DefiniteAssignment;
2605 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
2606 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
2608 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
2609 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
2610 right.FlowAnalysis (fc);
2611 fc.DefiniteAssignment = left_fc;
2613 if (!set_on_true_false) {
2614 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue = null;
2618 if (oper == Operator.LogicalOr) {
2619 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue);
2620 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
2622 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
2623 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet (left_fc_onfalse);
2628 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2630 string GetOperatorExpressionTypeName ()
2633 case Operator.Addition:
2634 return IsCompound ? "AddAssign" : "Add";
2635 case Operator.BitwiseAnd:
2636 return IsCompound ? "AndAssign" : "And";
2637 case Operator.BitwiseOr:
2638 return IsCompound ? "OrAssign" : "Or";
2639 case Operator.Division:
2640 return IsCompound ? "DivideAssign" : "Divide";
2641 case Operator.ExclusiveOr:
2642 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2643 case Operator.Equality:
2645 case Operator.GreaterThan:
2646 return "GreaterThan";
2647 case Operator.GreaterThanOrEqual:
2648 return "GreaterThanOrEqual";
2649 case Operator.Inequality:
2651 case Operator.LeftShift:
2652 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2653 case Operator.LessThan:
2655 case Operator.LessThanOrEqual:
2656 return "LessThanOrEqual";
2657 case Operator.LogicalAnd:
2659 case Operator.LogicalOr:
2661 case Operator.Modulus:
2662 return IsCompound ? "ModuloAssign" : "Modulo";
2663 case Operator.Multiply:
2664 return IsCompound ? "MultiplyAssign" : "Multiply";
2665 case Operator.RightShift:
2666 return IsCompound ? "RightShiftAssign" : "RightShift";
2667 case Operator.Subtraction:
2668 return IsCompound ? "SubtractAssign" : "Subtract";
2670 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2674 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2677 case Operator.Addition:
2678 return CSharp.Operator.OpType.Addition;
2679 case Operator.BitwiseAnd:
2680 case Operator.LogicalAnd:
2681 return CSharp.Operator.OpType.BitwiseAnd;
2682 case Operator.BitwiseOr:
2683 case Operator.LogicalOr:
2684 return CSharp.Operator.OpType.BitwiseOr;
2685 case Operator.Division:
2686 return CSharp.Operator.OpType.Division;
2687 case Operator.Equality:
2688 return CSharp.Operator.OpType.Equality;
2689 case Operator.ExclusiveOr:
2690 return CSharp.Operator.OpType.ExclusiveOr;
2691 case Operator.GreaterThan:
2692 return CSharp.Operator.OpType.GreaterThan;
2693 case Operator.GreaterThanOrEqual:
2694 return CSharp.Operator.OpType.GreaterThanOrEqual;
2695 case Operator.Inequality:
2696 return CSharp.Operator.OpType.Inequality;
2697 case Operator.LeftShift:
2698 return CSharp.Operator.OpType.LeftShift;
2699 case Operator.LessThan:
2700 return CSharp.Operator.OpType.LessThan;
2701 case Operator.LessThanOrEqual:
2702 return CSharp.Operator.OpType.LessThanOrEqual;
2703 case Operator.Modulus:
2704 return CSharp.Operator.OpType.Modulus;
2705 case Operator.Multiply:
2706 return CSharp.Operator.OpType.Multiply;
2707 case Operator.RightShift:
2708 return CSharp.Operator.OpType.RightShift;
2709 case Operator.Subtraction:
2710 return CSharp.Operator.OpType.Subtraction;
2712 throw new InternalErrorException (op.ToString ());
2716 public override bool ContainsEmitWithAwait ()
2718 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2721 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
2726 case Operator.Multiply:
2727 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2728 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2729 opcode = OpCodes.Mul_Ovf;
2730 else if (!IsFloat (l))
2731 opcode = OpCodes.Mul_Ovf_Un;
2733 opcode = OpCodes.Mul;
2735 opcode = OpCodes.Mul;
2739 case Operator.Division:
2741 opcode = OpCodes.Div_Un;
2743 opcode = OpCodes.Div;
2746 case Operator.Modulus:
2748 opcode = OpCodes.Rem_Un;
2750 opcode = OpCodes.Rem;
2753 case Operator.Addition:
2754 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2755 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2756 opcode = OpCodes.Add_Ovf;
2757 else if (!IsFloat (l))
2758 opcode = OpCodes.Add_Ovf_Un;
2760 opcode = OpCodes.Add;
2762 opcode = OpCodes.Add;
2765 case Operator.Subtraction:
2766 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2767 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2768 opcode = OpCodes.Sub_Ovf;
2769 else if (!IsFloat (l))
2770 opcode = OpCodes.Sub_Ovf_Un;
2772 opcode = OpCodes.Sub;
2774 opcode = OpCodes.Sub;
2777 case Operator.RightShift:
2778 if (!(right is IntConstant)) {
2779 ec.EmitInt (GetShiftMask (l));
2780 ec.Emit (OpCodes.And);
2784 opcode = OpCodes.Shr_Un;
2786 opcode = OpCodes.Shr;
2789 case Operator.LeftShift:
2790 if (!(right is IntConstant)) {
2791 ec.EmitInt (GetShiftMask (l));
2792 ec.Emit (OpCodes.And);
2795 opcode = OpCodes.Shl;
2798 case Operator.Equality:
2799 opcode = OpCodes.Ceq;
2802 case Operator.Inequality:
2803 ec.Emit (OpCodes.Ceq);
2806 opcode = OpCodes.Ceq;
2809 case Operator.LessThan:
2811 opcode = OpCodes.Clt_Un;
2813 opcode = OpCodes.Clt;
2816 case Operator.GreaterThan:
2818 opcode = OpCodes.Cgt_Un;
2820 opcode = OpCodes.Cgt;
2823 case Operator.LessThanOrEqual:
2824 if (IsUnsigned (l) || IsFloat (l))
2825 ec.Emit (OpCodes.Cgt_Un);
2827 ec.Emit (OpCodes.Cgt);
2830 opcode = OpCodes.Ceq;
2833 case Operator.GreaterThanOrEqual:
2834 if (IsUnsigned (l) || IsFloat (l))
2835 ec.Emit (OpCodes.Clt_Un);
2837 ec.Emit (OpCodes.Clt);
2841 opcode = OpCodes.Ceq;
2844 case Operator.BitwiseOr:
2845 opcode = OpCodes.Or;
2848 case Operator.BitwiseAnd:
2849 opcode = OpCodes.And;
2852 case Operator.ExclusiveOr:
2853 opcode = OpCodes.Xor;
2857 throw new InternalErrorException (oper.ToString ());
2863 static int GetShiftMask (TypeSpec type)
2865 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
2868 static bool IsUnsigned (TypeSpec t)
2870 switch (t.BuiltinType) {
2871 case BuiltinTypeSpec.Type.Char:
2872 case BuiltinTypeSpec.Type.UInt:
2873 case BuiltinTypeSpec.Type.ULong:
2874 case BuiltinTypeSpec.Type.UShort:
2875 case BuiltinTypeSpec.Type.Byte:
2882 static bool IsFloat (TypeSpec t)
2884 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2887 public Expression ResolveOperator (ResolveContext rc)
2889 eclass = ExprClass.Value;
2891 TypeSpec l = left.Type;
2892 TypeSpec r = right.Type;
2894 bool primitives_only = false;
2897 // Handles predefined primitive types
2899 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
2900 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
2901 if ((oper & Operator.ShiftMask) == 0) {
2902 if (!DoBinaryOperatorPromotion (rc))
2905 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
2909 if (l.IsPointer || r.IsPointer)
2910 return ResolveOperatorPointer (rc, l, r);
2913 expr = ResolveUserOperator (rc, left, right);
2918 bool lenum = l.IsEnum;
2919 bool renum = r.IsEnum;
2920 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2924 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2925 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
2930 if ((oper & Operator.BitwiseMask) != 0) {
2931 expr = EmptyCast.Create (expr, type);
2932 AddEnumResultCast (type);
2934 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
2935 expr = OptimizeAndOperation (expr);
2939 left = ConvertEnumOperandToUnderlyingType (rc, left);
2940 right = ConvertEnumOperandToUnderlyingType (rc, right);
2943 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
2944 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2948 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
2951 // We cannot break here there is also Enum + String possible match
2952 // which is not ambiguous with predefined enum operators
2955 left = ConvertEnumOperandToUnderlyingType (rc, left);
2956 right = ConvertEnumOperandToUnderlyingType (rc, right);
2960 } else if (l.IsDelegate || r.IsDelegate) {
2964 expr = ResolveOperatorDelegate (rc, l, r);
2966 // TODO: Can this be ambiguous
2974 // Equality operators are more complicated
2976 if ((oper & Operator.EqualityMask) != 0) {
2977 return ResolveEquality (rc, l, r, primitives_only);
2980 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
2984 if (primitives_only)
2988 // Lifted operators have lower priority
2990 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
2993 static bool IsEnumOrNullableEnum (TypeSpec type)
2995 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
2999 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3000 // if 'left' is not an enumeration constant, create one from the type of 'right'
3001 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3004 case Operator.BitwiseOr:
3005 case Operator.BitwiseAnd:
3006 case Operator.ExclusiveOr:
3007 case Operator.Equality:
3008 case Operator.Inequality:
3009 case Operator.LessThan:
3010 case Operator.LessThanOrEqual:
3011 case Operator.GreaterThan:
3012 case Operator.GreaterThanOrEqual:
3013 if (left.Type.IsEnum)
3016 if (left.IsZeroInteger)
3017 return left.Reduce (ec, right.Type);
3021 case Operator.Addition:
3022 case Operator.Subtraction:
3025 case Operator.Multiply:
3026 case Operator.Division:
3027 case Operator.Modulus:
3028 case Operator.LeftShift:
3029 case Operator.RightShift:
3030 if (right.Type.IsEnum || left.Type.IsEnum)
3039 // The `|' operator used on types which were extended is dangerous
3041 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3043 OpcodeCast lcast = left as OpcodeCast;
3044 if (lcast != null) {
3045 if (IsUnsigned (lcast.UnderlyingType))
3049 OpcodeCast rcast = right as OpcodeCast;
3050 if (rcast != null) {
3051 if (IsUnsigned (rcast.UnderlyingType))
3055 if (lcast == null && rcast == null)
3058 // FIXME: consider constants
3060 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3061 ec.Report.Warning (675, 3, loc,
3062 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3063 ltype.GetSignatureForError ());
3066 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3068 return new PredefinedOperator[] {
3070 // Pointer arithmetic:
3072 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3073 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3074 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3075 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3077 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3078 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3079 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3080 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3083 // T* operator + (int y, T* x);
3084 // T* operator + (uint y, T *x);
3085 // T* operator + (long y, T *x);
3086 // T* operator + (ulong y, T *x);
3088 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3089 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3090 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3091 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3094 // long operator - (T* x, T *y)
3096 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3100 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3102 TypeSpec bool_type = types.Bool;
3105 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3106 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3107 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3108 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3109 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3110 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3111 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3113 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3114 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3115 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3116 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3117 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3118 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3119 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3121 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3122 // Remaining string operators are in lifted tables
3124 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3126 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3127 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3128 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3132 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3134 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3135 if (nullable == null)
3136 return new PredefinedOperator [0];
3138 var types = module.Compiler.BuiltinTypes;
3139 var bool_type = types.Bool;
3141 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3142 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3143 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3144 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3145 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3146 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3147 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3148 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3151 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3152 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3153 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3154 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3155 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3156 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3157 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3159 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3160 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3161 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3162 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3163 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3164 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3165 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3167 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3169 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3170 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3171 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3174 // Not strictly lifted but need to be in second group otherwise expressions like
3175 // int + null would resolve to +(object, string) instead of +(int?, int?)
3177 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3178 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3183 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3185 TypeSpec bool_type = types.Bool;
3188 new PredefinedEqualityOperator (types.String, bool_type),
3189 new PredefinedEqualityOperator (types.Delegate, bool_type),
3190 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3191 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3192 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3193 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3194 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3195 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3196 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3197 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3201 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3203 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3205 if (nullable == null)
3206 return new PredefinedOperator [0];
3208 var types = module.Compiler.BuiltinTypes;
3209 var bool_type = types.Bool;
3210 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3211 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3212 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3213 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3214 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3215 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3216 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3217 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3220 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3221 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3222 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3223 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3224 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3225 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3226 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3227 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3232 // 7.2.6.2 Binary numeric promotions
3234 bool DoBinaryOperatorPromotion (ResolveContext rc)
3236 TypeSpec ltype = left.Type;
3237 if (ltype.IsNullableType) {
3238 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
3242 // This is numeric promotion code only
3244 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
3247 TypeSpec rtype = right.Type;
3248 if (rtype.IsNullableType) {
3249 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
3252 var lb = ltype.BuiltinType;
3253 var rb = rtype.BuiltinType;
3257 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
3258 type = rc.BuiltinTypes.Decimal;
3259 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
3260 type = rc.BuiltinTypes.Double;
3261 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
3262 type = rc.BuiltinTypes.Float;
3263 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
3264 type = rc.BuiltinTypes.ULong;
3266 if (IsSignedType (lb)) {
3267 expr = ConvertSignedConstant (left, type);
3271 } else if (IsSignedType (rb)) {
3272 expr = ConvertSignedConstant (right, type);
3278 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
3279 type = rc.BuiltinTypes.Long;
3280 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
3281 type = rc.BuiltinTypes.UInt;
3283 if (IsSignedType (lb)) {
3284 expr = ConvertSignedConstant (left, type);
3286 type = rc.BuiltinTypes.Long;
3287 } else if (IsSignedType (rb)) {
3288 expr = ConvertSignedConstant (right, type);
3290 type = rc.BuiltinTypes.Long;
3293 type = rc.BuiltinTypes.Int;
3296 if (ltype != type) {
3297 expr = PromoteExpression (rc, left, type);
3304 if (rtype != type) {
3305 expr = PromoteExpression (rc, right, type);
3315 static bool IsSignedType (BuiltinTypeSpec.Type type)
3318 case BuiltinTypeSpec.Type.Int:
3319 case BuiltinTypeSpec.Type.Short:
3320 case BuiltinTypeSpec.Type.SByte:
3321 case BuiltinTypeSpec.Type.Long:
3328 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
3330 var c = expr as Constant;
3334 return c.ConvertImplicitly (type);
3337 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
3339 if (expr.Type.IsNullableType) {
3340 return Convert.ImplicitConversionStandard (rc, expr,
3341 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
3344 var c = expr as Constant;
3346 return c.ConvertImplicitly (type);
3348 return Convert.ImplicitNumericConversion (expr, type);
3351 protected override Expression DoResolve (ResolveContext ec)
3356 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
3357 left = ((ParenthesizedExpression) left).Expr;
3358 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
3362 if (left.eclass == ExprClass.Type) {
3363 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
3367 left = left.Resolve (ec);
3372 right = right.Resolve (ec);
3376 Constant lc = left as Constant;
3377 Constant rc = right as Constant;
3379 // The conversion rules are ignored in enum context but why
3380 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
3381 lc = EnumLiftUp (ec, lc, rc);
3383 rc = EnumLiftUp (ec, rc, lc);
3386 if (rc != null && lc != null) {
3387 int prev_e = ec.Report.Errors;
3388 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
3389 if (e != null || ec.Report.Errors != prev_e)
3393 // Comparison warnings
3394 if ((oper & Operator.ComparisonMask) != 0) {
3395 if (left.Equals (right)) {
3396 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
3398 CheckOutOfRangeComparison (ec, lc, right.Type);
3399 CheckOutOfRangeComparison (ec, rc, left.Type);
3402 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3403 return DoResolveDynamic (ec);
3405 return DoResolveCore (ec, left, right);
3408 Expression DoResolveDynamic (ResolveContext rc)
3411 var rt = right.Type;
3412 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
3413 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
3414 Error_OperatorCannotBeApplied (rc, left, right);
3421 // Special handling for logical boolean operators which require rhs not to be
3422 // evaluated based on lhs value
3424 if ((oper & Operator.LogicalMask) != 0) {
3425 Expression cond_left, cond_right, expr;
3427 args = new Arguments (2);
3429 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3430 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
3432 var cond_args = new Arguments (1);
3433 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
3436 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
3437 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
3439 left = temp.CreateReferenceExpression (rc, loc);
3440 if (oper == Operator.LogicalAnd) {
3441 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
3444 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
3448 args.Add (new Argument (left));
3449 args.Add (new Argument (right));
3450 cond_right = new DynamicExpressionStatement (this, args, loc);
3452 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
3454 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
3455 args.Add (new Argument (right));
3456 right = new DynamicExpressionStatement (this, args, loc);
3459 // bool && dynamic => (temp = left) ? temp && right : temp;
3460 // bool || dynamic => (temp = left) ? temp : temp || right;
3462 if (oper == Operator.LogicalAnd) {
3464 cond_right = temp.CreateReferenceExpression (rc, loc);
3466 cond_left = temp.CreateReferenceExpression (rc, loc);
3470 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
3473 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
3476 args = new Arguments (2);
3477 args.Add (new Argument (left));
3478 args.Add (new Argument (right));
3479 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
3482 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3484 Expression expr = ResolveOperator (ec);
3486 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3488 if (left == null || right == null)
3489 throw new InternalErrorException ("Invalid conversion");
3491 if (oper == Operator.BitwiseOr)
3492 CheckBitwiseOrOnSignExtended (ec);
3497 public override SLE.Expression MakeExpression (BuilderContext ctx)
3499 return MakeExpression (ctx, left, right);
3502 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
3504 var le = left.MakeExpression (ctx);
3505 var re = right.MakeExpression (ctx);
3506 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3509 case Operator.Addition:
3510 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3511 case Operator.BitwiseAnd:
3512 return SLE.Expression.And (le, re);
3513 case Operator.BitwiseOr:
3514 return SLE.Expression.Or (le, re);
3515 case Operator.Division:
3516 return SLE.Expression.Divide (le, re);
3517 case Operator.Equality:
3518 return SLE.Expression.Equal (le, re);
3519 case Operator.ExclusiveOr:
3520 return SLE.Expression.ExclusiveOr (le, re);
3521 case Operator.GreaterThan:
3522 return SLE.Expression.GreaterThan (le, re);
3523 case Operator.GreaterThanOrEqual:
3524 return SLE.Expression.GreaterThanOrEqual (le, re);
3525 case Operator.Inequality:
3526 return SLE.Expression.NotEqual (le, re);
3527 case Operator.LeftShift:
3528 return SLE.Expression.LeftShift (le, re);
3529 case Operator.LessThan:
3530 return SLE.Expression.LessThan (le, re);
3531 case Operator.LessThanOrEqual:
3532 return SLE.Expression.LessThanOrEqual (le, re);
3533 case Operator.LogicalAnd:
3534 return SLE.Expression.AndAlso (le, re);
3535 case Operator.LogicalOr:
3536 return SLE.Expression.OrElse (le, re);
3537 case Operator.Modulus:
3538 return SLE.Expression.Modulo (le, re);
3539 case Operator.Multiply:
3540 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3541 case Operator.RightShift:
3542 return SLE.Expression.RightShift (le, re);
3543 case Operator.Subtraction:
3544 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3546 throw new NotImplementedException (oper.ToString ());
3551 // D operator + (D x, D y)
3552 // D operator - (D x, D y)
3554 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3556 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3558 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3559 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3564 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3565 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3575 MethodSpec method = null;
3576 Arguments args = new Arguments (2);
3577 args.Add (new Argument (left));
3578 args.Add (new Argument (right));
3580 if (oper == Operator.Addition) {
3581 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3582 } else if (oper == Operator.Subtraction) {
3583 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3587 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3589 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
3590 return new ClassCast (expr, l);
3594 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
3596 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3599 // bool operator == (E x, E y);
3600 // bool operator != (E x, E y);
3601 // bool operator < (E x, E y);
3602 // bool operator > (E x, E y);
3603 // bool operator <= (E x, E y);
3604 // bool operator >= (E x, E y);
3606 // E operator & (E x, E y);
3607 // E operator | (E x, E y);
3608 // E operator ^ (E x, E y);
3611 if ((oper & Operator.ComparisonMask) != 0) {
3612 type = rc.BuiltinTypes.Bool;
3618 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3624 if (ltype == rtype) {
3628 var lifted = new Nullable.LiftedBinaryOperator (this);
3630 lifted.Right = right;
3631 return lifted.Resolve (rc);
3634 if (renum && !ltype.IsNullableType) {
3635 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
3640 } else if (lenum && !rtype.IsNullableType) {
3641 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
3649 // Now try lifted version of predefined operator
3651 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
3652 if (nullable_type != null) {
3653 if (renum && !ltype.IsNullableType) {
3654 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
3656 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3659 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3662 if ((oper & Operator.BitwiseMask) != 0)
3666 if ((oper & Operator.BitwiseMask) != 0)
3667 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3669 return CreateLiftedValueTypeResult (rc, rtype);
3673 var lifted = new Nullable.LiftedBinaryOperator (this);
3675 lifted.Right = right;
3676 return lifted.Resolve (rc);
3678 } else if (lenum && !rtype.IsNullableType) {
3679 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
3681 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3684 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3687 if ((oper & Operator.BitwiseMask) != 0)
3691 if ((oper & Operator.BitwiseMask) != 0)
3692 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3694 return CreateLiftedValueTypeResult (rc, ltype);
3698 var lifted = new Nullable.LiftedBinaryOperator (this);
3700 lifted.Right = expr;
3701 return lifted.Resolve (rc);
3703 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
3705 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3706 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
3708 if ((oper & Operator.RelationalMask) != 0)
3709 return CreateLiftedValueTypeResult (rc, rtype);
3711 if ((oper & Operator.BitwiseMask) != 0)
3712 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3714 // Equality operators are valid between E? and null
3717 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
3723 var lifted = new Nullable.LiftedBinaryOperator (this);
3725 lifted.Right = right;
3726 return lifted.Resolve (rc);
3728 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
3730 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3731 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
3733 if ((oper & Operator.RelationalMask) != 0)
3734 return CreateLiftedValueTypeResult (rc, ltype);
3736 if ((oper & Operator.BitwiseMask) != 0)
3737 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3739 // Equality operators are valid between E? and null
3742 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
3748 var lifted = new Nullable.LiftedBinaryOperator (this);
3750 lifted.Right = expr;
3751 return lifted.Resolve (rc);
3759 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr)
3761 TypeSpec underlying_type;
3762 if (expr.Type.IsNullableType) {
3763 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
3765 underlying_type = EnumSpec.GetUnderlyingType (nt);
3767 underlying_type = nt;
3768 } else if (expr.Type.IsEnum) {
3769 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
3771 underlying_type = expr.Type;
3774 switch (underlying_type.BuiltinType) {
3775 case BuiltinTypeSpec.Type.SByte:
3776 case BuiltinTypeSpec.Type.Byte:
3777 case BuiltinTypeSpec.Type.Short:
3778 case BuiltinTypeSpec.Type.UShort:
3779 underlying_type = rc.BuiltinTypes.Int;
3783 if (expr.Type.IsNullableType)
3784 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
3786 if (expr.Type == underlying_type)
3789 return EmptyCast.Create (expr, underlying_type);
3792 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3795 // U operator - (E e, E f)
3796 // E operator - (E e, U x) // Internal decomposition operator
3797 // E operator - (U x, E e) // Internal decomposition operator
3799 // E operator + (E e, U x)
3800 // E operator + (U x, E e)
3809 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3815 if (!enum_type.IsNullableType) {
3816 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
3818 if (oper == Operator.Subtraction)
3819 expr = ConvertEnumSubtractionResult (rc, expr);
3821 expr = ConvertEnumAdditionalResult (expr, enum_type);
3823 AddEnumResultCast (expr.Type);
3828 enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
3831 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
3833 if (oper == Operator.Subtraction)
3834 expr = ConvertEnumSubtractionResult (rc, expr);
3836 expr = ConvertEnumAdditionalResult (expr, enum_type);
3838 AddEnumResultCast (expr.Type);
3844 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
3846 return EmptyCast.Create (expr, enumType);
3849 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
3852 // Enumeration subtraction has different result type based on
3855 TypeSpec result_type;
3856 if (left.Type == right.Type) {
3857 var c = right as EnumConstant;
3858 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
3860 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
3861 // E which is not what expressions E - 1 or 0 - E return
3863 result_type = left.Type;
3865 result_type = left.Type.IsNullableType ?
3866 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
3867 EnumSpec.GetUnderlyingType (left.Type);
3870 if (IsEnumOrNullableEnum (left.Type)) {
3871 result_type = left.Type;
3873 result_type = right.Type;
3876 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
3877 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
3880 return EmptyCast.Create (expr, result_type);
3883 void AddEnumResultCast (TypeSpec type)
3885 if (type.IsNullableType)
3886 type = Nullable.NullableInfo.GetUnderlyingType (type);
3889 type = EnumSpec.GetUnderlyingType (type);
3891 switch (type.BuiltinType) {
3892 case BuiltinTypeSpec.Type.SByte:
3893 enum_conversion = ConvCast.Mode.I4_I1;
3895 case BuiltinTypeSpec.Type.Byte:
3896 enum_conversion = ConvCast.Mode.I4_U1;
3898 case BuiltinTypeSpec.Type.Short:
3899 enum_conversion = ConvCast.Mode.I4_I2;
3901 case BuiltinTypeSpec.Type.UShort:
3902 enum_conversion = ConvCast.Mode.I4_U2;
3908 // Equality operators rules
3910 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
3913 type = ec.BuiltinTypes.Bool;
3914 bool no_arg_conv = false;
3916 if (!primitives_only) {
3919 // a, Both operands are reference-type values or the value null
3920 // b, One operand is a value of type T where T is a type-parameter and
3921 // the other operand is the value null. Furthermore T does not have the
3922 // value type constraint
3924 // LAMESPEC: Very confusing details in the specification, basically any
3925 // reference like type-parameter is allowed
3927 var tparam_l = l as TypeParameterSpec;
3928 var tparam_r = r as TypeParameterSpec;
3929 if (tparam_l != null) {
3930 if (right is NullLiteral) {
3931 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3934 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3938 if (!tparam_l.IsReferenceType)
3941 l = tparam_l.GetEffectiveBase ();
3942 left = new BoxedCast (left, l);
3943 } else if (left is NullLiteral && tparam_r == null) {
3944 if (TypeSpec.IsReferenceType (r))
3947 if (r.Kind == MemberKind.InternalCompilerType)
3951 if (tparam_r != null) {
3952 if (left is NullLiteral) {
3953 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3956 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3960 if (!tparam_r.IsReferenceType)
3963 r = tparam_r.GetEffectiveBase ();
3964 right = new BoxedCast (right, r);
3965 } else if (right is NullLiteral) {
3966 if (TypeSpec.IsReferenceType (l))
3969 if (l.Kind == MemberKind.InternalCompilerType)
3974 // LAMESPEC: method groups can be compared when they convert to other side delegate
3977 if (right.eclass == ExprClass.MethodGroup) {
3978 result = Convert.ImplicitConversion (ec, right, l, loc);
3984 } else if (r.IsDelegate && l != r) {
3987 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3988 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3995 no_arg_conv = l == r && !l.IsStruct;
4000 // bool operator != (string a, string b)
4001 // bool operator == (string a, string b)
4003 // bool operator != (Delegate a, Delegate b)
4004 // bool operator == (Delegate a, Delegate b)
4006 // bool operator != (bool a, bool b)
4007 // bool operator == (bool a, bool b)
4009 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4010 // they implement an implicit conversion to any of types above. This does
4011 // not apply when both operands are of same reference type
4013 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4014 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4019 // Now try lifted version of predefined operators
4021 if (no_arg_conv && !l.IsNullableType) {
4023 // Optimizes cases which won't match
4026 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4032 // The == and != operators permit one operand to be a value of a nullable
4033 // type and the other to be the null literal, even if no predefined or user-defined
4034 // operator (in unlifted or lifted form) exists for the operation.
4036 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4037 var lifted = new Nullable.LiftedBinaryOperator (this);
4039 lifted.Right = right;
4040 return lifted.Resolve (ec);
4045 // bool operator != (object a, object b)
4046 // bool operator == (object a, object b)
4048 // An explicit reference conversion exists from the
4049 // type of either operand to the type of the other operand.
4052 // Optimize common path
4054 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4057 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4058 !Convert.ExplicitReferenceConversionExists (r, l))
4061 // Reject allowed explicit conversions like int->object
4062 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4065 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4066 ec.Report.Warning (253, 2, loc,
4067 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4068 l.GetSignatureForError ());
4070 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4071 ec.Report.Warning (252, 2, loc,
4072 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4073 r.GetSignatureForError ());
4079 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4082 // bool operator == (void* x, void* y);
4083 // bool operator != (void* x, void* y);
4084 // bool operator < (void* x, void* y);
4085 // bool operator > (void* x, void* y);
4086 // bool operator <= (void* x, void* y);
4087 // bool operator >= (void* x, void* y);
4089 if ((oper & Operator.ComparisonMask) != 0) {
4092 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4099 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4105 type = ec.BuiltinTypes.Bool;
4109 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4113 // Build-in operators method overloading
4115 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4117 PredefinedOperator best_operator = null;
4118 TypeSpec l = left.Type;
4119 TypeSpec r = right.Type;
4120 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4122 foreach (PredefinedOperator po in operators) {
4123 if ((po.OperatorsMask & oper_mask) == 0)
4126 if (primitives_only) {
4127 if (!po.IsPrimitiveApplicable (l, r))
4130 if (!po.IsApplicable (ec, left, right))
4134 if (best_operator == null) {
4136 if (primitives_only)
4142 best_operator = po.ResolveBetterOperator (ec, best_operator);
4144 if (best_operator == null) {
4145 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4146 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4153 if (best_operator == null)
4156 return best_operator.ConvertResult (ec, this);
4160 // Optimize & constant expressions with 0 value
4162 Expression OptimizeAndOperation (Expression expr)
4164 Constant rc = right as Constant;
4165 Constant lc = left as Constant;
4166 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4168 // The result is a constant with side-effect
4170 Constant side_effect = rc == null ?
4171 new SideEffectConstant (lc, right, loc) :
4172 new SideEffectConstant (rc, left, loc);
4174 return ReducedExpression.Create (side_effect, expr);
4181 // Value types can be compared with the null literal because of the lifting
4182 // language rules. However the result is always true or false.
4184 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4186 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4187 type = rc.BuiltinTypes.Bool;
4191 // FIXME: Handle side effect constants
4192 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4194 if ((Oper & Operator.EqualityMask) != 0) {
4195 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4196 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4198 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4199 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4206 // Performs user-operator overloading
4208 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4210 Expression oper_expr;
4212 var op = ConvertBinaryToUserOperator (oper);
4214 if (l.IsNullableType)
4215 l = Nullable.NullableInfo.GetUnderlyingType (l);
4217 if (r.IsNullableType)
4218 r = Nullable.NullableInfo.GetUnderlyingType (r);
4220 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
4221 IList<MemberSpec> right_operators = null;
4224 right_operators = MemberCache.GetUserOperator (r, op, false);
4225 if (right_operators == null && left_operators == null)
4227 } else if (left_operators == null) {
4231 Arguments args = new Arguments (2);
4232 Argument larg = new Argument (left);
4234 Argument rarg = new Argument (right);
4238 // User-defined operator implementations always take precedence
4239 // over predefined operator implementations
4241 if (left_operators != null && right_operators != null) {
4242 left_operators = CombineUserOperators (left_operators, right_operators);
4243 } else if (right_operators != null) {
4244 left_operators = right_operators;
4247 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
4248 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
4250 var res = new OverloadResolver (left_operators, restr, loc);
4252 var oper_method = res.ResolveOperator (rc, ref args);
4253 if (oper_method == null) {
4255 // Logical && and || cannot be lifted
4257 if ((oper & Operator.LogicalMask) != 0)
4261 // Apply lifted user operators only for liftable types. Implicit conversion
4262 // to nullable types is not allowed
4264 if (!IsLiftedOperatorApplicable ())
4267 // TODO: Cache the result in module container
4268 var lifted_methods = CreateLiftedOperators (rc, left_operators);
4269 if (lifted_methods == null)
4272 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
4274 oper_method = res.ResolveOperator (rc, ref args);
4275 if (oper_method == null)
4278 MethodSpec best_original = null;
4279 foreach (MethodSpec ms in left_operators) {
4280 if (ms.MemberDefinition == oper_method.MemberDefinition) {
4286 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4288 // Expression trees use lifted notation in this case
4290 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
4291 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
4294 var ptypes = best_original.Parameters.Types;
4296 if (left.IsNull || right.IsNull) {
4298 // The lifted operator produces the value false if one or both operands are null for
4299 // relational operators.
4301 if ((oper & Operator.ComparisonMask) != 0) {
4303 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
4304 // because return type is actually bool
4306 // For some reason CSC does not report this warning for equality operators
4308 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
4311 // The lifted operator produces a null value if one or both operands are null
4313 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
4314 type = oper_method.ReturnType;
4315 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4319 type = oper_method.ReturnType;
4320 var lifted = new Nullable.LiftedBinaryOperator (this);
4321 lifted.UserOperator = best_original;
4323 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
4324 lifted.UnwrapLeft = new Nullable.Unwrap (left);
4327 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
4328 lifted.UnwrapRight = new Nullable.Unwrap (right);
4331 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
4332 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
4334 return lifted.Resolve (rc);
4337 if ((oper & Operator.LogicalMask) != 0) {
4338 // TODO: CreateExpressionTree is allocated every time
4339 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
4340 oper == Operator.LogicalAnd, loc).Resolve (rc);
4342 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
4345 this.left = larg.Expr;
4346 this.right = rarg.Expr;
4351 bool IsLiftedOperatorApplicable ()
4353 if (left.Type.IsNullableType) {
4354 if ((oper & Operator.EqualityMask) != 0)
4355 return !right.IsNull;
4360 if (right.Type.IsNullableType) {
4361 if ((oper & Operator.EqualityMask) != 0)
4362 return !left.IsNull;
4367 if (TypeSpec.IsValueType (left.Type))
4368 return right.IsNull;
4370 if (TypeSpec.IsValueType (right.Type))
4376 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
4378 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4379 if (nullable_type == null)
4383 // Lifted operators permit predefined and user-defined operators that operate
4384 // on non-nullable value types to also be used with nullable forms of those types.
4385 // Lifted operators are constructed from predefined and user-defined operators
4386 // that meet certain requirements
4388 List<MemberSpec> lifted = null;
4389 foreach (MethodSpec oper in operators) {
4391 if ((Oper & Operator.ComparisonMask) != 0) {
4393 // Result type must be of type bool for lifted comparison operators
4395 rt = oper.ReturnType;
4396 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
4399 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
4405 var ptypes = oper.Parameters.Types;
4406 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
4410 // LAMESPEC: I am not sure why but for equality operators to be lifted
4411 // both types have to match
4413 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
4417 lifted = new List<MemberSpec> ();
4420 // The lifted form is constructed by adding a single ? modifier to each operand and
4421 // result type except for comparison operators where return type is bool
4424 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
4426 var parameters = ParametersCompiled.CreateFullyResolved (
4427 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
4428 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
4430 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
4431 rt, parameters, oper.Modifiers);
4433 lifted.Add (lifted_op);
4440 // Merge two sets of user operators into one, they are mostly distinguish
4441 // except when they share base type and it contains an operator
4443 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
4445 var combined = new List<MemberSpec> (left.Count + right.Count);
4446 combined.AddRange (left);
4447 foreach (var r in right) {
4449 foreach (var l in left) {
4450 if (l.DeclaringType == r.DeclaringType) {
4463 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
4465 if (c is IntegralConstant || c is CharConstant) {
4467 c.ConvertExplicitly (true, type);
4468 } catch (OverflowException) {
4469 ec.Report.Warning (652, 2, loc,
4470 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
4471 type.GetSignatureForError ());
4477 /// EmitBranchable is called from Statement.EmitBoolExpression in the
4478 /// context of a conditional bool expression. This function will return
4479 /// false if it is was possible to use EmitBranchable, or true if it was.
4481 /// The expression's code is generated, and we will generate a branch to `target'
4482 /// if the resulting expression value is equal to isTrue
4484 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
4486 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4487 left = left.EmitToField (ec);
4489 if ((oper & Operator.LogicalMask) == 0) {
4490 right = right.EmitToField (ec);
4495 // This is more complicated than it looks, but its just to avoid
4496 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
4497 // but on top of that we want for == and != to use a special path
4498 // if we are comparing against null
4500 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
4501 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
4504 // put the constant on the rhs, for simplicity
4506 if (left is Constant) {
4507 Expression swap = right;
4513 // brtrue/brfalse works with native int only
4515 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
4516 left.EmitBranchable (ec, target, my_on_true);
4519 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
4520 // right is a boolean, and it's not 'false' => it is 'true'
4521 left.EmitBranchable (ec, target, !my_on_true);
4525 } else if (oper == Operator.LogicalAnd) {
4528 Label tests_end = ec.DefineLabel ();
4530 left.EmitBranchable (ec, tests_end, false);
4531 right.EmitBranchable (ec, target, true);
4532 ec.MarkLabel (tests_end);
4535 // This optimizes code like this
4536 // if (true && i > 4)
4538 if (!(left is Constant))
4539 left.EmitBranchable (ec, target, false);
4541 if (!(right is Constant))
4542 right.EmitBranchable (ec, target, false);
4547 } else if (oper == Operator.LogicalOr){
4549 left.EmitBranchable (ec, target, true);
4550 right.EmitBranchable (ec, target, true);
4553 Label tests_end = ec.DefineLabel ();
4554 left.EmitBranchable (ec, tests_end, true);
4555 right.EmitBranchable (ec, target, false);
4556 ec.MarkLabel (tests_end);
4561 } else if ((oper & Operator.ComparisonMask) == 0) {
4562 base.EmitBranchable (ec, target, on_true);
4569 TypeSpec t = left.Type;
4570 bool is_float = IsFloat (t);
4571 bool is_unsigned = is_float || IsUnsigned (t);
4574 case Operator.Equality:
4576 ec.Emit (OpCodes.Beq, target);
4578 ec.Emit (OpCodes.Bne_Un, target);
4581 case Operator.Inequality:
4583 ec.Emit (OpCodes.Bne_Un, target);
4585 ec.Emit (OpCodes.Beq, target);
4588 case Operator.LessThan:
4590 if (is_unsigned && !is_float)
4591 ec.Emit (OpCodes.Blt_Un, target);
4593 ec.Emit (OpCodes.Blt, target);
4596 ec.Emit (OpCodes.Bge_Un, target);
4598 ec.Emit (OpCodes.Bge, target);
4601 case Operator.GreaterThan:
4603 if (is_unsigned && !is_float)
4604 ec.Emit (OpCodes.Bgt_Un, target);
4606 ec.Emit (OpCodes.Bgt, target);
4609 ec.Emit (OpCodes.Ble_Un, target);
4611 ec.Emit (OpCodes.Ble, target);
4614 case Operator.LessThanOrEqual:
4616 if (is_unsigned && !is_float)
4617 ec.Emit (OpCodes.Ble_Un, target);
4619 ec.Emit (OpCodes.Ble, target);
4622 ec.Emit (OpCodes.Bgt_Un, target);
4624 ec.Emit (OpCodes.Bgt, target);
4628 case Operator.GreaterThanOrEqual:
4630 if (is_unsigned && !is_float)
4631 ec.Emit (OpCodes.Bge_Un, target);
4633 ec.Emit (OpCodes.Bge, target);
4636 ec.Emit (OpCodes.Blt_Un, target);
4638 ec.Emit (OpCodes.Blt, target);
4641 throw new InternalErrorException (oper.ToString ());
4645 public override void Emit (EmitContext ec)
4647 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4648 left = left.EmitToField (ec);
4650 if ((oper & Operator.LogicalMask) == 0) {
4651 right = right.EmitToField (ec);
4656 // Handle short-circuit operators differently
4659 if ((oper & Operator.LogicalMask) != 0) {
4660 Label load_result = ec.DefineLabel ();
4661 Label end = ec.DefineLabel ();
4663 bool is_or = oper == Operator.LogicalOr;
4664 left.EmitBranchable (ec, load_result, is_or);
4666 ec.Emit (OpCodes.Br_S, end);
4668 ec.MarkLabel (load_result);
4669 ec.EmitInt (is_or ? 1 : 0);
4675 // Optimize zero-based operations which cannot be optimized at expression level
4677 if (oper == Operator.Subtraction) {
4678 var lc = left as IntegralConstant;
4679 if (lc != null && lc.IsDefaultValue) {
4681 ec.Emit (OpCodes.Neg);
4686 EmitOperator (ec, left, right);
4689 public void EmitOperator (EmitContext ec, Expression left, Expression right)
4694 EmitOperatorOpcode (ec, oper, left.Type, right);
4697 // Emit result enumerable conversion this way because it's quite complicated get it
4698 // to resolved tree because expression tree cannot see it.
4700 if (enum_conversion != 0)
4701 ConvCast.Emit (ec, enum_conversion);
4704 public override void EmitSideEffect (EmitContext ec)
4706 if ((oper & Operator.LogicalMask) != 0 ||
4707 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
4708 base.EmitSideEffect (ec);
4710 left.EmitSideEffect (ec);
4711 right.EmitSideEffect (ec);
4715 public override Expression EmitToField (EmitContext ec)
4717 if ((oper & Operator.LogicalMask) == 0) {
4718 var await_expr = left as Await;
4719 if (await_expr != null && right.IsSideEffectFree) {
4720 await_expr.Statement.EmitPrologue (ec);
4721 left = await_expr.Statement.GetResultExpression (ec);
4725 await_expr = right as Await;
4726 if (await_expr != null && left.IsSideEffectFree) {
4727 await_expr.Statement.EmitPrologue (ec);
4728 right = await_expr.Statement.GetResultExpression (ec);
4733 return base.EmitToField (ec);
4736 protected override void CloneTo (CloneContext clonectx, Expression t)
4738 Binary target = (Binary) t;
4740 target.left = left.Clone (clonectx);
4741 target.right = right.Clone (clonectx);
4744 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
4746 Arguments binder_args = new Arguments (4);
4748 MemberAccess sle = new MemberAccess (new MemberAccess (
4749 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
4751 CSharpBinderFlags flags = 0;
4752 if (ec.HasSet (ResolveContext.Options.CheckedScope))
4753 flags = CSharpBinderFlags.CheckedContext;
4755 if ((oper & Operator.LogicalMask) != 0)
4756 flags |= CSharpBinderFlags.BinaryOperationLogical;
4758 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
4759 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
4760 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
4761 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
4763 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
4766 public override Expression CreateExpressionTree (ResolveContext ec)
4768 return CreateExpressionTree (ec, null);
4771 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
4774 bool lift_arg = false;
4777 case Operator.Addition:
4778 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4779 method_name = "AddChecked";
4781 method_name = "Add";
4783 case Operator.BitwiseAnd:
4784 method_name = "And";
4786 case Operator.BitwiseOr:
4789 case Operator.Division:
4790 method_name = "Divide";
4792 case Operator.Equality:
4793 method_name = "Equal";
4796 case Operator.ExclusiveOr:
4797 method_name = "ExclusiveOr";
4799 case Operator.GreaterThan:
4800 method_name = "GreaterThan";
4803 case Operator.GreaterThanOrEqual:
4804 method_name = "GreaterThanOrEqual";
4807 case Operator.Inequality:
4808 method_name = "NotEqual";
4811 case Operator.LeftShift:
4812 method_name = "LeftShift";
4814 case Operator.LessThan:
4815 method_name = "LessThan";
4818 case Operator.LessThanOrEqual:
4819 method_name = "LessThanOrEqual";
4822 case Operator.LogicalAnd:
4823 method_name = "AndAlso";
4825 case Operator.LogicalOr:
4826 method_name = "OrElse";
4828 case Operator.Modulus:
4829 method_name = "Modulo";
4831 case Operator.Multiply:
4832 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4833 method_name = "MultiplyChecked";
4835 method_name = "Multiply";
4837 case Operator.RightShift:
4838 method_name = "RightShift";
4840 case Operator.Subtraction:
4841 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4842 method_name = "SubtractChecked";
4844 method_name = "Subtract";
4848 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4851 Arguments args = new Arguments (2);
4852 args.Add (new Argument (left.CreateExpressionTree (ec)));
4853 args.Add (new Argument (right.CreateExpressionTree (ec)));
4854 if (method != null) {
4856 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4858 args.Add (new Argument (method));
4861 return CreateExpressionFactoryCall (ec, method_name, args);
4864 public override object Accept (StructuralVisitor visitor)
4866 return visitor.Visit (this);
4872 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4873 // b, c, d... may be strings or objects.
4875 public class StringConcat : Expression
4877 Arguments arguments;
4879 StringConcat (Location loc)
4882 arguments = new Arguments (2);
4885 public override bool ContainsEmitWithAwait ()
4887 return arguments.ContainsEmitWithAwait ();
4890 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4892 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4893 throw new ArgumentException ();
4895 var s = new StringConcat (loc);
4896 s.type = rc.BuiltinTypes.String;
4897 s.eclass = ExprClass.Value;
4899 s.Append (rc, left);
4900 s.Append (rc, right);
4904 public override Expression CreateExpressionTree (ResolveContext ec)
4906 Argument arg = arguments [0];
4907 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4911 // Creates nested calls tree from an array of arguments used for IL emit
4913 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4915 Arguments concat_args = new Arguments (2);
4916 Arguments add_args = new Arguments (3);
4918 concat_args.Add (left);
4919 add_args.Add (new Argument (left_etree));
4921 concat_args.Add (arguments [pos]);
4922 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4924 var methods = GetConcatMethodCandidates ();
4925 if (methods == null)
4928 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4929 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4933 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4935 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4936 if (++pos == arguments.Count)
4939 left = new Argument (new EmptyExpression (method.ReturnType));
4940 return CreateExpressionAddCall (ec, left, expr, pos);
4943 protected override Expression DoResolve (ResolveContext ec)
4948 void Append (ResolveContext rc, Expression operand)
4953 StringConstant sc = operand as StringConstant;
4955 if (arguments.Count != 0) {
4956 Argument last_argument = arguments [arguments.Count - 1];
4957 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4958 if (last_expr_constant != null) {
4959 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4965 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4967 StringConcat concat_oper = operand as StringConcat;
4968 if (concat_oper != null) {
4969 arguments.AddRange (concat_oper.arguments);
4974 arguments.Add (new Argument (operand));
4977 IList<MemberSpec> GetConcatMethodCandidates ()
4979 return MemberCache.FindMembers (type, "Concat", true);
4982 public override void Emit (EmitContext ec)
4984 // Optimize by removing any extra null arguments, they are no-op
4985 for (int i = 0; i < arguments.Count; ++i) {
4986 if (arguments[i].Expr is NullConstant)
4987 arguments.RemoveAt (i--);
4990 var members = GetConcatMethodCandidates ();
4991 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4992 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4993 if (method != null) {
4994 var call = new CallEmitter ();
4995 call.EmitPredefined (ec, method, arguments);
4999 public override void FlowAnalysis (FlowAnalysisContext fc)
5001 arguments.FlowAnalysis (fc);
5004 public override SLE.Expression MakeExpression (BuilderContext ctx)
5006 if (arguments.Count != 2)
5007 throw new NotImplementedException ("arguments.Count != 2");
5009 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5010 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5015 // User-defined conditional logical operator
5017 public class ConditionalLogicalOperator : UserOperatorCall
5019 readonly bool is_and;
5020 Expression oper_expr;
5022 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5023 : base (oper, arguments, expr_tree, loc)
5025 this.is_and = is_and;
5026 eclass = ExprClass.Unresolved;
5029 protected override Expression DoResolve (ResolveContext ec)
5031 AParametersCollection pd = oper.Parameters;
5032 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5033 ec.Report.Error (217, loc,
5034 "A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
5035 oper.GetSignatureForError ());
5039 Expression left_dup = new EmptyExpression (type);
5040 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5041 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5042 if (op_true == null || op_false == null) {
5043 ec.Report.Error (218, loc,
5044 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5045 type.GetSignatureForError (), oper.GetSignatureForError ());
5049 oper_expr = is_and ? op_false : op_true;
5050 eclass = ExprClass.Value;
5054 public override void Emit (EmitContext ec)
5056 Label end_target = ec.DefineLabel ();
5059 // Emit and duplicate left argument
5061 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5062 if (right_contains_await) {
5063 arguments[0] = arguments[0].EmitToField (ec, false);
5064 arguments[0].Expr.Emit (ec);
5066 arguments[0].Expr.Emit (ec);
5067 ec.Emit (OpCodes.Dup);
5068 arguments.RemoveAt (0);
5071 oper_expr.EmitBranchable (ec, end_target, true);
5075 if (right_contains_await) {
5077 // Special handling when right expression contains await and left argument
5078 // could not be left on stack before logical branch
5080 Label skip_left_load = ec.DefineLabel ();
5081 ec.Emit (OpCodes.Br_S, skip_left_load);
5082 ec.MarkLabel (end_target);
5083 arguments[0].Expr.Emit (ec);
5084 ec.MarkLabel (skip_left_load);
5086 ec.MarkLabel (end_target);
5091 public class PointerArithmetic : Expression {
5092 Expression left, right;
5093 readonly Binary.Operator op;
5096 // We assume that `l' is always a pointer
5098 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5107 public override bool ContainsEmitWithAwait ()
5109 throw new NotImplementedException ();
5112 public override Expression CreateExpressionTree (ResolveContext ec)
5114 Error_PointerInsideExpressionTree (ec);
5118 protected override Expression DoResolve (ResolveContext ec)
5120 eclass = ExprClass.Variable;
5122 var pc = left.Type as PointerContainer;
5123 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5124 Error_VoidPointerOperation (ec);
5131 public override void Emit (EmitContext ec)
5133 TypeSpec op_type = left.Type;
5135 // It must be either array or fixed buffer
5137 if (TypeManager.HasElementType (op_type)) {
5138 element = TypeManager.GetElementType (op_type);
5140 FieldExpr fe = left as FieldExpr;
5142 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5147 int size = BuiltinTypeSpec.GetSize(element);
5148 TypeSpec rtype = right.Type;
5150 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5152 // handle (pointer - pointer)
5156 ec.Emit (OpCodes.Sub);
5160 ec.Emit (OpCodes.Sizeof, element);
5163 ec.Emit (OpCodes.Div);
5165 ec.Emit (OpCodes.Conv_I8);
5168 // handle + and - on (pointer op int)
5170 Constant left_const = left as Constant;
5171 if (left_const != null) {
5173 // Optimize ((T*)null) pointer operations
5175 if (left_const.IsDefaultValue) {
5176 left = EmptyExpression.Null;
5184 var right_const = right as Constant;
5185 if (right_const != null) {
5187 // Optimize 0-based arithmetic
5189 if (right_const.IsDefaultValue)
5193 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5195 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5197 // TODO: Should be the checks resolve context sensitive?
5198 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5199 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5205 switch (rtype.BuiltinType) {
5206 case BuiltinTypeSpec.Type.SByte:
5207 case BuiltinTypeSpec.Type.Byte:
5208 case BuiltinTypeSpec.Type.Short:
5209 case BuiltinTypeSpec.Type.UShort:
5210 ec.Emit (OpCodes.Conv_I);
5212 case BuiltinTypeSpec.Type.UInt:
5213 ec.Emit (OpCodes.Conv_U);
5217 if (right_const == null && size != 1){
5219 ec.Emit (OpCodes.Sizeof, element);
5222 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5223 ec.Emit (OpCodes.Conv_I8);
5225 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
5228 if (left_const == null) {
5229 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
5230 ec.Emit (OpCodes.Conv_I);
5231 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5232 ec.Emit (OpCodes.Conv_U);
5234 Binary.EmitOperatorOpcode (ec, op, op_type, right);
5241 // A boolean-expression is an expression that yields a result
5244 public class BooleanExpression : ShimExpression
5246 public BooleanExpression (Expression expr)
5249 this.loc = expr.Location;
5252 public override Expression CreateExpressionTree (ResolveContext ec)
5254 // TODO: We should emit IsTrue (v4) instead of direct user operator
5255 // call but that would break csc compatibility
5256 return base.CreateExpressionTree (ec);
5259 protected override Expression DoResolve (ResolveContext ec)
5261 // A boolean-expression is required to be of a type
5262 // that can be implicitly converted to bool or of
5263 // a type that implements operator true
5265 expr = expr.Resolve (ec);
5269 Assign ass = expr as Assign;
5270 if (ass != null && ass.Source is Constant) {
5271 ec.Report.Warning (665, 3, loc,
5272 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
5275 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
5278 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5279 Arguments args = new Arguments (1);
5280 args.Add (new Argument (expr));
5281 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
5284 type = ec.BuiltinTypes.Bool;
5285 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
5286 if (converted != null)
5290 // If no implicit conversion to bool exists, try using `operator true'
5292 converted = GetOperatorTrue (ec, expr, loc);
5293 if (converted == null) {
5294 expr.Error_ValueCannotBeConverted (ec, type, false);
5301 public override object Accept (StructuralVisitor visitor)
5303 return visitor.Visit (this);
5307 public class BooleanExpressionFalse : Unary
5309 public BooleanExpressionFalse (Expression expr)
5310 : base (Operator.LogicalNot, expr, expr.Location)
5314 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
5316 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
5321 /// Implements the ternary conditional operator (?:)
5323 public class Conditional : Expression {
5324 Expression expr, true_expr, false_expr;
5326 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
5329 this.true_expr = true_expr;
5330 this.false_expr = false_expr;
5336 public Expression Expr {
5342 public Expression TrueExpr {
5348 public Expression FalseExpr {
5356 public override bool ContainsEmitWithAwait ()
5358 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
5361 public override Expression CreateExpressionTree (ResolveContext ec)
5363 Arguments args = new Arguments (3);
5364 args.Add (new Argument (expr.CreateExpressionTree (ec)));
5365 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
5366 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
5367 return CreateExpressionFactoryCall (ec, "Condition", args);
5370 protected override Expression DoResolve (ResolveContext ec)
5372 expr = expr.Resolve (ec);
5373 true_expr = true_expr.Resolve (ec);
5374 false_expr = false_expr.Resolve (ec);
5376 if (true_expr == null || false_expr == null || expr == null)
5379 eclass = ExprClass.Value;
5380 TypeSpec true_type = true_expr.Type;
5381 TypeSpec false_type = false_expr.Type;
5385 // First, if an implicit conversion exists from true_expr
5386 // to false_expr, then the result type is of type false_expr.Type
5388 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
5389 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
5390 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5392 // Check if both can convert implicitly to each other's type
5396 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5397 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
5399 // LAMESPEC: There seems to be hardcoded promotition to int type when
5400 // both sides are numeric constants and one side is int constant and
5401 // other side is numeric constant convertible to int.
5403 // var res = condition ? (short)1 : 1;
5405 // Type of res is int even if according to the spec the conversion is
5406 // ambiguous because 1 literal can be converted to short.
5408 if (conv_false_expr != null) {
5409 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
5411 conv_false_expr = null;
5412 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
5413 conv_false_expr = null;
5417 if (conv_false_expr != null) {
5418 ec.Report.Error (172, true_expr.Location,
5419 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
5420 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5425 if (true_expr.Type != type)
5426 true_expr = EmptyCast.Create (true_expr, type);
5427 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
5430 ec.Report.Error (173, true_expr.Location,
5431 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
5432 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5437 Constant c = expr as Constant;
5439 bool is_false = c.IsDefaultValue;
5442 // Don't issue the warning for constant expressions
5444 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
5445 // CSC: Missing warning
5446 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
5449 return ReducedExpression.Create (
5450 is_false ? false_expr : true_expr, this,
5451 false_expr is Constant && true_expr is Constant).Resolve (ec);
5457 public override void Emit (EmitContext ec)
5459 Label false_target = ec.DefineLabel ();
5460 Label end_target = ec.DefineLabel ();
5462 expr.EmitBranchable (ec, false_target, false);
5463 true_expr.Emit (ec);
5466 // Verifier doesn't support interface merging. When there are two types on
5467 // the stack without common type hint and the common type is an interface.
5468 // Use temporary local to give verifier hint on what type to unify the stack
5470 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
5471 var temp = ec.GetTemporaryLocal (type);
5472 ec.Emit (OpCodes.Stloc, temp);
5473 ec.Emit (OpCodes.Ldloc, temp);
5474 ec.FreeTemporaryLocal (temp, type);
5477 ec.Emit (OpCodes.Br, end_target);
5478 ec.MarkLabel (false_target);
5479 false_expr.Emit (ec);
5480 ec.MarkLabel (end_target);
5483 public override void FlowAnalysis (FlowAnalysisContext fc)
5485 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
5487 expr.FlowAnalysis (fc);
5488 var da_true = fc.DefiniteAssignmentOnTrue;
5489 var da_false = fc.DefiniteAssignmentOnFalse;
5491 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da_true);
5492 true_expr.FlowAnalysis (fc);
5493 var true_fc = fc.DefiniteAssignment;
5495 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da_false);
5496 false_expr.FlowAnalysis (fc);
5498 fc.DefiniteAssignment &= true_fc;
5499 if (fc.DefiniteAssignmentOnTrue != null)
5500 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignment;
5501 if (fc.DefiniteAssignmentOnFalse != null)
5502 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
5505 protected override void CloneTo (CloneContext clonectx, Expression t)
5507 Conditional target = (Conditional) t;
5509 target.expr = expr.Clone (clonectx);
5510 target.true_expr = true_expr.Clone (clonectx);
5511 target.false_expr = false_expr.Clone (clonectx);
5515 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
5517 LocalTemporary temp;
5520 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
5521 public abstract void SetHasAddressTaken ();
5523 public abstract bool IsLockedByStatement { get; set; }
5525 public abstract bool IsFixed { get; }
5526 public abstract bool IsRef { get; }
5527 public abstract string Name { get; }
5530 // Variable IL data, it has to be protected to encapsulate hoisted variables
5532 protected abstract ILocalVariable Variable { get; }
5535 // Variable flow-analysis data
5537 public abstract VariableInfo VariableInfo { get; }
5540 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5542 HoistedVariable hv = GetHoistedVariable (ec);
5544 hv.AddressOf (ec, mode);
5548 Variable.EmitAddressOf (ec);
5551 public override bool ContainsEmitWithAwait ()
5556 public override Expression CreateExpressionTree (ResolveContext ec)
5558 HoistedVariable hv = GetHoistedVariable (ec);
5560 return hv.CreateExpressionTree ();
5562 Arguments arg = new Arguments (1);
5563 arg.Add (new Argument (this));
5564 return CreateExpressionFactoryCall (ec, "Constant", arg);
5567 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
5569 if (IsLockedByStatement) {
5570 rc.Report.Warning (728, 2, loc,
5571 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
5578 public override void Emit (EmitContext ec)
5583 public override void EmitSideEffect (EmitContext ec)
5589 // This method is used by parameters that are references, that are
5590 // being passed as references: we only want to pass the pointer (that
5591 // is already stored in the parameter, not the address of the pointer,
5592 // and not the value of the variable).
5594 public void EmitLoad (EmitContext ec)
5599 public void Emit (EmitContext ec, bool leave_copy)
5601 HoistedVariable hv = GetHoistedVariable (ec);
5603 hv.Emit (ec, leave_copy);
5611 // If we are a reference, we loaded on the stack a pointer
5612 // Now lets load the real value
5614 ec.EmitLoadFromPtr (type);
5618 ec.Emit (OpCodes.Dup);
5621 temp = new LocalTemporary (Type);
5627 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
5628 bool prepare_for_load)
5630 HoistedVariable hv = GetHoistedVariable (ec);
5632 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
5636 New n_source = source as New;
5637 if (n_source != null) {
5638 if (!n_source.Emit (ec, this)) {
5642 ec.EmitLoadFromPtr (type);
5654 ec.Emit (OpCodes.Dup);
5656 temp = new LocalTemporary (Type);
5662 ec.EmitStoreFromPtr (type);
5664 Variable.EmitAssign (ec);
5672 public override Expression EmitToField (EmitContext ec)
5674 HoistedVariable hv = GetHoistedVariable (ec);
5676 return hv.EmitToField (ec);
5679 return base.EmitToField (ec);
5682 public HoistedVariable GetHoistedVariable (ResolveContext rc)
5684 return GetHoistedVariable (rc.CurrentAnonymousMethod);
5687 public HoistedVariable GetHoistedVariable (EmitContext ec)
5689 return GetHoistedVariable (ec.CurrentAnonymousMethod);
5692 public override string GetSignatureForError ()
5697 public bool IsHoisted {
5698 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
5703 // Resolved reference to a local variable
5705 public class LocalVariableReference : VariableReference
5707 public LocalVariable local_info;
5709 public LocalVariableReference (LocalVariable li, Location l)
5711 this.local_info = li;
5715 public override VariableInfo VariableInfo {
5716 get { return local_info.VariableInfo; }
5719 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5721 return local_info.HoistedVariant;
5727 // A local variable is always fixed
5729 public override bool IsFixed {
5735 public override bool IsLockedByStatement {
5737 return local_info.IsLocked;
5740 local_info.IsLocked = value;
5744 public override bool IsRef {
5745 get { return false; }
5748 public override string Name {
5749 get { return local_info.Name; }
5754 public override void FlowAnalysis (FlowAnalysisContext fc)
5756 VariableInfo variable_info = VariableInfo;
5757 if (variable_info == null)
5760 if (fc.IsDefinitelyAssigned (variable_info))
5763 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
5764 variable_info.SetAssigned (fc.DefiniteAssignment, true);
5767 public override void SetHasAddressTaken ()
5769 local_info.SetHasAddressTaken ();
5772 void DoResolveBase (ResolveContext ec)
5775 // If we are referencing a variable from the external block
5776 // flag it for capturing
5778 if (ec.MustCaptureVariable (local_info)) {
5779 if (local_info.AddressTaken) {
5780 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5781 } else if (local_info.IsFixed) {
5782 ec.Report.Error (1764, loc,
5783 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
5784 GetSignatureForError ());
5787 if (ec.IsVariableCapturingRequired) {
5788 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
5789 storey.CaptureLocalVariable (ec, local_info);
5793 eclass = ExprClass.Variable;
5794 type = local_info.Type;
5797 protected override Expression DoResolve (ResolveContext ec)
5799 local_info.SetIsUsed ();
5805 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5808 // Don't be too pedantic when variable is used as out param or for some broken code
5809 // which uses property/indexer access to run some initialization
5811 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5812 local_info.SetIsUsed ();
5814 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5815 if (rhs == EmptyExpression.LValueMemberAccess) {
5816 // CS1654 already reported
5820 if (rhs == EmptyExpression.OutAccess) {
5821 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5822 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5823 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5824 } else if (rhs == EmptyExpression.UnaryAddress) {
5825 code = 459; msg = "Cannot take the address of {1} `{0}'";
5827 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5829 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5833 if (eclass == ExprClass.Unresolved)
5836 return base.DoResolveLValue (ec, rhs);
5839 public override int GetHashCode ()
5841 return local_info.GetHashCode ();
5844 public override bool Equals (object obj)
5846 LocalVariableReference lvr = obj as LocalVariableReference;
5850 return local_info == lvr.local_info;
5853 protected override ILocalVariable Variable {
5854 get { return local_info; }
5857 public override string ToString ()
5859 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5862 protected override void CloneTo (CloneContext clonectx, Expression t)
5869 /// This represents a reference to a parameter in the intermediate
5872 public class ParameterReference : VariableReference
5874 protected ParametersBlock.ParameterInfo pi;
5876 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5884 public override bool IsLockedByStatement {
5889 pi.IsLocked = value;
5893 public override bool IsRef {
5894 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5897 bool HasOutModifier {
5898 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5901 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5903 return pi.Parameter.HoistedVariant;
5907 // A ref or out parameter is classified as a moveable variable, even
5908 // if the argument given for the parameter is a fixed variable
5910 public override bool IsFixed {
5911 get { return !IsRef; }
5914 public override string Name {
5915 get { return Parameter.Name; }
5918 public Parameter Parameter {
5919 get { return pi.Parameter; }
5922 public override VariableInfo VariableInfo {
5923 get { return pi.VariableInfo; }
5926 protected override ILocalVariable Variable {
5927 get { return Parameter; }
5932 public override void AddressOf (EmitContext ec, AddressOp mode)
5935 // ParameterReferences might already be a reference
5942 base.AddressOf (ec, mode);
5945 public override void SetHasAddressTaken ()
5947 Parameter.HasAddressTaken = true;
5950 bool DoResolveBase (ResolveContext ec)
5952 if (eclass != ExprClass.Unresolved)
5955 type = pi.ParameterType;
5956 eclass = ExprClass.Variable;
5959 // If we are referencing a parameter from the external block
5960 // flag it for capturing
5962 if (ec.MustCaptureVariable (pi)) {
5963 if (Parameter.HasAddressTaken)
5964 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5967 ec.Report.Error (1628, loc,
5968 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5969 Name, ec.CurrentAnonymousMethod.ContainerType);
5972 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5973 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5974 storey.CaptureParameter (ec, pi, this);
5981 public override int GetHashCode ()
5983 return Name.GetHashCode ();
5986 public override bool Equals (object obj)
5988 ParameterReference pr = obj as ParameterReference;
5992 return Name == pr.Name;
5995 protected override void CloneTo (CloneContext clonectx, Expression target)
6001 public override Expression CreateExpressionTree (ResolveContext ec)
6003 HoistedVariable hv = GetHoistedVariable (ec);
6005 return hv.CreateExpressionTree ();
6007 return Parameter.ExpressionTreeVariableReference ();
6010 protected override Expression DoResolve (ResolveContext ec)
6012 if (!DoResolveBase (ec))
6018 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6020 if (!DoResolveBase (ec))
6023 if (Parameter.HoistedVariant != null)
6024 Parameter.HoistedVariant.IsAssigned = true;
6026 return base.DoResolveLValue (ec, right_side);
6029 public override void FlowAnalysis (FlowAnalysisContext fc)
6031 VariableInfo variable_info = VariableInfo;
6032 if (variable_info == null)
6035 if (fc.IsDefinitelyAssigned (variable_info))
6038 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6039 fc.SetVariableAssigned (variable_info);
6044 /// Invocation of methods or delegates.
6046 public class Invocation : ExpressionStatement
6048 protected Arguments arguments;
6049 protected Expression expr;
6050 protected MethodGroupExpr mg;
6052 public Invocation (Expression expr, Arguments arguments)
6055 this.arguments = arguments;
6057 loc = expr.Location;
6062 public Arguments Arguments {
6068 public Expression Exp {
6074 public MethodGroupExpr MethodGroup {
6080 public override Location StartLocation {
6082 return expr.StartLocation;
6088 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6090 if (MethodGroup == null)
6093 var candidate = MethodGroup.BestCandidate;
6094 if (candidate == null || !(candidate.IsStatic || Exp is This))
6097 var args_count = arguments == null ? 0 : arguments.Count;
6098 if (args_count != body.Parameters.Count)
6101 var lambda_parameters = body.Block.Parameters.FixedParameters;
6102 for (int i = 0; i < args_count; ++i) {
6103 var pr = arguments[i].Expr as ParameterReference;
6107 if (lambda_parameters[i] != pr.Parameter)
6110 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6114 var emg = MethodGroup as ExtensionMethodGroupExpr;
6116 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6117 if (candidate.IsGeneric) {
6118 var targs = new TypeExpression [candidate.Arity];
6119 for (int i = 0; i < targs.Length; ++i) {
6120 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6123 mg.SetTypeArguments (null, new TypeArguments (targs));
6132 protected override void CloneTo (CloneContext clonectx, Expression t)
6134 Invocation target = (Invocation) t;
6136 if (arguments != null)
6137 target.arguments = arguments.Clone (clonectx);
6139 target.expr = expr.Clone (clonectx);
6142 public override bool ContainsEmitWithAwait ()
6144 if (arguments != null && arguments.ContainsEmitWithAwait ())
6147 return mg.ContainsEmitWithAwait ();
6150 public override Expression CreateExpressionTree (ResolveContext ec)
6152 Expression instance = mg.IsInstance ?
6153 mg.InstanceExpression.CreateExpressionTree (ec) :
6154 new NullLiteral (loc);
6156 var args = Arguments.CreateForExpressionTree (ec, arguments,
6158 mg.CreateExpressionTree (ec));
6160 return CreateExpressionFactoryCall (ec, "Call", args);
6163 protected override Expression DoResolve (ResolveContext ec)
6165 Expression member_expr;
6166 var atn = expr as ATypeNameExpression;
6168 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
6169 if (member_expr != null)
6170 member_expr = member_expr.Resolve (ec);
6172 member_expr = expr.Resolve (ec);
6175 if (member_expr == null)
6179 // Next, evaluate all the expressions in the argument list
6181 bool dynamic_arg = false;
6182 if (arguments != null)
6183 arguments.Resolve (ec, out dynamic_arg);
6185 TypeSpec expr_type = member_expr.Type;
6186 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6187 return DoResolveDynamic (ec, member_expr);
6189 mg = member_expr as MethodGroupExpr;
6190 Expression invoke = null;
6193 if (expr_type != null && expr_type.IsDelegate) {
6194 invoke = new DelegateInvocation (member_expr, arguments, loc);
6195 invoke = invoke.Resolve (ec);
6196 if (invoke == null || !dynamic_arg)
6199 if (member_expr is RuntimeValueExpression) {
6200 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
6201 member_expr.Type.GetSignatureForError ());
6205 MemberExpr me = member_expr as MemberExpr;
6207 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
6211 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
6212 member_expr.GetSignatureForError ());
6217 if (invoke == null) {
6218 mg = DoResolveOverload (ec);
6224 return DoResolveDynamic (ec, member_expr);
6226 var method = mg.BestCandidate;
6227 type = mg.BestCandidateReturnType;
6229 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
6231 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
6233 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
6237 IsSpecialMethodInvocation (ec, method, loc);
6239 eclass = ExprClass.Value;
6243 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
6246 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
6248 args = dmb.Arguments;
6249 if (arguments != null)
6250 args.AddRange (arguments);
6251 } else if (mg == null) {
6252 if (arguments == null)
6253 args = new Arguments (1);
6257 args.Insert (0, new Argument (memberExpr));
6261 ec.Report.Error (1971, loc,
6262 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
6267 if (arguments == null)
6268 args = new Arguments (1);
6272 MemberAccess ma = expr as MemberAccess;
6274 var left_type = ma.LeftExpression as TypeExpr;
6275 if (left_type != null) {
6276 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6279 // Any value type has to be pass as by-ref to get back the same
6280 // instance on which the member was called
6282 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
6283 Argument.AType.Ref : Argument.AType.None;
6284 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
6286 } else { // is SimpleName
6288 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6290 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
6295 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
6298 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
6300 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
6303 public override void FlowAnalysis (FlowAnalysisContext fc)
6305 if (mg.IsConditionallyExcluded)
6308 mg.FlowAnalysis (fc);
6310 if (arguments != null)
6311 arguments.FlowAnalysis (fc);
6314 public override string GetSignatureForError ()
6316 return mg.GetSignatureForError ();
6320 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
6321 // or the type dynamic, then the member is invocable
6323 public static bool IsMemberInvocable (MemberSpec member)
6325 switch (member.Kind) {
6326 case MemberKind.Event:
6328 case MemberKind.Field:
6329 case MemberKind.Property:
6330 var m = member as IInterfaceMemberSpec;
6331 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
6337 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
6339 if (!method.IsReservedMethod)
6342 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
6345 ec.Report.SymbolRelatedToPreviousError (method);
6346 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
6347 method.GetSignatureForError ());
6352 public override void Emit (EmitContext ec)
6354 if (mg.IsConditionallyExcluded)
6357 mg.EmitCall (ec, arguments);
6360 public override void EmitStatement (EmitContext ec)
6365 // Pop the return value if there is one
6367 if (type.Kind != MemberKind.Void)
6368 ec.Emit (OpCodes.Pop);
6371 public override SLE.Expression MakeExpression (BuilderContext ctx)
6373 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
6376 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
6379 throw new NotSupportedException ();
6381 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
6382 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
6386 public override object Accept (StructuralVisitor visitor)
6388 return visitor.Visit (this);
6393 // Implements simple new expression
6395 public class New : ExpressionStatement, IMemoryLocation
6397 protected Arguments arguments;
6400 // During bootstrap, it contains the RequestedType,
6401 // but if `type' is not null, it *might* contain a NewDelegate
6402 // (because of field multi-initialization)
6404 protected Expression RequestedType;
6406 protected MethodSpec method;
6408 public New (Expression requested_type, Arguments arguments, Location l)
6410 RequestedType = requested_type;
6411 this.arguments = arguments;
6416 public Arguments Arguments {
6423 // Returns true for resolved `new S()'
6425 public bool IsDefaultStruct {
6427 return arguments == null && type.IsStruct && GetType () == typeof (New);
6431 public Expression TypeExpression {
6433 return RequestedType;
6440 /// Converts complex core type syntax like 'new int ()' to simple constant
6442 public static Constant Constantify (TypeSpec t, Location loc)
6444 switch (t.BuiltinType) {
6445 case BuiltinTypeSpec.Type.Int:
6446 return new IntConstant (t, 0, loc);
6447 case BuiltinTypeSpec.Type.UInt:
6448 return new UIntConstant (t, 0, loc);
6449 case BuiltinTypeSpec.Type.Long:
6450 return new LongConstant (t, 0, loc);
6451 case BuiltinTypeSpec.Type.ULong:
6452 return new ULongConstant (t, 0, loc);
6453 case BuiltinTypeSpec.Type.Float:
6454 return new FloatConstant (t, 0, loc);
6455 case BuiltinTypeSpec.Type.Double:
6456 return new DoubleConstant (t, 0, loc);
6457 case BuiltinTypeSpec.Type.Short:
6458 return new ShortConstant (t, 0, loc);
6459 case BuiltinTypeSpec.Type.UShort:
6460 return new UShortConstant (t, 0, loc);
6461 case BuiltinTypeSpec.Type.SByte:
6462 return new SByteConstant (t, 0, loc);
6463 case BuiltinTypeSpec.Type.Byte:
6464 return new ByteConstant (t, 0, loc);
6465 case BuiltinTypeSpec.Type.Char:
6466 return new CharConstant (t, '\0', loc);
6467 case BuiltinTypeSpec.Type.Bool:
6468 return new BoolConstant (t, false, loc);
6469 case BuiltinTypeSpec.Type.Decimal:
6470 return new DecimalConstant (t, 0, loc);
6474 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
6476 if (t.IsNullableType)
6477 return Nullable.LiftedNull.Create (t, loc);
6482 public override bool ContainsEmitWithAwait ()
6484 return arguments != null && arguments.ContainsEmitWithAwait ();
6488 // Checks whether the type is an interface that has the
6489 // [ComImport, CoClass] attributes and must be treated
6492 public Expression CheckComImport (ResolveContext ec)
6494 if (!type.IsInterface)
6498 // Turn the call into:
6499 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
6501 var real_class = type.MemberDefinition.GetAttributeCoClass ();
6502 if (real_class == null)
6505 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
6506 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
6507 return cast.Resolve (ec);
6510 public override Expression CreateExpressionTree (ResolveContext ec)
6513 if (method == null) {
6514 args = new Arguments (1);
6515 args.Add (new Argument (new TypeOf (type, loc)));
6517 args = Arguments.CreateForExpressionTree (ec,
6518 arguments, new TypeOfMethod (method, loc));
6521 return CreateExpressionFactoryCall (ec, "New", args);
6524 protected override Expression DoResolve (ResolveContext ec)
6526 type = RequestedType.ResolveAsType (ec);
6530 eclass = ExprClass.Value;
6532 if (type.IsPointer) {
6533 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
6534 type.GetSignatureForError ());
6538 if (arguments == null) {
6539 Constant c = Constantify (type, RequestedType.Location);
6541 return ReducedExpression.Create (c, this);
6544 if (type.IsDelegate) {
6545 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
6548 var tparam = type as TypeParameterSpec;
6549 if (tparam != null) {
6551 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
6552 // where type parameter constraint is inflated to struct
6554 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
6555 ec.Report.Error (304, loc,
6556 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
6557 type.GetSignatureForError ());
6560 if ((arguments != null) && (arguments.Count != 0)) {
6561 ec.Report.Error (417, loc,
6562 "`{0}': cannot provide arguments when creating an instance of a variable type",
6563 type.GetSignatureForError ());
6569 if (type.IsStatic) {
6570 ec.Report.SymbolRelatedToPreviousError (type);
6571 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
6575 if (type.IsInterface || type.IsAbstract){
6576 if (!TypeManager.IsGenericType (type)) {
6577 RequestedType = CheckComImport (ec);
6578 if (RequestedType != null)
6579 return RequestedType;
6582 ec.Report.SymbolRelatedToPreviousError (type);
6583 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
6588 // Any struct always defines parameterless constructor
6590 if (type.IsStruct && arguments == null)
6594 if (arguments != null) {
6595 arguments.Resolve (ec, out dynamic);
6600 method = ConstructorLookup (ec, type, ref arguments, loc);
6603 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6604 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
6610 bool DoEmitTypeParameter (EmitContext ec)
6612 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
6616 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
6617 var tparam = (TypeParameterSpec) type;
6619 if (tparam.IsReferenceType) {
6620 ec.Emit (OpCodes.Call, ctor_factory);
6624 // Allow DoEmit() to be called multiple times.
6625 // We need to create a new LocalTemporary each time since
6626 // you can't share LocalBuilders among ILGeneators.
6627 LocalTemporary temp = new LocalTemporary (type);
6629 Label label_activator = ec.DefineLabel ();
6630 Label label_end = ec.DefineLabel ();
6632 temp.AddressOf (ec, AddressOp.Store);
6633 ec.Emit (OpCodes.Initobj, type);
6636 ec.Emit (OpCodes.Box, type);
6637 ec.Emit (OpCodes.Brfalse, label_activator);
6639 temp.AddressOf (ec, AddressOp.Store);
6640 ec.Emit (OpCodes.Initobj, type);
6643 ec.Emit (OpCodes.Br_S, label_end);
6645 ec.MarkLabel (label_activator);
6647 ec.Emit (OpCodes.Call, ctor_factory);
6648 ec.MarkLabel (label_end);
6653 // This Emit can be invoked in two contexts:
6654 // * As a mechanism that will leave a value on the stack (new object)
6655 // * As one that wont (init struct)
6657 // If we are dealing with a ValueType, we have a few
6658 // situations to deal with:
6660 // * The target is a ValueType, and we have been provided
6661 // the instance (this is easy, we are being assigned).
6663 // * The target of New is being passed as an argument,
6664 // to a boxing operation or a function that takes a
6667 // In this case, we need to create a temporary variable
6668 // that is the argument of New.
6670 // Returns whether a value is left on the stack
6672 // *** Implementation note ***
6674 // To benefit from this optimization, each assignable expression
6675 // has to manually cast to New and call this Emit.
6677 // TODO: It's worth to implement it for arrays and fields
6679 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
6681 bool is_value_type = TypeSpec.IsValueType (type);
6682 VariableReference vr = target as VariableReference;
6684 if (target != null && is_value_type && (vr != null || method == null)) {
6685 target.AddressOf (ec, AddressOp.Store);
6686 } else if (vr != null && vr.IsRef) {
6690 if (arguments != null) {
6691 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
6692 arguments = arguments.Emit (ec, false, true);
6694 arguments.Emit (ec);
6697 if (is_value_type) {
6698 if (method == null) {
6699 ec.Emit (OpCodes.Initobj, type);
6704 ec.MarkCallEntry (loc);
6705 ec.Emit (OpCodes.Call, method);
6710 if (type is TypeParameterSpec)
6711 return DoEmitTypeParameter (ec);
6713 ec.MarkCallEntry (loc);
6714 ec.Emit (OpCodes.Newobj, method);
6718 public override void Emit (EmitContext ec)
6720 LocalTemporary v = null;
6721 if (method == null && TypeSpec.IsValueType (type)) {
6722 // TODO: Use temporary variable from pool
6723 v = new LocalTemporary (type);
6730 public override void EmitStatement (EmitContext ec)
6732 LocalTemporary v = null;
6733 if (method == null && TypeSpec.IsValueType (type)) {
6734 // TODO: Use temporary variable from pool
6735 v = new LocalTemporary (type);
6739 ec.Emit (OpCodes.Pop);
6742 public override void FlowAnalysis (FlowAnalysisContext fc)
6744 if (arguments != null)
6745 arguments.FlowAnalysis (fc);
6748 public void AddressOf (EmitContext ec, AddressOp mode)
6750 EmitAddressOf (ec, mode);
6753 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
6755 LocalTemporary value_target = new LocalTemporary (type);
6757 if (type is TypeParameterSpec) {
6758 DoEmitTypeParameter (ec);
6759 value_target.Store (ec);
6760 value_target.AddressOf (ec, mode);
6761 return value_target;
6764 value_target.AddressOf (ec, AddressOp.Store);
6766 if (method == null) {
6767 ec.Emit (OpCodes.Initobj, type);
6769 if (arguments != null)
6770 arguments.Emit (ec);
6772 ec.Emit (OpCodes.Call, method);
6775 value_target.AddressOf (ec, mode);
6776 return value_target;
6779 protected override void CloneTo (CloneContext clonectx, Expression t)
6781 New target = (New) t;
6783 target.RequestedType = RequestedType.Clone (clonectx);
6784 if (arguments != null){
6785 target.arguments = arguments.Clone (clonectx);
6789 public override SLE.Expression MakeExpression (BuilderContext ctx)
6792 return base.MakeExpression (ctx);
6794 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
6798 public override object Accept (StructuralVisitor visitor)
6800 return visitor.Visit (this);
6805 // Array initializer expression, the expression is allowed in
6806 // variable or field initialization only which makes it tricky as
6807 // the type has to be infered based on the context either from field
6808 // type or variable type (think of multiple declarators)
6810 public class ArrayInitializer : Expression
6812 List<Expression> elements;
6813 BlockVariable variable;
6815 public ArrayInitializer (List<Expression> init, Location loc)
6821 public ArrayInitializer (int count, Location loc)
6822 : this (new List<Expression> (count), loc)
6826 public ArrayInitializer (Location loc)
6834 get { return elements.Count; }
6837 public List<Expression> Elements {
6843 public Expression this [int index] {
6845 return elements [index];
6849 public BlockVariable VariableDeclaration {
6860 public void Add (Expression expr)
6862 elements.Add (expr);
6865 public override bool ContainsEmitWithAwait ()
6867 throw new NotSupportedException ();
6870 public override Expression CreateExpressionTree (ResolveContext ec)
6872 throw new NotSupportedException ("ET");
6875 protected override void CloneTo (CloneContext clonectx, Expression t)
6877 var target = (ArrayInitializer) t;
6879 target.elements = new List<Expression> (elements.Count);
6880 foreach (var element in elements)
6881 target.elements.Add (element.Clone (clonectx));
6884 protected override Expression DoResolve (ResolveContext rc)
6886 var current_field = rc.CurrentMemberDefinition as FieldBase;
6887 TypeExpression type;
6888 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6889 type = new TypeExpression (current_field.MemberType, current_field.Location);
6890 } else if (variable != null) {
6891 if (variable.TypeExpression is VarExpr) {
6892 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6893 return EmptyExpression.Null;
6896 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6898 throw new NotImplementedException ("Unexpected array initializer context");
6901 return new ArrayCreation (type, this).Resolve (rc);
6904 public override void Emit (EmitContext ec)
6906 throw new InternalErrorException ("Missing Resolve call");
6909 public override void FlowAnalysis (FlowAnalysisContext fc)
6911 throw new InternalErrorException ("Missing Resolve call");
6914 public override object Accept (StructuralVisitor visitor)
6916 return visitor.Visit (this);
6921 /// 14.5.10.2: Represents an array creation expression.
6925 /// There are two possible scenarios here: one is an array creation
6926 /// expression that specifies the dimensions and optionally the
6927 /// initialization data and the other which does not need dimensions
6928 /// specified but where initialization data is mandatory.
6930 public class ArrayCreation : Expression
6932 FullNamedExpression requested_base_type;
6933 ArrayInitializer initializers;
6936 // The list of Argument types.
6937 // This is used to construct the `newarray' or constructor signature
6939 protected List<Expression> arguments;
6941 protected TypeSpec array_element_type;
6943 protected int dimensions;
6944 protected readonly ComposedTypeSpecifier rank;
6945 Expression first_emit;
6946 LocalTemporary first_emit_temp;
6948 protected List<Expression> array_data;
6950 Dictionary<int, int> bounds;
6953 // The number of constants in array initializers
6954 int const_initializers_count;
6955 bool only_constant_initializers;
6957 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6958 : this (requested_base_type, rank, initializers, l)
6960 arguments = new List<Expression> (exprs);
6961 num_arguments = arguments.Count;
6965 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6967 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6969 this.requested_base_type = requested_base_type;
6971 this.initializers = initializers;
6975 num_arguments = rank.Dimension;
6979 // For compiler generated single dimensional arrays only
6981 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6982 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6987 // For expressions like int[] foo = { 1, 2, 3 };
6989 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6990 : this (requested_base_type, null, initializers, initializers.Location)
6994 public ComposedTypeSpecifier Rank {
7000 public FullNamedExpression TypeExpression {
7002 return this.requested_base_type;
7006 public ArrayInitializer Initializers {
7008 return this.initializers;
7012 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7014 if (initializers != null && bounds == null) {
7016 // We use this to store all the data values in the order in which we
7017 // will need to store them in the byte blob later
7019 array_data = new List<Expression> (probe.Count);
7020 bounds = new Dictionary<int, int> ();
7023 if (specified_dims) {
7024 Expression a = arguments [idx];
7029 a = ConvertExpressionToArrayIndex (ec, a);
7035 if (initializers != null) {
7036 Constant c = a as Constant;
7037 if (c == null && a is ArrayIndexCast)
7038 c = ((ArrayIndexCast) a).Child as Constant;
7041 ec.Report.Error (150, a.Location, "A constant value is expected");
7047 value = System.Convert.ToInt32 (c.GetValue ());
7049 ec.Report.Error (150, a.Location, "A constant value is expected");
7053 // TODO: probe.Count does not fit ulong in
7054 if (value != probe.Count) {
7055 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7059 bounds[idx] = value;
7063 if (initializers == null)
7066 for (int i = 0; i < probe.Count; ++i) {
7068 if (o is ArrayInitializer) {
7069 var sub_probe = o as ArrayInitializer;
7070 if (idx + 1 >= dimensions){
7071 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7075 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7076 if (!bounds.ContainsKey(idx + 1))
7077 bounds[idx + 1] = sub_probe.Count;
7079 if (bounds[idx + 1] != sub_probe.Count) {
7080 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7084 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7087 } else if (child_bounds > 1) {
7088 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7090 Expression element = ResolveArrayElement (ec, o);
7091 if (element == null)
7094 // Initializers with the default values can be ignored
7095 Constant c = element as Constant;
7097 if (!c.IsDefaultInitializer (array_element_type)) {
7098 ++const_initializers_count;
7101 only_constant_initializers = false;
7104 array_data.Add (element);
7111 public override bool ContainsEmitWithAwait ()
7113 foreach (var arg in arguments) {
7114 if (arg.ContainsEmitWithAwait ())
7118 return InitializersContainAwait ();
7121 public override Expression CreateExpressionTree (ResolveContext ec)
7125 if (array_data == null) {
7126 args = new Arguments (arguments.Count + 1);
7127 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7128 foreach (Expression a in arguments)
7129 args.Add (new Argument (a.CreateExpressionTree (ec)));
7131 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7134 if (dimensions > 1) {
7135 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7139 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7140 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7141 if (array_data != null) {
7142 for (int i = 0; i < array_data.Count; ++i) {
7143 Expression e = array_data [i];
7144 args.Add (new Argument (e.CreateExpressionTree (ec)));
7148 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7151 void UpdateIndices (ResolveContext rc)
7154 for (var probe = initializers; probe != null;) {
7155 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7157 bounds[i++] = probe.Count;
7159 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7160 probe = (ArrayInitializer) probe[0];
7161 } else if (dimensions > i) {
7169 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7171 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
7174 public override void FlowAnalysis (FlowAnalysisContext fc)
7176 foreach (var arg in arguments)
7177 arg.FlowAnalysis (fc);
7179 if (array_data != null) {
7180 foreach (var ad in array_data)
7181 ad.FlowAnalysis (fc);
7185 bool InitializersContainAwait ()
7187 if (array_data == null)
7190 foreach (var expr in array_data) {
7191 if (expr.ContainsEmitWithAwait ())
7198 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
7200 element = element.Resolve (ec);
7201 if (element == null)
7204 if (element is CompoundAssign.TargetExpression) {
7205 if (first_emit != null)
7206 throw new InternalErrorException ("Can only handle one mutator at a time");
7207 first_emit = element;
7208 element = first_emit_temp = new LocalTemporary (element.Type);
7211 return Convert.ImplicitConversionRequired (
7212 ec, element, array_element_type, loc);
7215 protected bool ResolveInitializers (ResolveContext ec)
7218 only_constant_initializers = true;
7221 if (arguments != null) {
7223 for (int i = 0; i < arguments.Count; ++i) {
7224 res &= CheckIndices (ec, initializers, i, true, dimensions);
7225 if (initializers != null)
7232 arguments = new List<Expression> ();
7234 if (!CheckIndices (ec, initializers, 0, false, dimensions))
7243 // Resolved the type of the array
7245 bool ResolveArrayType (ResolveContext ec)
7250 FullNamedExpression array_type_expr;
7251 if (num_arguments > 0) {
7252 array_type_expr = new ComposedCast (requested_base_type, rank);
7254 array_type_expr = requested_base_type;
7257 type = array_type_expr.ResolveAsType (ec);
7258 if (array_type_expr == null)
7261 var ac = type as ArrayContainer;
7263 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
7267 array_element_type = ac.Element;
7268 dimensions = ac.Rank;
7273 protected override Expression DoResolve (ResolveContext ec)
7278 if (!ResolveArrayType (ec))
7282 // validate the initializers and fill in any missing bits
7284 if (!ResolveInitializers (ec))
7287 eclass = ExprClass.Value;
7291 byte [] MakeByteBlob ()
7296 int count = array_data.Count;
7298 TypeSpec element_type = array_element_type;
7299 if (element_type.IsEnum)
7300 element_type = EnumSpec.GetUnderlyingType (element_type);
7302 factor = BuiltinTypeSpec.GetSize (element_type);
7304 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
7306 data = new byte [(count * factor + 3) & ~3];
7309 for (int i = 0; i < count; ++i) {
7310 var c = array_data[i] as Constant;
7316 object v = c.GetValue ();
7318 switch (element_type.BuiltinType) {
7319 case BuiltinTypeSpec.Type.Long:
7320 long lval = (long) v;
7322 for (int j = 0; j < factor; ++j) {
7323 data[idx + j] = (byte) (lval & 0xFF);
7327 case BuiltinTypeSpec.Type.ULong:
7328 ulong ulval = (ulong) v;
7330 for (int j = 0; j < factor; ++j) {
7331 data[idx + j] = (byte) (ulval & 0xFF);
7332 ulval = (ulval >> 8);
7335 case BuiltinTypeSpec.Type.Float:
7336 var fval = SingleConverter.SingleToInt32Bits((float) v);
7338 data[idx] = (byte) (fval & 0xff);
7339 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
7340 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
7341 data[idx + 3] = (byte) (fval >> 24);
7343 case BuiltinTypeSpec.Type.Double:
7344 element = BitConverter.GetBytes ((double) v);
7346 for (int j = 0; j < factor; ++j)
7347 data[idx + j] = element[j];
7349 // FIXME: Handle the ARM float format.
7350 if (!BitConverter.IsLittleEndian)
7351 System.Array.Reverse (data, idx, 8);
7353 case BuiltinTypeSpec.Type.Char:
7354 int chval = (int) ((char) v);
7356 data[idx] = (byte) (chval & 0xff);
7357 data[idx + 1] = (byte) (chval >> 8);
7359 case BuiltinTypeSpec.Type.Short:
7360 int sval = (int) ((short) v);
7362 data[idx] = (byte) (sval & 0xff);
7363 data[idx + 1] = (byte) (sval >> 8);
7365 case BuiltinTypeSpec.Type.UShort:
7366 int usval = (int) ((ushort) v);
7368 data[idx] = (byte) (usval & 0xff);
7369 data[idx + 1] = (byte) (usval >> 8);
7371 case BuiltinTypeSpec.Type.Int:
7374 data[idx] = (byte) (val & 0xff);
7375 data[idx + 1] = (byte) ((val >> 8) & 0xff);
7376 data[idx + 2] = (byte) ((val >> 16) & 0xff);
7377 data[idx + 3] = (byte) (val >> 24);
7379 case BuiltinTypeSpec.Type.UInt:
7380 uint uval = (uint) v;
7382 data[idx] = (byte) (uval & 0xff);
7383 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
7384 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
7385 data[idx + 3] = (byte) (uval >> 24);
7387 case BuiltinTypeSpec.Type.SByte:
7388 data[idx] = (byte) (sbyte) v;
7390 case BuiltinTypeSpec.Type.Byte:
7391 data[idx] = (byte) v;
7393 case BuiltinTypeSpec.Type.Bool:
7394 data[idx] = (byte) ((bool) v ? 1 : 0);
7396 case BuiltinTypeSpec.Type.Decimal:
7397 int[] bits = Decimal.GetBits ((decimal) v);
7400 // FIXME: For some reason, this doesn't work on the MS runtime.
7401 int[] nbits = new int[4];
7407 for (int j = 0; j < 4; j++) {
7408 data[p++] = (byte) (nbits[j] & 0xff);
7409 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
7410 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
7411 data[p++] = (byte) (nbits[j] >> 24);
7415 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
7424 #if NET_4_0 || MONODROID
7425 public override SLE.Expression MakeExpression (BuilderContext ctx)
7428 return base.MakeExpression (ctx);
7430 var initializers = new SLE.Expression [array_data.Count];
7431 for (var i = 0; i < initializers.Length; i++) {
7432 if (array_data [i] == null)
7433 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
7435 initializers [i] = array_data [i].MakeExpression (ctx);
7438 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
7444 // Emits the initializers for the array
7446 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
7448 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
7453 // First, the static data
7455 byte [] data = MakeByteBlob ();
7456 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
7458 if (stackArray == null) {
7459 ec.Emit (OpCodes.Dup);
7461 stackArray.Emit (ec);
7464 ec.Emit (OpCodes.Ldtoken, fb);
7465 ec.Emit (OpCodes.Call, m);
7470 // Emits pieces of the array that can not be computed at compile
7471 // time (variables and string locations).
7473 // This always expect the top value on the stack to be the array
7475 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
7477 int dims = bounds.Count;
7478 var current_pos = new int [dims];
7480 for (int i = 0; i < array_data.Count; i++){
7482 Expression e = array_data [i];
7483 var c = e as Constant;
7485 // Constant can be initialized via StaticInitializer
7486 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
7490 if (stackArray != null) {
7491 if (e.ContainsEmitWithAwait ()) {
7492 e = e.EmitToField (ec);
7495 stackArray.Emit (ec);
7497 ec.Emit (OpCodes.Dup);
7500 for (int idx = 0; idx < dims; idx++)
7501 ec.EmitInt (current_pos [idx]);
7504 // If we are dealing with a struct, get the
7505 // address of it, so we can store it.
7507 if (dims == 1 && etype.IsStruct) {
7508 switch (etype.BuiltinType) {
7509 case BuiltinTypeSpec.Type.Byte:
7510 case BuiltinTypeSpec.Type.SByte:
7511 case BuiltinTypeSpec.Type.Bool:
7512 case BuiltinTypeSpec.Type.Short:
7513 case BuiltinTypeSpec.Type.UShort:
7514 case BuiltinTypeSpec.Type.Char:
7515 case BuiltinTypeSpec.Type.Int:
7516 case BuiltinTypeSpec.Type.UInt:
7517 case BuiltinTypeSpec.Type.Long:
7518 case BuiltinTypeSpec.Type.ULong:
7519 case BuiltinTypeSpec.Type.Float:
7520 case BuiltinTypeSpec.Type.Double:
7523 ec.Emit (OpCodes.Ldelema, etype);
7530 ec.EmitArrayStore ((ArrayContainer) type);
7536 for (int j = dims - 1; j >= 0; j--){
7538 if (current_pos [j] < bounds [j])
7540 current_pos [j] = 0;
7545 public override void Emit (EmitContext ec)
7547 EmitToFieldSource (ec);
7550 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
7552 if (first_emit != null) {
7553 first_emit.Emit (ec);
7554 first_emit_temp.Store (ec);
7557 FieldExpr await_stack_field;
7558 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
7559 await_stack_field = ec.GetTemporaryField (type);
7562 await_stack_field = null;
7565 EmitExpressionsList (ec, arguments);
7567 ec.EmitArrayNew ((ArrayContainer) type);
7569 if (initializers == null)
7570 return await_stack_field;
7572 if (await_stack_field != null)
7573 await_stack_field.EmitAssignFromStack (ec);
7577 // Emit static initializer for arrays which contain more than 2 items and
7578 // the static initializer will initialize at least 25% of array values or there
7579 // is more than 10 items to be initialized
7581 // NOTE: const_initializers_count does not contain default constant values.
7583 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
7584 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
7585 EmitStaticInitializers (ec, await_stack_field);
7587 if (!only_constant_initializers)
7588 EmitDynamicInitializers (ec, false, await_stack_field);
7592 EmitDynamicInitializers (ec, true, await_stack_field);
7595 if (first_emit_temp != null)
7596 first_emit_temp.Release (ec);
7598 return await_stack_field;
7601 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7603 // no multi dimensional or jagged arrays
7604 if (arguments.Count != 1 || array_element_type.IsArray) {
7605 base.EncodeAttributeValue (rc, enc, targetType);
7609 // No array covariance, except for array -> object
7610 if (type != targetType) {
7611 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
7612 base.EncodeAttributeValue (rc, enc, targetType);
7616 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
7617 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7622 // Single dimensional array of 0 size
7623 if (array_data == null) {
7624 IntConstant ic = arguments[0] as IntConstant;
7625 if (ic == null || !ic.IsDefaultValue) {
7626 base.EncodeAttributeValue (rc, enc, targetType);
7634 enc.Encode (array_data.Count);
7635 foreach (var element in array_data) {
7636 element.EncodeAttributeValue (rc, enc, array_element_type);
7640 protected override void CloneTo (CloneContext clonectx, Expression t)
7642 ArrayCreation target = (ArrayCreation) t;
7644 if (requested_base_type != null)
7645 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
7647 if (arguments != null){
7648 target.arguments = new List<Expression> (arguments.Count);
7649 foreach (Expression e in arguments)
7650 target.arguments.Add (e.Clone (clonectx));
7653 if (initializers != null)
7654 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
7657 public override object Accept (StructuralVisitor visitor)
7659 return visitor.Visit (this);
7664 // Represents an implicitly typed array epxression
7666 class ImplicitlyTypedArrayCreation : ArrayCreation
7668 TypeInferenceContext best_type_inference;
7670 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7671 : base (null, rank, initializers, loc)
7675 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
7676 : base (null, initializers, loc)
7680 protected override Expression DoResolve (ResolveContext ec)
7685 dimensions = rank.Dimension;
7687 best_type_inference = new TypeInferenceContext ();
7689 if (!ResolveInitializers (ec))
7692 best_type_inference.FixAllTypes (ec);
7693 array_element_type = best_type_inference.InferredTypeArguments[0];
7694 best_type_inference = null;
7696 if (array_element_type == null ||
7697 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
7698 arguments.Count != rank.Dimension) {
7699 ec.Report.Error (826, loc,
7700 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
7705 // At this point we found common base type for all initializer elements
7706 // but we have to be sure that all static initializer elements are of
7709 UnifyInitializerElement (ec);
7711 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
7712 eclass = ExprClass.Value;
7717 // Converts static initializer only
7719 void UnifyInitializerElement (ResolveContext ec)
7721 for (int i = 0; i < array_data.Count; ++i) {
7722 Expression e = array_data[i];
7724 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
7728 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
7730 element = element.Resolve (ec);
7731 if (element != null)
7732 best_type_inference.AddCommonTypeBound (element.Type);
7738 sealed class CompilerGeneratedThis : This
7740 public CompilerGeneratedThis (TypeSpec type, Location loc)
7744 eclass = ExprClass.Variable;
7747 protected override Expression DoResolve (ResolveContext ec)
7752 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7759 /// Represents the `this' construct
7762 public class This : VariableReference
7764 sealed class ThisVariable : ILocalVariable
7766 public static readonly ILocalVariable Instance = new ThisVariable ();
7768 public void Emit (EmitContext ec)
7773 public void EmitAssign (EmitContext ec)
7775 throw new InvalidOperationException ();
7778 public void EmitAddressOf (EmitContext ec)
7784 VariableInfo variable_info;
7786 public This (Location loc)
7793 public override string Name {
7794 get { return "this"; }
7797 public override bool IsLockedByStatement {
7805 public override bool IsRef {
7806 get { return type.IsStruct; }
7809 public override bool IsSideEffectFree {
7815 protected override ILocalVariable Variable {
7816 get { return ThisVariable.Instance; }
7819 public override VariableInfo VariableInfo {
7820 get { return variable_info; }
7823 public override bool IsFixed {
7824 get { return false; }
7829 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
7832 // It's null for all cases when we don't need to check `this'
7833 // definitive assignment
7835 if (variable_info == null)
7838 if (fc.IsDefinitelyAssigned (variable_info))
7841 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
7844 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7846 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7847 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7848 } else if (ec.CurrentAnonymousMethod != null) {
7849 ec.Report.Error (1673, loc,
7850 "Anonymous methods inside structs cannot access instance members of `this'. " +
7851 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7853 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7857 public override void FlowAnalysis (FlowAnalysisContext fc)
7859 CheckStructThisDefiniteAssignment (fc);
7862 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7867 AnonymousMethodStorey storey = ae.Storey;
7868 return storey != null ? storey.HoistedThis : null;
7871 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7873 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7876 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7879 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7885 public virtual void ResolveBase (ResolveContext ec)
7887 eclass = ExprClass.Variable;
7888 type = ec.CurrentType;
7890 if (!IsThisAvailable (ec, false)) {
7891 Error_ThisNotAvailable (ec);
7895 var block = ec.CurrentBlock;
7896 if (block != null) {
7897 var top = block.ParametersBlock.TopBlock;
7898 if (top.ThisVariable != null)
7899 variable_info = top.ThisVariable.VariableInfo;
7901 AnonymousExpression am = ec.CurrentAnonymousMethod;
7902 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7904 // Hoisted this is almost like hoisted variable but not exactly. When
7905 // there is no variable hoisted we can simply emit an instance method
7906 // without lifting this into a storey. Unfotunatelly this complicates
7907 // things in other cases because we don't know where this will be hoisted
7908 // until top-level block is fully resolved
7910 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7911 am.SetHasThisAccess ();
7916 protected override Expression DoResolve (ResolveContext ec)
7922 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7924 if (eclass == ExprClass.Unresolved)
7928 if (right_side == EmptyExpression.UnaryAddress)
7929 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7930 else if (right_side == EmptyExpression.OutAccess)
7931 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7933 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7939 public override int GetHashCode()
7941 throw new NotImplementedException ();
7944 public override bool Equals (object obj)
7946 This t = obj as This;
7953 protected override void CloneTo (CloneContext clonectx, Expression t)
7958 public override void SetHasAddressTaken ()
7963 public override object Accept (StructuralVisitor visitor)
7965 return visitor.Visit (this);
7970 /// Represents the `__arglist' construct
7972 public class ArglistAccess : Expression
7974 public ArglistAccess (Location loc)
7979 protected override void CloneTo (CloneContext clonectx, Expression target)
7984 public override bool ContainsEmitWithAwait ()
7989 public override Expression CreateExpressionTree (ResolveContext ec)
7991 throw new NotSupportedException ("ET");
7994 protected override Expression DoResolve (ResolveContext ec)
7996 eclass = ExprClass.Variable;
7997 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
7999 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8000 ec.Report.Error (190, loc,
8001 "The __arglist construct is valid only within a variable argument method");
8007 public override void Emit (EmitContext ec)
8009 ec.Emit (OpCodes.Arglist);
8012 public override object Accept (StructuralVisitor visitor)
8014 return visitor.Visit (this);
8019 /// Represents the `__arglist (....)' construct
8021 public class Arglist : Expression
8023 Arguments arguments;
8025 public Arglist (Location loc)
8030 public Arglist (Arguments args, Location l)
8036 public Arguments Arguments {
8042 public MetaType[] ArgumentTypes {
8044 if (arguments == null)
8045 return MetaType.EmptyTypes;
8047 var retval = new MetaType[arguments.Count];
8048 for (int i = 0; i < retval.Length; i++)
8049 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8055 public override bool ContainsEmitWithAwait ()
8057 throw new NotImplementedException ();
8060 public override Expression CreateExpressionTree (ResolveContext ec)
8062 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8066 protected override Expression DoResolve (ResolveContext ec)
8068 eclass = ExprClass.Variable;
8069 type = InternalType.Arglist;
8070 if (arguments != null) {
8071 bool dynamic; // Can be ignored as there is always only 1 overload
8072 arguments.Resolve (ec, out dynamic);
8078 public override void Emit (EmitContext ec)
8080 if (arguments != null)
8081 arguments.Emit (ec);
8084 protected override void CloneTo (CloneContext clonectx, Expression t)
8086 Arglist target = (Arglist) t;
8088 if (arguments != null)
8089 target.arguments = arguments.Clone (clonectx);
8092 public override object Accept (StructuralVisitor visitor)
8094 return visitor.Visit (this);
8098 public class RefValueExpr : ShimExpression, IAssignMethod
8100 FullNamedExpression texpr;
8102 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8109 public FullNamedExpression TypeExpression {
8115 public override bool ContainsEmitWithAwait ()
8120 protected override Expression DoResolve (ResolveContext rc)
8122 expr = expr.Resolve (rc);
8123 type = texpr.ResolveAsType (rc);
8124 if (expr == null || type == null)
8127 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8128 eclass = ExprClass.Value;
8132 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8134 return DoResolve (rc);
8137 public override void Emit (EmitContext ec)
8140 ec.Emit (OpCodes.Refanyval, type);
8141 ec.EmitLoadFromPtr (type);
8144 public void Emit (EmitContext ec, bool leave_copy)
8146 throw new NotImplementedException ();
8149 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8152 ec.Emit (OpCodes.Refanyval, type);
8155 LocalTemporary temporary = null;
8157 ec.Emit (OpCodes.Dup);
8158 temporary = new LocalTemporary (source.Type);
8159 temporary.Store (ec);
8162 ec.EmitStoreFromPtr (type);
8164 if (temporary != null) {
8165 temporary.Emit (ec);
8166 temporary.Release (ec);
8170 public override object Accept (StructuralVisitor visitor)
8172 return visitor.Visit (this);
8176 public class RefTypeExpr : ShimExpression
8178 public RefTypeExpr (Expression expr, Location loc)
8184 protected override Expression DoResolve (ResolveContext rc)
8186 expr = expr.Resolve (rc);
8190 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8194 type = rc.BuiltinTypes.Type;
8195 eclass = ExprClass.Value;
8199 public override void Emit (EmitContext ec)
8202 ec.Emit (OpCodes.Refanytype);
8203 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8205 ec.Emit (OpCodes.Call, m);
8208 public override object Accept (StructuralVisitor visitor)
8210 return visitor.Visit (this);
8214 public class MakeRefExpr : ShimExpression
8216 public MakeRefExpr (Expression expr, Location loc)
8222 public override bool ContainsEmitWithAwait ()
8224 throw new NotImplementedException ();
8227 protected override Expression DoResolve (ResolveContext rc)
8229 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8230 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8231 eclass = ExprClass.Value;
8235 public override void Emit (EmitContext ec)
8237 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8238 ec.Emit (OpCodes.Mkrefany, expr.Type);
8241 public override object Accept (StructuralVisitor visitor)
8243 return visitor.Visit (this);
8248 /// Implements the typeof operator
8250 public class TypeOf : Expression {
8251 FullNamedExpression QueriedType;
8254 public TypeOf (FullNamedExpression queried_type, Location l)
8256 QueriedType = queried_type;
8261 // Use this constructor for any compiler generated typeof expression
8263 public TypeOf (TypeSpec type, Location loc)
8265 this.typearg = type;
8271 public override bool IsSideEffectFree {
8277 public TypeSpec TypeArgument {
8283 public FullNamedExpression TypeExpression {
8292 protected override void CloneTo (CloneContext clonectx, Expression t)
8294 TypeOf target = (TypeOf) t;
8295 if (QueriedType != null)
8296 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
8299 public override bool ContainsEmitWithAwait ()
8304 public override Expression CreateExpressionTree (ResolveContext ec)
8306 Arguments args = new Arguments (2);
8307 args.Add (new Argument (this));
8308 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8309 return CreateExpressionFactoryCall (ec, "Constant", args);
8312 protected override Expression DoResolve (ResolveContext ec)
8314 if (eclass != ExprClass.Unresolved)
8317 if (typearg == null) {
8319 // Pointer types are allowed without explicit unsafe, they are just tokens
8321 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
8322 typearg = QueriedType.ResolveAsType (ec);
8325 if (typearg == null)
8328 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8329 ec.Report.Error (1962, QueriedType.Location,
8330 "The typeof operator cannot be used on the dynamic type");
8334 type = ec.BuiltinTypes.Type;
8336 // Even though what is returned is a type object, it's treated as a value by the compiler.
8337 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
8338 eclass = ExprClass.Value;
8342 static bool ContainsDynamicType (TypeSpec type)
8344 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
8347 var element_container = type as ElementTypeSpec;
8348 if (element_container != null)
8349 return ContainsDynamicType (element_container.Element);
8351 foreach (var t in type.TypeArguments) {
8352 if (ContainsDynamicType (t)) {
8360 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
8362 // Target type is not System.Type therefore must be object
8363 // and we need to use different encoding sequence
8364 if (targetType != type)
8367 if (typearg is InflatedTypeSpec) {
8370 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
8371 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
8372 typearg.GetSignatureForError ());
8376 gt = gt.DeclaringType;
8377 } while (gt != null);
8380 if (ContainsDynamicType (typearg)) {
8381 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8385 enc.EncodeTypeName (typearg);
8388 public override void Emit (EmitContext ec)
8390 ec.Emit (OpCodes.Ldtoken, typearg);
8391 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8393 ec.Emit (OpCodes.Call, m);
8396 public override object Accept (StructuralVisitor visitor)
8398 return visitor.Visit (this);
8402 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
8404 public TypeOfMethod (MethodSpec method, Location loc)
8405 : base (method, loc)
8409 protected override Expression DoResolve (ResolveContext ec)
8411 if (member.IsConstructor) {
8412 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
8414 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
8420 return base.DoResolve (ec);
8423 public override void Emit (EmitContext ec)
8425 ec.Emit (OpCodes.Ldtoken, member);
8428 ec.Emit (OpCodes.Castclass, type);
8431 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8433 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
8436 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8438 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
8442 abstract class TypeOfMember<T> : Expression where T : MemberSpec
8444 protected readonly T member;
8446 protected TypeOfMember (T member, Location loc)
8448 this.member = member;
8452 public override bool IsSideEffectFree {
8458 public override bool ContainsEmitWithAwait ()
8463 public override Expression CreateExpressionTree (ResolveContext ec)
8465 Arguments args = new Arguments (2);
8466 args.Add (new Argument (this));
8467 args.Add (new Argument (new TypeOf (type, loc)));
8468 return CreateExpressionFactoryCall (ec, "Constant", args);
8471 protected override Expression DoResolve (ResolveContext ec)
8473 eclass = ExprClass.Value;
8477 public override void Emit (EmitContext ec)
8479 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
8480 PredefinedMember<MethodSpec> p;
8482 p = GetTypeFromHandleGeneric (ec);
8483 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
8485 p = GetTypeFromHandle (ec);
8488 var mi = p.Resolve (loc);
8490 ec.Emit (OpCodes.Call, mi);
8493 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
8494 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
8497 sealed class TypeOfField : TypeOfMember<FieldSpec>
8499 public TypeOfField (FieldSpec field, Location loc)
8504 protected override Expression DoResolve (ResolveContext ec)
8506 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
8510 return base.DoResolve (ec);
8513 public override void Emit (EmitContext ec)
8515 ec.Emit (OpCodes.Ldtoken, member);
8519 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8521 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
8524 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8526 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
8531 /// Implements the sizeof expression
8533 public class SizeOf : Expression {
8534 readonly Expression texpr;
8535 TypeSpec type_queried;
8537 public SizeOf (Expression queried_type, Location l)
8539 this.texpr = queried_type;
8543 public override bool IsSideEffectFree {
8549 public Expression TypeExpression {
8555 public override bool ContainsEmitWithAwait ()
8560 public override Expression CreateExpressionTree (ResolveContext ec)
8562 Error_PointerInsideExpressionTree (ec);
8566 protected override Expression DoResolve (ResolveContext ec)
8568 type_queried = texpr.ResolveAsType (ec);
8569 if (type_queried == null)
8572 if (type_queried.IsEnum)
8573 type_queried = EnumSpec.GetUnderlyingType (type_queried);
8575 int size_of = BuiltinTypeSpec.GetSize (type_queried);
8577 return new IntConstant (ec.BuiltinTypes, size_of, loc);
8580 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
8585 ec.Report.Error (233, loc,
8586 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
8587 type_queried.GetSignatureForError ());
8590 type = ec.BuiltinTypes.Int;
8591 eclass = ExprClass.Value;
8595 public override void Emit (EmitContext ec)
8597 ec.Emit (OpCodes.Sizeof, type_queried);
8600 protected override void CloneTo (CloneContext clonectx, Expression t)
8604 public override object Accept (StructuralVisitor visitor)
8606 return visitor.Visit (this);
8611 /// Implements the qualified-alias-member (::) expression.
8613 public class QualifiedAliasMember : MemberAccess
8615 readonly string alias;
8616 public static readonly string GlobalAlias = "global";
8618 public QualifiedAliasMember (string alias, string identifier, Location l)
8619 : base (null, identifier, l)
8624 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
8625 : base (null, identifier, targs, l)
8630 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
8631 : base (null, identifier, arity, l)
8636 public string Alias {
8642 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
8644 if (alias == GlobalAlias) {
8645 expr = ec.Module.GlobalRootNamespace;
8646 return base.ResolveAsTypeOrNamespace (ec);
8649 int errors = ec.Module.Compiler.Report.Errors;
8650 expr = ec.LookupNamespaceAlias (alias);
8652 if (errors == ec.Module.Compiler.Report.Errors)
8653 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
8657 return base.ResolveAsTypeOrNamespace (ec);
8660 protected override Expression DoResolve (ResolveContext ec)
8662 return ResolveAsTypeOrNamespace (ec);
8665 public override string GetSignatureForError ()
8668 if (targs != null) {
8669 name = Name + "<" + targs.GetSignatureForError () + ">";
8672 return alias + "::" + name;
8675 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8677 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
8678 rc.Module.Compiler.Report.Error (687, loc,
8679 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
8680 GetSignatureForError ());
8685 return DoResolve (rc);
8688 protected override void CloneTo (CloneContext clonectx, Expression t)
8693 public override object Accept (StructuralVisitor visitor)
8695 return visitor.Visit (this);
8700 /// Implements the member access expression
8702 public class MemberAccess : ATypeNameExpression
8704 protected Expression expr;
8706 public MemberAccess (Expression expr, string id)
8707 : base (id, expr.Location)
8712 public MemberAccess (Expression expr, string identifier, Location loc)
8713 : base (identifier, loc)
8718 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
8719 : base (identifier, args, loc)
8724 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
8725 : base (identifier, arity, loc)
8730 public Expression LeftExpression {
8736 public override Location StartLocation {
8738 return expr == null ? loc : expr.StartLocation;
8742 protected override Expression DoResolve (ResolveContext rc)
8744 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
8746 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
8751 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
8753 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
8755 if (e is TypeExpr) {
8756 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8761 e = e.ResolveLValue (rc, rhs);
8766 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8768 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8769 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8771 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8774 public static bool IsValidDotExpression (TypeSpec type)
8776 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8777 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8779 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8782 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8784 var sn = expr as SimpleName;
8785 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8788 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8791 // Resolve expression which does have type set as we need expression type
8792 // with disable flow analysis as we don't know whether left side expression
8793 // is used as variable or type
8795 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8796 expr = expr.Resolve (rc);
8797 } else if (expr is TypeParameterExpr) {
8798 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8802 expr = expr.Resolve (rc, flags);
8808 Namespace ns = expr as Namespace;
8810 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8812 if (retval == null) {
8813 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8817 if (HasTypeArguments)
8818 return new GenericTypeExpr (retval.Type, targs, loc);
8824 TypeSpec expr_type = expr.Type;
8825 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8826 me = expr as MemberExpr;
8828 me.ResolveInstanceExpression (rc, null);
8830 Arguments args = new Arguments (1);
8831 args.Add (new Argument (expr));
8832 return new DynamicMemberBinder (Name, args, loc);
8835 if (!IsValidDotExpression (expr_type)) {
8836 Error_OperatorCannotBeApplied (rc, expr_type);
8840 var lookup_arity = Arity;
8841 bool errorMode = false;
8842 Expression member_lookup;
8844 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8845 if (member_lookup == null) {
8847 // Try to look for extension method when member lookup failed
8849 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8850 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8851 if (methods != null) {
8852 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8853 if (HasTypeArguments) {
8854 if (!targs.Resolve (rc))
8857 emg.SetTypeArguments (rc, targs);
8860 // TODO: it should really skip the checks bellow
8861 return emg.Resolve (rc);
8867 if (member_lookup == null) {
8868 var dep = expr_type.GetMissingDependencies ();
8870 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8871 } else if (expr is TypeExpr) {
8872 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8874 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8880 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8881 // Leave it to overload resolution to report correct error
8882 } else if (!(member_lookup is TypeExpr)) {
8883 // TODO: rc.SymbolRelatedToPreviousError
8884 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8889 if (member_lookup != null)
8893 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8897 TypeExpr texpr = member_lookup as TypeExpr;
8898 if (texpr != null) {
8899 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8900 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8901 Name, texpr.GetSignatureForError ());
8904 if (!texpr.Type.IsAccessible (rc)) {
8905 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8906 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8910 if (HasTypeArguments) {
8911 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8914 return member_lookup;
8917 me = member_lookup as MemberExpr;
8919 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8923 me = me.ResolveMemberAccess (rc, expr, sn);
8926 if (!targs.Resolve (rc))
8929 me.SetTypeArguments (rc, targs);
8935 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8937 FullNamedExpression fexpr = expr as FullNamedExpression;
8938 if (fexpr == null) {
8939 expr.ResolveAsType (rc);
8943 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8945 if (expr_resolved == null)
8948 Namespace ns = expr_resolved as Namespace;
8950 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8952 if (retval == null) {
8953 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8954 } else if (HasTypeArguments) {
8955 retval = new GenericTypeExpr (retval.Type, targs, loc);
8956 if (retval.ResolveAsType (rc) == null)
8963 var tnew_expr = expr_resolved.ResolveAsType (rc);
8964 if (tnew_expr == null)
8967 TypeSpec expr_type = tnew_expr;
8968 if (TypeManager.IsGenericParameter (expr_type)) {
8969 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8970 tnew_expr.GetSignatureForError ());
8974 var qam = this as QualifiedAliasMember;
8976 rc.Module.Compiler.Report.Error (431, loc,
8977 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8982 TypeSpec nested = null;
8983 while (expr_type != null) {
8984 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8985 if (nested == null) {
8986 if (expr_type == tnew_expr) {
8987 Error_IdentifierNotFound (rc, expr_type, Name);
8991 expr_type = tnew_expr;
8992 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8993 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
8997 if (nested.IsAccessible (rc))
9001 // Keep looking after inaccessible candidate but only if
9002 // we are not in same context as the definition itself
9004 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9007 expr_type = expr_type.BaseType;
9012 if (HasTypeArguments) {
9013 texpr = new GenericTypeExpr (nested, targs, loc);
9015 texpr = new GenericOpenTypeExpr (nested, loc);
9018 texpr = new TypeExpression (nested, loc);
9021 if (texpr.ResolveAsType (rc) == null)
9027 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
9029 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9031 if (nested != null) {
9032 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9036 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9037 if (any_other_member != null) {
9038 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9042 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9043 Name, expr_type.GetSignatureForError ());
9046 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9048 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9051 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9053 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9054 ec.Report.SymbolRelatedToPreviousError (type);
9056 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9058 // a using directive or an assembly reference
9060 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9062 missing = "an assembly reference";
9065 ec.Report.Error (1061, loc,
9066 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9067 type.GetSignatureForError (), name, missing);
9071 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9074 public override string GetSignatureForError ()
9076 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9079 protected override void CloneTo (CloneContext clonectx, Expression t)
9081 MemberAccess target = (MemberAccess) t;
9083 target.expr = expr.Clone (clonectx);
9086 public override object Accept (StructuralVisitor visitor)
9088 return visitor.Visit (this);
9093 /// Implements checked expressions
9095 public class CheckedExpr : Expression {
9097 public Expression Expr;
9099 public CheckedExpr (Expression e, Location l)
9105 public override bool ContainsEmitWithAwait ()
9107 return Expr.ContainsEmitWithAwait ();
9110 public override Expression CreateExpressionTree (ResolveContext ec)
9112 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9113 return Expr.CreateExpressionTree (ec);
9116 protected override Expression DoResolve (ResolveContext ec)
9118 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9119 Expr = Expr.Resolve (ec);
9124 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9127 eclass = Expr.eclass;
9132 public override void Emit (EmitContext ec)
9134 using (ec.With (EmitContext.Options.CheckedScope, true))
9138 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9140 using (ec.With (EmitContext.Options.CheckedScope, true))
9141 Expr.EmitBranchable (ec, target, on_true);
9144 public override void FlowAnalysis (FlowAnalysisContext fc)
9146 Expr.FlowAnalysis (fc);
9149 public override SLE.Expression MakeExpression (BuilderContext ctx)
9151 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9152 return Expr.MakeExpression (ctx);
9156 protected override void CloneTo (CloneContext clonectx, Expression t)
9158 CheckedExpr target = (CheckedExpr) t;
9160 target.Expr = Expr.Clone (clonectx);
9163 public override object Accept (StructuralVisitor visitor)
9165 return visitor.Visit (this);
9170 /// Implements the unchecked expression
9172 public class UnCheckedExpr : Expression {
9174 public Expression Expr;
9176 public UnCheckedExpr (Expression e, Location l)
9182 public override bool ContainsEmitWithAwait ()
9184 return Expr.ContainsEmitWithAwait ();
9187 public override Expression CreateExpressionTree (ResolveContext ec)
9189 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9190 return Expr.CreateExpressionTree (ec);
9193 protected override Expression DoResolve (ResolveContext ec)
9195 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9196 Expr = Expr.Resolve (ec);
9201 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9204 eclass = Expr.eclass;
9209 public override void Emit (EmitContext ec)
9211 using (ec.With (EmitContext.Options.CheckedScope, false))
9215 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9217 using (ec.With (EmitContext.Options.CheckedScope, false))
9218 Expr.EmitBranchable (ec, target, on_true);
9221 public override void FlowAnalysis (FlowAnalysisContext fc)
9223 Expr.FlowAnalysis (fc);
9226 protected override void CloneTo (CloneContext clonectx, Expression t)
9228 UnCheckedExpr target = (UnCheckedExpr) t;
9230 target.Expr = Expr.Clone (clonectx);
9233 public override object Accept (StructuralVisitor visitor)
9235 return visitor.Visit (this);
9240 /// An Element Access expression.
9242 /// During semantic analysis these are transformed into
9243 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
9245 public class ElementAccess : Expression
9247 public Arguments Arguments;
9248 public Expression Expr;
9250 public ElementAccess (Expression e, Arguments args, Location loc)
9254 this.Arguments = args;
9257 public override Location StartLocation {
9259 return Expr.StartLocation;
9263 public override bool ContainsEmitWithAwait ()
9265 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
9269 // We perform some simple tests, and then to "split" the emit and store
9270 // code we create an instance of a different class, and return that.
9272 Expression CreateAccessExpression (ResolveContext ec)
9275 return (new ArrayAccess (this, loc));
9278 return MakePointerAccess (ec, type);
9280 FieldExpr fe = Expr as FieldExpr;
9282 var ff = fe.Spec as FixedFieldSpec;
9284 return MakePointerAccess (ec, ff.ElementType);
9288 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
9289 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9290 return new IndexerExpr (indexers, type, this);
9293 if (type != InternalType.ErrorType) {
9294 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
9295 type.GetSignatureForError ());
9301 public override Expression CreateExpressionTree (ResolveContext ec)
9303 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
9304 Expr.CreateExpressionTree (ec));
9306 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
9309 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
9311 if (Arguments.Count != 1){
9312 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
9316 if (Arguments [0] is NamedArgument)
9317 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
9319 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
9320 return new Indirection (p, loc);
9323 protected override Expression DoResolve (ResolveContext ec)
9325 Expr = Expr.Resolve (ec);
9331 // TODO: Create 1 result for Resolve and ResolveLValue ?
9332 var res = CreateAccessExpression (ec);
9336 return res.Resolve (ec);
9339 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
9341 Expr = Expr.Resolve (ec);
9347 var res = CreateAccessExpression (ec);
9351 return res.ResolveLValue (ec, rhs);
9354 public override void Emit (EmitContext ec)
9356 throw new Exception ("Should never be reached");
9359 public static void Error_NamedArgument (NamedArgument na, Report Report)
9361 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
9364 public override void FlowAnalysis (FlowAnalysisContext fc)
9366 Expr.FlowAnalysis (fc);
9367 Arguments.FlowAnalysis (fc);
9370 public override string GetSignatureForError ()
9372 return Expr.GetSignatureForError ();
9375 protected override void CloneTo (CloneContext clonectx, Expression t)
9377 ElementAccess target = (ElementAccess) t;
9379 target.Expr = Expr.Clone (clonectx);
9380 if (Arguments != null)
9381 target.Arguments = Arguments.Clone (clonectx);
9384 public override object Accept (StructuralVisitor visitor)
9386 return visitor.Visit (this);
9391 /// Implements array access
9393 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
9395 // Points to our "data" repository
9399 LocalTemporary temp;
9401 bool? has_await_args;
9403 public ArrayAccess (ElementAccess ea_data, Location l)
9409 public void AddressOf (EmitContext ec, AddressOp mode)
9411 var ac = (ArrayContainer) ea.Expr.Type;
9413 LoadInstanceAndArguments (ec, false, false);
9415 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
9416 ec.Emit (OpCodes.Readonly);
9418 ec.EmitArrayAddress (ac);
9421 public override Expression CreateExpressionTree (ResolveContext ec)
9423 return ea.CreateExpressionTree (ec);
9426 public override bool ContainsEmitWithAwait ()
9428 return ea.ContainsEmitWithAwait ();
9431 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9433 return DoResolve (ec);
9436 protected override Expression DoResolve (ResolveContext ec)
9438 // dynamic is used per argument in ConvertExpressionToArrayIndex case
9440 ea.Arguments.Resolve (ec, out dynamic);
9442 var ac = ea.Expr.Type as ArrayContainer;
9443 int rank = ea.Arguments.Count;
9444 if (ac.Rank != rank) {
9445 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
9446 rank.ToString (), ac.Rank.ToString ());
9451 if (type.IsPointer && !ec.IsUnsafe) {
9452 UnsafeError (ec, ea.Location);
9455 foreach (Argument a in ea.Arguments) {
9456 if (a is NamedArgument)
9457 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
9459 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
9462 eclass = ExprClass.Variable;
9467 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
9469 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
9472 public override void FlowAnalysis (FlowAnalysisContext fc)
9474 ea.FlowAnalysis (fc);
9478 // Load the array arguments into the stack.
9480 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
9483 ea.Expr = ea.Expr.EmitToField (ec);
9484 } else if (duplicateArguments) {
9486 ec.Emit (OpCodes.Dup);
9488 var copy = new LocalTemporary (ea.Expr.Type);
9495 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
9496 if (dup_args != null)
9497 ea.Arguments = dup_args;
9500 public void Emit (EmitContext ec, bool leave_copy)
9502 var ac = ea.Expr.Type as ArrayContainer;
9505 ec.EmitLoadFromPtr (type);
9507 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
9508 LoadInstanceAndArguments (ec, false, true);
9511 LoadInstanceAndArguments (ec, false, false);
9512 ec.EmitArrayLoad (ac);
9516 ec.Emit (OpCodes.Dup);
9517 temp = new LocalTemporary (this.type);
9522 public override void Emit (EmitContext ec)
9527 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9529 var ac = (ArrayContainer) ea.Expr.Type;
9530 TypeSpec t = source.Type;
9532 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
9535 // When we are dealing with a struct, get the address of it to avoid value copy
9536 // Same cannot be done for reference type because array covariance and the
9537 // check in ldelema requires to specify the type of array element stored at the index
9539 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
9540 LoadInstanceAndArguments (ec, false, has_await_args.Value);
9542 if (has_await_args.Value) {
9543 if (source.ContainsEmitWithAwait ()) {
9544 source = source.EmitToField (ec);
9549 LoadInstanceAndArguments (ec, isCompound, false);
9554 ec.EmitArrayAddress (ac);
9557 ec.Emit (OpCodes.Dup);
9561 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
9563 if (has_await_args.Value) {
9564 if (source.ContainsEmitWithAwait ())
9565 source = source.EmitToField (ec);
9567 LoadInstanceAndArguments (ec, false, false);
9574 var lt = ea.Expr as LocalTemporary;
9580 ec.Emit (OpCodes.Dup);
9581 temp = new LocalTemporary (this.type);
9586 ec.EmitStoreFromPtr (t);
9588 ec.EmitArrayStore (ac);
9597 public override Expression EmitToField (EmitContext ec)
9600 // Have to be specialized for arrays to get access to
9601 // underlying element. Instead of another result copy we
9602 // need direct access to element
9606 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
9608 ea.Expr = ea.Expr.EmitToField (ec);
9612 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9614 #if NET_4_0 || MONODROID
9615 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9617 throw new NotImplementedException ();
9621 public override SLE.Expression MakeExpression (BuilderContext ctx)
9623 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9626 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
9628 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9629 return Arguments.MakeExpression (ea.Arguments, ctx);
9635 // Indexer access expression
9637 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
9639 IList<MemberSpec> indexers;
9640 Arguments arguments;
9641 TypeSpec queried_type;
9643 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
9644 : base (ea.Location)
9646 this.indexers = indexers;
9647 this.queried_type = queriedType;
9648 this.InstanceExpression = ea.Expr;
9649 this.arguments = ea.Arguments;
9654 protected override Arguments Arguments {
9663 protected override TypeSpec DeclaringType {
9665 return best_candidate.DeclaringType;
9669 public override bool IsInstance {
9675 public override bool IsStatic {
9681 public override string KindName {
9682 get { return "indexer"; }
9685 public override string Name {
9693 public override bool ContainsEmitWithAwait ()
9695 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
9698 public override Expression CreateExpressionTree (ResolveContext ec)
9700 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
9701 InstanceExpression.CreateExpressionTree (ec),
9702 new TypeOfMethod (Getter, loc));
9704 return CreateExpressionFactoryCall (ec, "Call", args);
9707 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9709 LocalTemporary await_source_arg = null;
9712 emitting_compound_assignment = true;
9713 if (source is DynamicExpressionStatement) {
9718 emitting_compound_assignment = false;
9720 if (has_await_arguments) {
9721 await_source_arg = new LocalTemporary (Type);
9722 await_source_arg.Store (ec);
9724 arguments.Add (new Argument (await_source_arg));
9727 temp = await_source_arg;
9730 has_await_arguments = false;
9735 ec.Emit (OpCodes.Dup);
9736 temp = new LocalTemporary (Type);
9742 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9743 source = source.EmitToField (ec);
9745 temp = new LocalTemporary (Type);
9752 arguments.Add (new Argument (source));
9755 var call = new CallEmitter ();
9756 call.InstanceExpression = InstanceExpression;
9757 if (arguments == null)
9758 call.InstanceExpressionOnStack = true;
9760 call.Emit (ec, Setter, arguments, loc);
9765 } else if (leave_copy) {
9769 if (await_source_arg != null) {
9770 await_source_arg.Release (ec);
9774 public override void FlowAnalysis (FlowAnalysisContext fc)
9776 // TODO: Check the order
9777 base.FlowAnalysis (fc);
9778 arguments.FlowAnalysis (fc);
9781 public override string GetSignatureForError ()
9783 return best_candidate.GetSignatureForError ();
9786 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9789 throw new NotSupportedException ();
9791 var value = new[] { source.MakeExpression (ctx) };
9792 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9793 #if NET_4_0 || MONODROID
9794 return SLE.Expression.Block (
9795 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9798 return args.First ();
9803 public override SLE.Expression MakeExpression (BuilderContext ctx)
9806 return base.MakeExpression (ctx);
9808 var args = Arguments.MakeExpression (arguments, ctx);
9809 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9813 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9815 if (best_candidate != null)
9818 eclass = ExprClass.IndexerAccess;
9821 arguments.Resolve (rc, out dynamic);
9823 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9826 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9827 res.BaseMembersProvider = this;
9828 res.InstanceQualifier = this;
9830 // TODO: Do I need 2 argument sets?
9831 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9832 if (best_candidate != null)
9833 type = res.BestCandidateReturnType;
9834 else if (!res.BestCandidateIsDynamic)
9839 // It has dynamic arguments
9842 Arguments args = new Arguments (arguments.Count + 1);
9844 rc.Report.Error (1972, loc,
9845 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9847 args.Add (new Argument (InstanceExpression));
9849 args.AddRange (arguments);
9851 best_candidate = null;
9852 return new DynamicIndexBinder (args, loc);
9856 // Try to avoid resolving left expression again
9858 if (right_side != null)
9859 ResolveInstanceExpression (rc, right_side);
9864 protected override void CloneTo (CloneContext clonectx, Expression t)
9866 IndexerExpr target = (IndexerExpr) t;
9868 if (arguments != null)
9869 target.arguments = arguments.Clone (clonectx);
9872 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9874 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9877 #region IBaseMembersProvider Members
9879 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9881 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9884 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9886 if (queried_type == member.DeclaringType)
9889 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9890 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9893 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9902 // A base access expression
9904 public class BaseThis : This
9906 public BaseThis (Location loc)
9911 public BaseThis (TypeSpec type, Location loc)
9915 eclass = ExprClass.Variable;
9920 public override string Name {
9928 public override Expression CreateExpressionTree (ResolveContext ec)
9930 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9931 return base.CreateExpressionTree (ec);
9934 public override void Emit (EmitContext ec)
9938 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
9939 var context_type = ec.CurrentType;
9940 ec.Emit (OpCodes.Ldobj, context_type);
9941 ec.Emit (OpCodes.Box, context_type);
9945 protected override void Error_ThisNotAvailable (ResolveContext ec)
9948 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9950 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9954 public override void ResolveBase (ResolveContext ec)
9956 base.ResolveBase (ec);
9957 type = ec.CurrentType.BaseType;
9960 public override object Accept (StructuralVisitor visitor)
9962 return visitor.Visit (this);
9967 /// This class exists solely to pass the Type around and to be a dummy
9968 /// that can be passed to the conversion functions (this is used by
9969 /// foreach implementation to typecast the object return value from
9970 /// get_Current into the proper type. All code has been generated and
9971 /// we only care about the side effect conversions to be performed
9973 /// This is also now used as a placeholder where a no-action expression
9974 /// is needed (the `New' class).
9976 public class EmptyExpression : Expression
9978 sealed class OutAccessExpression : EmptyExpression
9980 public OutAccessExpression (TypeSpec t)
9985 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9987 rc.Report.Error (206, right_side.Location,
9988 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
9994 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
9995 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
9996 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
9997 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
9998 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
9999 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
10000 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
10001 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
10003 public EmptyExpression (TypeSpec t)
10006 eclass = ExprClass.Value;
10007 loc = Location.Null;
10010 public override bool ContainsEmitWithAwait ()
10015 public override Expression CreateExpressionTree (ResolveContext ec)
10017 throw new NotSupportedException ("ET");
10020 protected override Expression DoResolve (ResolveContext ec)
10025 public override void Emit (EmitContext ec)
10027 // nothing, as we only exist to not do anything.
10030 public override void EmitSideEffect (EmitContext ec)
10034 public override object Accept (StructuralVisitor visitor)
10036 return visitor.Visit (this);
10040 sealed class EmptyAwaitExpression : EmptyExpression
10042 public EmptyAwaitExpression (TypeSpec type)
10047 public override bool ContainsEmitWithAwait ()
10054 // Empty statement expression
10056 public sealed class EmptyExpressionStatement : ExpressionStatement
10058 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
10060 private EmptyExpressionStatement ()
10062 loc = Location.Null;
10065 public override bool ContainsEmitWithAwait ()
10070 public override Expression CreateExpressionTree (ResolveContext ec)
10075 public override void EmitStatement (EmitContext ec)
10080 protected override Expression DoResolve (ResolveContext ec)
10082 eclass = ExprClass.Value;
10083 type = ec.BuiltinTypes.Object;
10087 public override void Emit (EmitContext ec)
10092 public override object Accept (StructuralVisitor visitor)
10094 return visitor.Visit (this);
10098 public class ErrorExpression : EmptyExpression
10100 public static readonly ErrorExpression Instance = new ErrorExpression ();
10102 private ErrorExpression ()
10103 : base (InternalType.ErrorType)
10107 public override Expression CreateExpressionTree (ResolveContext ec)
10112 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10117 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
10121 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
10125 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
10129 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
10133 public override object Accept (StructuralVisitor visitor)
10135 return visitor.Visit (this);
10139 public class UserCast : Expression {
10143 public UserCast (MethodSpec method, Expression source, Location l)
10145 if (source == null)
10146 throw new ArgumentNullException ("source");
10148 this.method = method;
10149 this.source = source;
10150 type = method.ReturnType;
10154 public Expression Source {
10160 public override bool ContainsEmitWithAwait ()
10162 return source.ContainsEmitWithAwait ();
10165 public override Expression CreateExpressionTree (ResolveContext ec)
10167 Arguments args = new Arguments (3);
10168 args.Add (new Argument (source.CreateExpressionTree (ec)));
10169 args.Add (new Argument (new TypeOf (type, loc)));
10170 args.Add (new Argument (new TypeOfMethod (method, loc)));
10171 return CreateExpressionFactoryCall (ec, "Convert", args);
10174 protected override Expression DoResolve (ResolveContext ec)
10176 ObsoleteAttribute oa = method.GetAttributeObsolete ();
10178 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
10180 eclass = ExprClass.Value;
10184 public override void Emit (EmitContext ec)
10187 ec.MarkCallEntry (loc);
10188 ec.Emit (OpCodes.Call, method);
10191 public override void FlowAnalysis (FlowAnalysisContext fc)
10193 source.FlowAnalysis (fc);
10196 public override string GetSignatureForError ()
10198 return TypeManager.CSharpSignature (method);
10201 public override SLE.Expression MakeExpression (BuilderContext ctx)
10204 return base.MakeExpression (ctx);
10206 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
10212 // Holds additional type specifiers like ?, *, []
10214 public class ComposedTypeSpecifier
10216 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
10218 public readonly int Dimension;
10219 public readonly Location Location;
10221 public ComposedTypeSpecifier (int specifier, Location loc)
10223 this.Dimension = specifier;
10224 this.Location = loc;
10228 public bool IsNullable {
10230 return Dimension == -1;
10234 public bool IsPointer {
10236 return Dimension == -2;
10240 public ComposedTypeSpecifier Next { get; set; }
10244 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
10246 return new ComposedTypeSpecifier (dimension, loc);
10249 public static ComposedTypeSpecifier CreateNullable (Location loc)
10251 return new ComposedTypeSpecifier (-1, loc);
10254 public static ComposedTypeSpecifier CreatePointer (Location loc)
10256 return new ComposedTypeSpecifier (-2, loc);
10259 public string GetSignatureForError ()
10264 ArrayContainer.GetPostfixSignature (Dimension);
10266 return Next != null ? s + Next.GetSignatureForError () : s;
10271 // This class is used to "construct" the type during a typecast
10272 // operation. Since the Type.GetType class in .NET can parse
10273 // the type specification, we just use this to construct the type
10274 // one bit at a time.
10276 public class ComposedCast : TypeExpr {
10277 FullNamedExpression left;
10278 ComposedTypeSpecifier spec;
10280 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
10283 throw new ArgumentNullException ("spec");
10287 this.loc = left.Location;
10290 public override TypeSpec ResolveAsType (IMemberContext ec)
10292 type = left.ResolveAsType (ec);
10296 eclass = ExprClass.Type;
10298 var single_spec = spec;
10300 if (single_spec.IsNullable) {
10301 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
10305 single_spec = single_spec.Next;
10306 } else if (single_spec.IsPointer) {
10307 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
10310 if (!ec.IsUnsafe) {
10311 UnsafeError (ec.Module.Compiler.Report, loc);
10315 type = PointerContainer.MakeType (ec.Module, type);
10316 single_spec = single_spec.Next;
10317 } while (single_spec != null && single_spec.IsPointer);
10320 if (single_spec != null && single_spec.Dimension > 0) {
10321 if (type.IsSpecialRuntimeType) {
10322 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
10323 } else if (type.IsStatic) {
10324 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
10325 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
10326 type.GetSignatureForError ());
10328 MakeArray (ec.Module, single_spec);
10335 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
10337 if (spec.Next != null)
10338 MakeArray (module, spec.Next);
10340 type = ArrayContainer.MakeType (module, type, spec.Dimension);
10343 public override string GetSignatureForError ()
10345 return left.GetSignatureForError () + spec.GetSignatureForError ();
10348 public override object Accept (StructuralVisitor visitor)
10350 return visitor.Visit (this);
10354 class FixedBufferPtr : Expression
10356 readonly Expression array;
10358 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
10360 this.type = array_type;
10361 this.array = array;
10365 public override bool ContainsEmitWithAwait ()
10367 throw new NotImplementedException ();
10370 public override Expression CreateExpressionTree (ResolveContext ec)
10372 Error_PointerInsideExpressionTree (ec);
10376 public override void Emit(EmitContext ec)
10381 protected override Expression DoResolve (ResolveContext ec)
10383 type = PointerContainer.MakeType (ec.Module, type);
10384 eclass = ExprClass.Value;
10391 // This class is used to represent the address of an array, used
10392 // only by the Fixed statement, this generates "&a [0]" construct
10393 // for fixed (char *pa = a)
10395 class ArrayPtr : FixedBufferPtr
10397 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
10398 base (array, array_type, l)
10402 public override void Emit (EmitContext ec)
10407 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
10412 // Encapsulates a conversion rules required for array indexes
10414 public class ArrayIndexCast : TypeCast
10416 public ArrayIndexCast (Expression expr, TypeSpec returnType)
10417 : base (expr, returnType)
10419 if (expr.Type == returnType) // int -> int
10420 throw new ArgumentException ("unnecessary array index conversion");
10423 public override Expression CreateExpressionTree (ResolveContext ec)
10425 using (ec.Set (ResolveContext.Options.CheckedScope)) {
10426 return base.CreateExpressionTree (ec);
10430 public override void Emit (EmitContext ec)
10434 switch (child.Type.BuiltinType) {
10435 case BuiltinTypeSpec.Type.UInt:
10436 ec.Emit (OpCodes.Conv_U);
10438 case BuiltinTypeSpec.Type.Long:
10439 ec.Emit (OpCodes.Conv_Ovf_I);
10441 case BuiltinTypeSpec.Type.ULong:
10442 ec.Emit (OpCodes.Conv_Ovf_I_Un);
10445 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
10451 // Implements the `stackalloc' keyword
10453 public class StackAlloc : Expression {
10458 public StackAlloc (Expression type, Expression count, Location l)
10461 this.count = count;
10465 public Expression TypeExpression {
10471 public Expression CountExpression {
10477 public override bool ContainsEmitWithAwait ()
10482 public override Expression CreateExpressionTree (ResolveContext ec)
10484 throw new NotSupportedException ("ET");
10487 protected override Expression DoResolve (ResolveContext ec)
10489 count = count.Resolve (ec);
10493 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
10494 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
10499 Constant c = count as Constant;
10500 if (c != null && c.IsNegative) {
10501 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
10504 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
10505 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
10508 otype = t.ResolveAsType (ec);
10512 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
10515 type = PointerContainer.MakeType (ec.Module, otype);
10516 eclass = ExprClass.Value;
10521 public override void Emit (EmitContext ec)
10523 int size = BuiltinTypeSpec.GetSize (otype);
10528 ec.Emit (OpCodes.Sizeof, otype);
10532 ec.Emit (OpCodes.Mul_Ovf_Un);
10533 ec.Emit (OpCodes.Localloc);
10536 protected override void CloneTo (CloneContext clonectx, Expression t)
10538 StackAlloc target = (StackAlloc) t;
10539 target.count = count.Clone (clonectx);
10540 target.t = t.Clone (clonectx);
10543 public override object Accept (StructuralVisitor visitor)
10545 return visitor.Visit (this);
10550 // An object initializer expression
10552 public class ElementInitializer : Assign
10554 public readonly string Name;
10556 public ElementInitializer (string name, Expression initializer, Location loc)
10557 : base (null, initializer, loc)
10562 protected override void CloneTo (CloneContext clonectx, Expression t)
10564 ElementInitializer target = (ElementInitializer) t;
10565 target.source = source.Clone (clonectx);
10568 public override Expression CreateExpressionTree (ResolveContext ec)
10570 Arguments args = new Arguments (2);
10571 FieldExpr fe = target as FieldExpr;
10573 args.Add (new Argument (fe.CreateTypeOfExpression ()));
10575 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
10578 Expression arg_expr;
10579 var cinit = source as CollectionOrObjectInitializers;
10580 if (cinit == null) {
10582 arg_expr = source.CreateExpressionTree (ec);
10584 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
10585 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
10588 args.Add (new Argument (arg_expr));
10589 return CreateExpressionFactoryCall (ec, mname, args);
10592 protected override Expression DoResolve (ResolveContext ec)
10594 if (source == null)
10595 return EmptyExpressionStatement.Instance;
10597 var t = ec.CurrentInitializerVariable.Type;
10598 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10599 Arguments args = new Arguments (1);
10600 args.Add (new Argument (ec.CurrentInitializerVariable));
10601 target = new DynamicMemberBinder (Name, args, loc);
10604 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10605 if (member == null) {
10606 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10608 if (member != null) {
10609 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
10610 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
10615 if (member == null) {
10616 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
10620 if (!(member is PropertyExpr || member is FieldExpr)) {
10621 ec.Report.Error (1913, loc,
10622 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
10623 member.GetSignatureForError ());
10628 var me = member as MemberExpr;
10630 ec.Report.Error (1914, loc,
10631 "Static field or property `{0}' cannot be assigned in an object initializer",
10632 me.GetSignatureForError ());
10636 me.InstanceExpression = ec.CurrentInitializerVariable;
10639 if (source is CollectionOrObjectInitializers) {
10640 Expression previous = ec.CurrentInitializerVariable;
10641 ec.CurrentInitializerVariable = target;
10642 source = source.Resolve (ec);
10643 ec.CurrentInitializerVariable = previous;
10644 if (source == null)
10647 eclass = source.eclass;
10648 type = source.Type;
10652 return base.DoResolve (ec);
10655 public override void EmitStatement (EmitContext ec)
10657 if (source is CollectionOrObjectInitializers)
10660 base.EmitStatement (ec);
10665 // A collection initializer expression
10667 class CollectionElementInitializer : Invocation
10669 public class ElementInitializerArgument : Argument
10671 public ElementInitializerArgument (Expression e)
10677 sealed class AddMemberAccess : MemberAccess
10679 public AddMemberAccess (Expression expr, Location loc)
10680 : base (expr, "Add", loc)
10684 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10686 if (TypeManager.HasElementType (type))
10689 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10693 public CollectionElementInitializer (Expression argument)
10694 : base (null, new Arguments (1))
10696 base.arguments.Add (new ElementInitializerArgument (argument));
10697 this.loc = argument.Location;
10700 public CollectionElementInitializer (List<Expression> arguments, Location loc)
10701 : base (null, new Arguments (arguments.Count))
10703 foreach (Expression e in arguments)
10704 base.arguments.Add (new ElementInitializerArgument (e));
10709 public CollectionElementInitializer (Location loc)
10710 : base (null, null)
10715 public override Expression CreateExpressionTree (ResolveContext ec)
10717 Arguments args = new Arguments (2);
10718 args.Add (new Argument (mg.CreateExpressionTree (ec)));
10720 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
10721 foreach (Argument a in arguments)
10722 expr_initializers.Add (a.CreateExpressionTree (ec));
10724 args.Add (new Argument (new ArrayCreation (
10725 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
10726 return CreateExpressionFactoryCall (ec, "ElementInit", args);
10729 protected override void CloneTo (CloneContext clonectx, Expression t)
10731 CollectionElementInitializer target = (CollectionElementInitializer) t;
10732 if (arguments != null)
10733 target.arguments = arguments.Clone (clonectx);
10736 protected override Expression DoResolve (ResolveContext ec)
10738 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
10740 return base.DoResolve (ec);
10745 // A block of object or collection initializers
10747 public class CollectionOrObjectInitializers : ExpressionStatement
10749 IList<Expression> initializers;
10750 bool is_collection_initialization;
10752 public CollectionOrObjectInitializers (Location loc)
10753 : this (new Expression[0], loc)
10757 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10759 this.initializers = initializers;
10763 public IList<Expression> Initializers {
10765 return initializers;
10769 public bool IsEmpty {
10771 return initializers.Count == 0;
10775 public bool IsCollectionInitializer {
10777 return is_collection_initialization;
10781 protected override void CloneTo (CloneContext clonectx, Expression target)
10783 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10785 t.initializers = new List<Expression> (initializers.Count);
10786 foreach (var e in initializers)
10787 t.initializers.Add (e.Clone (clonectx));
10790 public override bool ContainsEmitWithAwait ()
10792 foreach (var e in initializers) {
10793 if (e.ContainsEmitWithAwait ())
10800 public override Expression CreateExpressionTree (ResolveContext ec)
10802 return CreateExpressionTree (ec, false);
10805 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10807 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10808 foreach (Expression e in initializers) {
10809 Expression expr = e.CreateExpressionTree (ec);
10811 expr_initializers.Add (expr);
10815 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10817 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10820 protected override Expression DoResolve (ResolveContext ec)
10822 List<string> element_names = null;
10823 for (int i = 0; i < initializers.Count; ++i) {
10824 Expression initializer = initializers [i];
10825 ElementInitializer element_initializer = initializer as ElementInitializer;
10828 if (element_initializer != null) {
10829 element_names = new List<string> (initializers.Count);
10830 element_names.Add (element_initializer.Name);
10831 } else if (initializer is CompletingExpression){
10832 initializer.Resolve (ec);
10833 throw new InternalErrorException ("This line should never be reached");
10835 var t = ec.CurrentInitializerVariable.Type;
10836 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10837 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10838 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10839 "object initializer because type `{1}' does not implement `{2}' interface",
10840 ec.CurrentInitializerVariable.GetSignatureForError (),
10841 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10842 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10845 is_collection_initialization = true;
10848 if (is_collection_initialization != (element_initializer == null)) {
10849 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10850 is_collection_initialization ? "collection initializer" : "object initializer");
10854 if (!is_collection_initialization) {
10855 if (element_names.Contains (element_initializer.Name)) {
10856 ec.Report.Error (1912, element_initializer.Location,
10857 "An object initializer includes more than one member `{0}' initialization",
10858 element_initializer.Name);
10860 element_names.Add (element_initializer.Name);
10865 Expression e = initializer.Resolve (ec);
10866 if (e == EmptyExpressionStatement.Instance)
10867 initializers.RemoveAt (i--);
10869 initializers [i] = e;
10872 type = ec.CurrentInitializerVariable.Type;
10873 if (is_collection_initialization) {
10874 if (TypeManager.HasElementType (type)) {
10875 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10876 type.GetSignatureForError ());
10880 eclass = ExprClass.Variable;
10884 public override void Emit (EmitContext ec)
10886 EmitStatement (ec);
10889 public override void EmitStatement (EmitContext ec)
10891 foreach (ExpressionStatement e in initializers) {
10892 // TODO: need location region
10893 ec.Mark (e.Location);
10894 e.EmitStatement (ec);
10898 public override void FlowAnalysis (FlowAnalysisContext fc)
10900 foreach (var initializer in initializers)
10901 initializer.FlowAnalysis (fc);
10906 // New expression with element/object initializers
10908 public class NewInitialize : New
10911 // This class serves as a proxy for variable initializer target instances.
10912 // A real variable is assigned later when we resolve left side of an
10915 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10917 NewInitialize new_instance;
10919 public InitializerTargetExpression (NewInitialize newInstance)
10921 this.type = newInstance.type;
10922 this.loc = newInstance.loc;
10923 this.eclass = newInstance.eclass;
10924 this.new_instance = newInstance;
10927 public override bool ContainsEmitWithAwait ()
10932 public override Expression CreateExpressionTree (ResolveContext ec)
10934 // Should not be reached
10935 throw new NotSupportedException ("ET");
10938 protected override Expression DoResolve (ResolveContext ec)
10943 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10948 public override void Emit (EmitContext ec)
10950 Expression e = (Expression) new_instance.instance;
10954 public override Expression EmitToField (EmitContext ec)
10956 return (Expression) new_instance.instance;
10959 #region IMemoryLocation Members
10961 public void AddressOf (EmitContext ec, AddressOp mode)
10963 new_instance.instance.AddressOf (ec, mode);
10969 CollectionOrObjectInitializers initializers;
10970 IMemoryLocation instance;
10971 DynamicExpressionStatement dynamic;
10973 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10974 : base (requested_type, arguments, l)
10976 this.initializers = initializers;
10979 public CollectionOrObjectInitializers Initializers {
10981 return initializers;
10985 protected override void CloneTo (CloneContext clonectx, Expression t)
10987 base.CloneTo (clonectx, t);
10989 NewInitialize target = (NewInitialize) t;
10990 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
10993 public override bool ContainsEmitWithAwait ()
10995 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
10998 public override Expression CreateExpressionTree (ResolveContext ec)
11000 Arguments args = new Arguments (2);
11001 args.Add (new Argument (base.CreateExpressionTree (ec)));
11002 if (!initializers.IsEmpty)
11003 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
11005 return CreateExpressionFactoryCall (ec,
11006 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
11010 protected override Expression DoResolve (ResolveContext ec)
11012 Expression e = base.DoResolve (ec);
11016 if (type.IsDelegate) {
11017 ec.Report.Error (1958, Initializers.Location,
11018 "Object and collection initializers cannot be used to instantiate a delegate");
11021 Expression previous = ec.CurrentInitializerVariable;
11022 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
11023 initializers.Resolve (ec);
11024 ec.CurrentInitializerVariable = previous;
11026 dynamic = e as DynamicExpressionStatement;
11027 if (dynamic != null)
11033 public override bool Emit (EmitContext ec, IMemoryLocation target)
11035 bool left_on_stack;
11036 if (dynamic != null) {
11038 left_on_stack = true;
11040 left_on_stack = base.Emit (ec, target);
11043 if (initializers.IsEmpty)
11044 return left_on_stack;
11046 LocalTemporary temp = null;
11048 instance = target as LocalTemporary;
11050 if (instance == null) {
11051 if (!left_on_stack) {
11052 VariableReference vr = target as VariableReference;
11054 // FIXME: This still does not work correctly for pre-set variables
11055 if (vr != null && vr.IsRef)
11056 target.AddressOf (ec, AddressOp.Load);
11058 ((Expression) target).Emit (ec);
11059 left_on_stack = true;
11062 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
11063 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
11065 temp = new LocalTemporary (type);
11070 if (left_on_stack && temp != null)
11073 initializers.Emit (ec);
11075 if (left_on_stack) {
11076 if (temp != null) {
11080 ((Expression) instance).Emit (ec);
11084 return left_on_stack;
11087 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
11089 instance = base.EmitAddressOf (ec, Mode);
11091 if (!initializers.IsEmpty)
11092 initializers.Emit (ec);
11097 public override void FlowAnalysis (FlowAnalysisContext fc)
11099 base.FlowAnalysis (fc);
11100 initializers.FlowAnalysis (fc);
11103 public override object Accept (StructuralVisitor visitor)
11105 return visitor.Visit (this);
11109 public class NewAnonymousType : New
11111 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
11113 List<AnonymousTypeParameter> parameters;
11114 readonly TypeContainer parent;
11115 AnonymousTypeClass anonymous_type;
11117 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
11118 : base (null, null, loc)
11120 this.parameters = parameters;
11121 this.parent = parent;
11124 public List<AnonymousTypeParameter> Parameters {
11126 return this.parameters;
11130 protected override void CloneTo (CloneContext clonectx, Expression target)
11132 if (parameters == null)
11135 NewAnonymousType t = (NewAnonymousType) target;
11136 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
11137 foreach (AnonymousTypeParameter atp in parameters)
11138 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
11141 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
11143 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
11147 type = AnonymousTypeClass.Create (parent, parameters, loc);
11151 int errors = ec.Report.Errors;
11152 type.CreateContainer ();
11153 type.DefineContainer ();
11155 if ((ec.Report.Errors - errors) == 0) {
11156 parent.Module.AddAnonymousType (type);
11162 public override Expression CreateExpressionTree (ResolveContext ec)
11164 if (parameters == null)
11165 return base.CreateExpressionTree (ec);
11167 var init = new ArrayInitializer (parameters.Count, loc);
11168 foreach (var m in anonymous_type.Members) {
11169 var p = m as Property;
11171 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
11174 var ctor_args = new ArrayInitializer (arguments.Count, loc);
11175 foreach (Argument a in arguments)
11176 ctor_args.Add (a.CreateExpressionTree (ec));
11178 Arguments args = new Arguments (3);
11179 args.Add (new Argument (new TypeOfMethod (method, loc)));
11180 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
11181 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
11183 return CreateExpressionFactoryCall (ec, "New", args);
11186 protected override Expression DoResolve (ResolveContext ec)
11188 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
11189 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
11193 if (parameters == null) {
11194 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
11195 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
11196 return base.DoResolve (ec);
11199 bool error = false;
11200 arguments = new Arguments (parameters.Count);
11201 var t_args = new TypeSpec [parameters.Count];
11202 for (int i = 0; i < parameters.Count; ++i) {
11203 Expression e = parameters [i].Resolve (ec);
11209 arguments.Add (new Argument (e));
11210 t_args [i] = e.Type;
11216 anonymous_type = CreateAnonymousType (ec, parameters);
11217 if (anonymous_type == null)
11220 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
11221 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
11222 eclass = ExprClass.Value;
11226 public override object Accept (StructuralVisitor visitor)
11228 return visitor.Visit (this);
11232 public class AnonymousTypeParameter : ShimExpression
11234 public readonly string Name;
11236 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
11237 : base (initializer)
11243 public AnonymousTypeParameter (Parameter parameter)
11244 : base (new SimpleName (parameter.Name, parameter.Location))
11246 this.Name = parameter.Name;
11247 this.loc = parameter.Location;
11250 public override bool Equals (object o)
11252 AnonymousTypeParameter other = o as AnonymousTypeParameter;
11253 return other != null && Name == other.Name;
11256 public override int GetHashCode ()
11258 return Name.GetHashCode ();
11261 protected override Expression DoResolve (ResolveContext ec)
11263 Expression e = expr.Resolve (ec);
11267 if (e.eclass == ExprClass.MethodGroup) {
11268 Error_InvalidInitializer (ec, e.ExprClassName);
11273 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
11274 Error_InvalidInitializer (ec, type.GetSignatureForError ());
11281 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
11283 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
11284 Name, initializer);