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 || MOBILE_DYNAMIC
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 || MOBILE_DYNAMIC
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 || MOBILE_DYNAMIC) && !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 each parameter type and return type 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 || MOBILE_DYNAMIC
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, StackFieldExpr 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.EmitWithCleanup (ec, false);
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;
7544 if (stackArray != null)
7545 stackArray.IsAvailableForReuse = true;
7548 public override void Emit (EmitContext ec)
7550 EmitToFieldSource (ec);
7553 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
7555 if (first_emit != null) {
7556 first_emit.Emit (ec);
7557 first_emit_temp.Store (ec);
7560 StackFieldExpr await_stack_field;
7561 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
7562 await_stack_field = ec.GetTemporaryField (type);
7565 await_stack_field = null;
7568 EmitExpressionsList (ec, arguments);
7570 ec.EmitArrayNew ((ArrayContainer) type);
7572 if (initializers == null)
7573 return await_stack_field;
7575 if (await_stack_field != null)
7576 await_stack_field.EmitAssignFromStack (ec);
7580 // Emit static initializer for arrays which contain more than 2 items and
7581 // the static initializer will initialize at least 25% of array values or there
7582 // is more than 10 items to be initialized
7584 // NOTE: const_initializers_count does not contain default constant values.
7586 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
7587 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
7588 EmitStaticInitializers (ec, await_stack_field);
7590 if (!only_constant_initializers)
7591 EmitDynamicInitializers (ec, false, await_stack_field);
7595 EmitDynamicInitializers (ec, true, await_stack_field);
7598 if (first_emit_temp != null)
7599 first_emit_temp.Release (ec);
7601 return await_stack_field;
7604 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7606 // no multi dimensional or jagged arrays
7607 if (arguments.Count != 1 || array_element_type.IsArray) {
7608 base.EncodeAttributeValue (rc, enc, targetType);
7612 // No array covariance, except for array -> object
7613 if (type != targetType) {
7614 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
7615 base.EncodeAttributeValue (rc, enc, targetType);
7619 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
7620 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7625 // Single dimensional array of 0 size
7626 if (array_data == null) {
7627 IntConstant ic = arguments[0] as IntConstant;
7628 if (ic == null || !ic.IsDefaultValue) {
7629 base.EncodeAttributeValue (rc, enc, targetType);
7637 enc.Encode (array_data.Count);
7638 foreach (var element in array_data) {
7639 element.EncodeAttributeValue (rc, enc, array_element_type);
7643 protected override void CloneTo (CloneContext clonectx, Expression t)
7645 ArrayCreation target = (ArrayCreation) t;
7647 if (requested_base_type != null)
7648 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
7650 if (arguments != null){
7651 target.arguments = new List<Expression> (arguments.Count);
7652 foreach (Expression e in arguments)
7653 target.arguments.Add (e.Clone (clonectx));
7656 if (initializers != null)
7657 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
7660 public override object Accept (StructuralVisitor visitor)
7662 return visitor.Visit (this);
7667 // Represents an implicitly typed array epxression
7669 class ImplicitlyTypedArrayCreation : ArrayCreation
7671 TypeInferenceContext best_type_inference;
7673 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7674 : base (null, rank, initializers, loc)
7678 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
7679 : base (null, initializers, loc)
7683 protected override Expression DoResolve (ResolveContext ec)
7688 dimensions = rank.Dimension;
7690 best_type_inference = new TypeInferenceContext ();
7692 if (!ResolveInitializers (ec))
7695 best_type_inference.FixAllTypes (ec);
7696 array_element_type = best_type_inference.InferredTypeArguments[0];
7697 best_type_inference = null;
7699 if (array_element_type == null ||
7700 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
7701 arguments.Count != rank.Dimension) {
7702 ec.Report.Error (826, loc,
7703 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
7708 // At this point we found common base type for all initializer elements
7709 // but we have to be sure that all static initializer elements are of
7712 UnifyInitializerElement (ec);
7714 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
7715 eclass = ExprClass.Value;
7720 // Converts static initializer only
7722 void UnifyInitializerElement (ResolveContext ec)
7724 for (int i = 0; i < array_data.Count; ++i) {
7725 Expression e = array_data[i];
7727 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
7731 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
7733 element = element.Resolve (ec);
7734 if (element != null)
7735 best_type_inference.AddCommonTypeBound (element.Type);
7741 sealed class CompilerGeneratedThis : This
7743 public CompilerGeneratedThis (TypeSpec type, Location loc)
7747 eclass = ExprClass.Variable;
7750 protected override Expression DoResolve (ResolveContext ec)
7755 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7762 /// Represents the `this' construct
7765 public class This : VariableReference
7767 sealed class ThisVariable : ILocalVariable
7769 public static readonly ILocalVariable Instance = new ThisVariable ();
7771 public void Emit (EmitContext ec)
7776 public void EmitAssign (EmitContext ec)
7778 throw new InvalidOperationException ();
7781 public void EmitAddressOf (EmitContext ec)
7787 VariableInfo variable_info;
7789 public This (Location loc)
7796 public override string Name {
7797 get { return "this"; }
7800 public override bool IsLockedByStatement {
7808 public override bool IsRef {
7809 get { return type.IsStruct; }
7812 public override bool IsSideEffectFree {
7818 protected override ILocalVariable Variable {
7819 get { return ThisVariable.Instance; }
7822 public override VariableInfo VariableInfo {
7823 get { return variable_info; }
7826 public override bool IsFixed {
7827 get { return false; }
7832 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
7835 // It's null for all cases when we don't need to check `this'
7836 // definitive assignment
7838 if (variable_info == null)
7841 if (fc.IsDefinitelyAssigned (variable_info))
7844 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
7847 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7849 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7850 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7851 } else if (ec.CurrentAnonymousMethod != null) {
7852 ec.Report.Error (1673, loc,
7853 "Anonymous methods inside structs cannot access instance members of `this'. " +
7854 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7856 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7860 public override void FlowAnalysis (FlowAnalysisContext fc)
7862 CheckStructThisDefiniteAssignment (fc);
7865 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7870 AnonymousMethodStorey storey = ae.Storey;
7871 return storey != null ? storey.HoistedThis : null;
7874 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7876 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7879 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7882 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7888 public virtual void ResolveBase (ResolveContext ec)
7890 eclass = ExprClass.Variable;
7891 type = ec.CurrentType;
7893 if (!IsThisAvailable (ec, false)) {
7894 Error_ThisNotAvailable (ec);
7898 var block = ec.CurrentBlock;
7899 if (block != null) {
7900 var top = block.ParametersBlock.TopBlock;
7901 if (top.ThisVariable != null)
7902 variable_info = top.ThisVariable.VariableInfo;
7904 AnonymousExpression am = ec.CurrentAnonymousMethod;
7905 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7907 // Hoisted this is almost like hoisted variable but not exactly. When
7908 // there is no variable hoisted we can simply emit an instance method
7909 // without lifting this into a storey. Unfotunatelly this complicates
7910 // things in other cases because we don't know where this will be hoisted
7911 // until top-level block is fully resolved
7913 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7914 am.SetHasThisAccess ();
7919 protected override Expression DoResolve (ResolveContext ec)
7925 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7927 if (eclass == ExprClass.Unresolved)
7931 if (right_side == EmptyExpression.UnaryAddress)
7932 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7933 else if (right_side == EmptyExpression.OutAccess)
7934 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7936 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7942 public override int GetHashCode()
7944 throw new NotImplementedException ();
7947 public override bool Equals (object obj)
7949 This t = obj as This;
7956 protected override void CloneTo (CloneContext clonectx, Expression t)
7961 public override void SetHasAddressTaken ()
7966 public override object Accept (StructuralVisitor visitor)
7968 return visitor.Visit (this);
7973 /// Represents the `__arglist' construct
7975 public class ArglistAccess : Expression
7977 public ArglistAccess (Location loc)
7982 protected override void CloneTo (CloneContext clonectx, Expression target)
7987 public override bool ContainsEmitWithAwait ()
7992 public override Expression CreateExpressionTree (ResolveContext ec)
7994 throw new NotSupportedException ("ET");
7997 protected override Expression DoResolve (ResolveContext ec)
7999 eclass = ExprClass.Variable;
8000 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8002 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8003 ec.Report.Error (190, loc,
8004 "The __arglist construct is valid only within a variable argument method");
8010 public override void Emit (EmitContext ec)
8012 ec.Emit (OpCodes.Arglist);
8015 public override object Accept (StructuralVisitor visitor)
8017 return visitor.Visit (this);
8022 /// Represents the `__arglist (....)' construct
8024 public class Arglist : Expression
8026 Arguments arguments;
8028 public Arglist (Location loc)
8033 public Arglist (Arguments args, Location l)
8039 public Arguments Arguments {
8045 public MetaType[] ArgumentTypes {
8047 if (arguments == null)
8048 return MetaType.EmptyTypes;
8050 var retval = new MetaType[arguments.Count];
8051 for (int i = 0; i < retval.Length; i++)
8052 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8058 public override bool ContainsEmitWithAwait ()
8060 throw new NotImplementedException ();
8063 public override Expression CreateExpressionTree (ResolveContext ec)
8065 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8069 protected override Expression DoResolve (ResolveContext ec)
8071 eclass = ExprClass.Variable;
8072 type = InternalType.Arglist;
8073 if (arguments != null) {
8074 bool dynamic; // Can be ignored as there is always only 1 overload
8075 arguments.Resolve (ec, out dynamic);
8081 public override void Emit (EmitContext ec)
8083 if (arguments != null)
8084 arguments.Emit (ec);
8087 protected override void CloneTo (CloneContext clonectx, Expression t)
8089 Arglist target = (Arglist) t;
8091 if (arguments != null)
8092 target.arguments = arguments.Clone (clonectx);
8095 public override object Accept (StructuralVisitor visitor)
8097 return visitor.Visit (this);
8101 public class RefValueExpr : ShimExpression, IAssignMethod
8103 FullNamedExpression texpr;
8105 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8112 public FullNamedExpression TypeExpression {
8118 public override bool ContainsEmitWithAwait ()
8123 protected override Expression DoResolve (ResolveContext rc)
8125 expr = expr.Resolve (rc);
8126 type = texpr.ResolveAsType (rc);
8127 if (expr == null || type == null)
8130 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8131 eclass = ExprClass.Value;
8135 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8137 return DoResolve (rc);
8140 public override void Emit (EmitContext ec)
8143 ec.Emit (OpCodes.Refanyval, type);
8144 ec.EmitLoadFromPtr (type);
8147 public void Emit (EmitContext ec, bool leave_copy)
8149 throw new NotImplementedException ();
8152 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8155 ec.Emit (OpCodes.Refanyval, type);
8158 LocalTemporary temporary = null;
8160 ec.Emit (OpCodes.Dup);
8161 temporary = new LocalTemporary (source.Type);
8162 temporary.Store (ec);
8165 ec.EmitStoreFromPtr (type);
8167 if (temporary != null) {
8168 temporary.Emit (ec);
8169 temporary.Release (ec);
8173 public override object Accept (StructuralVisitor visitor)
8175 return visitor.Visit (this);
8179 public class RefTypeExpr : ShimExpression
8181 public RefTypeExpr (Expression expr, Location loc)
8187 protected override Expression DoResolve (ResolveContext rc)
8189 expr = expr.Resolve (rc);
8193 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8197 type = rc.BuiltinTypes.Type;
8198 eclass = ExprClass.Value;
8202 public override void Emit (EmitContext ec)
8205 ec.Emit (OpCodes.Refanytype);
8206 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8208 ec.Emit (OpCodes.Call, m);
8211 public override object Accept (StructuralVisitor visitor)
8213 return visitor.Visit (this);
8217 public class MakeRefExpr : ShimExpression
8219 public MakeRefExpr (Expression expr, Location loc)
8225 public override bool ContainsEmitWithAwait ()
8227 throw new NotImplementedException ();
8230 protected override Expression DoResolve (ResolveContext rc)
8232 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8233 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8234 eclass = ExprClass.Value;
8238 public override void Emit (EmitContext ec)
8240 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8241 ec.Emit (OpCodes.Mkrefany, expr.Type);
8244 public override object Accept (StructuralVisitor visitor)
8246 return visitor.Visit (this);
8251 /// Implements the typeof operator
8253 public class TypeOf : Expression {
8254 FullNamedExpression QueriedType;
8257 public TypeOf (FullNamedExpression queried_type, Location l)
8259 QueriedType = queried_type;
8264 // Use this constructor for any compiler generated typeof expression
8266 public TypeOf (TypeSpec type, Location loc)
8268 this.typearg = type;
8274 public override bool IsSideEffectFree {
8280 public TypeSpec TypeArgument {
8286 public FullNamedExpression TypeExpression {
8295 protected override void CloneTo (CloneContext clonectx, Expression t)
8297 TypeOf target = (TypeOf) t;
8298 if (QueriedType != null)
8299 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
8302 public override bool ContainsEmitWithAwait ()
8307 public override Expression CreateExpressionTree (ResolveContext ec)
8309 Arguments args = new Arguments (2);
8310 args.Add (new Argument (this));
8311 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8312 return CreateExpressionFactoryCall (ec, "Constant", args);
8315 protected override Expression DoResolve (ResolveContext ec)
8317 if (eclass != ExprClass.Unresolved)
8320 if (typearg == null) {
8322 // Pointer types are allowed without explicit unsafe, they are just tokens
8324 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
8325 typearg = QueriedType.ResolveAsType (ec);
8328 if (typearg == null)
8331 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8332 ec.Report.Error (1962, QueriedType.Location,
8333 "The typeof operator cannot be used on the dynamic type");
8337 type = ec.BuiltinTypes.Type;
8339 // Even though what is returned is a type object, it's treated as a value by the compiler.
8340 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
8341 eclass = ExprClass.Value;
8345 static bool ContainsDynamicType (TypeSpec type)
8347 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
8350 var element_container = type as ElementTypeSpec;
8351 if (element_container != null)
8352 return ContainsDynamicType (element_container.Element);
8354 foreach (var t in type.TypeArguments) {
8355 if (ContainsDynamicType (t)) {
8363 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
8365 // Target type is not System.Type therefore must be object
8366 // and we need to use different encoding sequence
8367 if (targetType != type)
8370 if (typearg is InflatedTypeSpec) {
8373 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
8374 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
8375 typearg.GetSignatureForError ());
8379 gt = gt.DeclaringType;
8380 } while (gt != null);
8383 if (ContainsDynamicType (typearg)) {
8384 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8388 enc.EncodeTypeName (typearg);
8391 public override void Emit (EmitContext ec)
8393 ec.Emit (OpCodes.Ldtoken, typearg);
8394 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8396 ec.Emit (OpCodes.Call, m);
8399 public override object Accept (StructuralVisitor visitor)
8401 return visitor.Visit (this);
8405 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
8407 public TypeOfMethod (MethodSpec method, Location loc)
8408 : base (method, loc)
8412 protected override Expression DoResolve (ResolveContext ec)
8414 if (member.IsConstructor) {
8415 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
8417 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
8423 return base.DoResolve (ec);
8426 public override void Emit (EmitContext ec)
8428 ec.Emit (OpCodes.Ldtoken, member);
8431 ec.Emit (OpCodes.Castclass, type);
8434 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8436 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
8439 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8441 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
8445 abstract class TypeOfMember<T> : Expression where T : MemberSpec
8447 protected readonly T member;
8449 protected TypeOfMember (T member, Location loc)
8451 this.member = member;
8455 public override bool IsSideEffectFree {
8461 public override bool ContainsEmitWithAwait ()
8466 public override Expression CreateExpressionTree (ResolveContext ec)
8468 Arguments args = new Arguments (2);
8469 args.Add (new Argument (this));
8470 args.Add (new Argument (new TypeOf (type, loc)));
8471 return CreateExpressionFactoryCall (ec, "Constant", args);
8474 protected override Expression DoResolve (ResolveContext ec)
8476 eclass = ExprClass.Value;
8480 public override void Emit (EmitContext ec)
8482 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
8483 PredefinedMember<MethodSpec> p;
8485 p = GetTypeFromHandleGeneric (ec);
8486 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
8488 p = GetTypeFromHandle (ec);
8491 var mi = p.Resolve (loc);
8493 ec.Emit (OpCodes.Call, mi);
8496 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
8497 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
8500 sealed class TypeOfField : TypeOfMember<FieldSpec>
8502 public TypeOfField (FieldSpec field, Location loc)
8507 protected override Expression DoResolve (ResolveContext ec)
8509 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
8513 return base.DoResolve (ec);
8516 public override void Emit (EmitContext ec)
8518 ec.Emit (OpCodes.Ldtoken, member);
8522 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8524 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
8527 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8529 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
8534 /// Implements the sizeof expression
8536 public class SizeOf : Expression {
8537 readonly Expression texpr;
8538 TypeSpec type_queried;
8540 public SizeOf (Expression queried_type, Location l)
8542 this.texpr = queried_type;
8546 public override bool IsSideEffectFree {
8552 public Expression TypeExpression {
8558 public override bool ContainsEmitWithAwait ()
8563 public override Expression CreateExpressionTree (ResolveContext ec)
8565 Error_PointerInsideExpressionTree (ec);
8569 protected override Expression DoResolve (ResolveContext ec)
8571 type_queried = texpr.ResolveAsType (ec);
8572 if (type_queried == null)
8575 if (type_queried.IsEnum)
8576 type_queried = EnumSpec.GetUnderlyingType (type_queried);
8578 int size_of = BuiltinTypeSpec.GetSize (type_queried);
8580 return new IntConstant (ec.BuiltinTypes, size_of, loc);
8583 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
8588 ec.Report.Error (233, loc,
8589 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
8590 type_queried.GetSignatureForError ());
8593 type = ec.BuiltinTypes.Int;
8594 eclass = ExprClass.Value;
8598 public override void Emit (EmitContext ec)
8600 ec.Emit (OpCodes.Sizeof, type_queried);
8603 protected override void CloneTo (CloneContext clonectx, Expression t)
8607 public override object Accept (StructuralVisitor visitor)
8609 return visitor.Visit (this);
8614 /// Implements the qualified-alias-member (::) expression.
8616 public class QualifiedAliasMember : MemberAccess
8618 readonly string alias;
8619 public static readonly string GlobalAlias = "global";
8621 public QualifiedAliasMember (string alias, string identifier, Location l)
8622 : base (null, identifier, l)
8627 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
8628 : base (null, identifier, targs, l)
8633 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
8634 : base (null, identifier, arity, l)
8639 public string Alias {
8645 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
8647 if (alias == GlobalAlias) {
8648 expr = new NamespaceExpression (ec.Module.GlobalRootNamespace, loc);
8649 return base.ResolveAsTypeOrNamespace (ec);
8652 int errors = ec.Module.Compiler.Report.Errors;
8653 expr = ec.LookupNamespaceAlias (alias);
8655 if (errors == ec.Module.Compiler.Report.Errors)
8656 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
8660 return base.ResolveAsTypeOrNamespace (ec);
8663 protected override Expression DoResolve (ResolveContext ec)
8665 return ResolveAsTypeOrNamespace (ec);
8668 public override string GetSignatureForError ()
8671 if (targs != null) {
8672 name = Name + "<" + targs.GetSignatureForError () + ">";
8675 return alias + "::" + name;
8678 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8680 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
8681 rc.Module.Compiler.Report.Error (687, loc,
8682 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
8683 GetSignatureForError ());
8688 return DoResolve (rc);
8691 protected override void CloneTo (CloneContext clonectx, Expression t)
8696 public override object Accept (StructuralVisitor visitor)
8698 return visitor.Visit (this);
8703 /// Implements the member access expression
8705 public class MemberAccess : ATypeNameExpression
8707 protected Expression expr;
8709 public MemberAccess (Expression expr, string id)
8710 : base (id, expr.Location)
8715 public MemberAccess (Expression expr, string identifier, Location loc)
8716 : base (identifier, loc)
8721 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
8722 : base (identifier, args, loc)
8727 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
8728 : base (identifier, arity, loc)
8733 public Expression LeftExpression {
8739 public override Location StartLocation {
8741 return expr == null ? loc : expr.StartLocation;
8745 protected override Expression DoResolve (ResolveContext rc)
8747 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
8749 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
8754 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
8756 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
8758 if (e is TypeExpr) {
8759 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8764 e = e.ResolveLValue (rc, rhs);
8769 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8771 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8772 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8774 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8777 public static bool IsValidDotExpression (TypeSpec type)
8779 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8780 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8782 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8785 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8787 var sn = expr as SimpleName;
8788 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8791 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8794 // Resolve expression which does have type set as we need expression type
8795 // with disable flow analysis as we don't know whether left side expression
8796 // is used as variable or type
8798 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8799 expr = expr.Resolve (rc);
8800 } else if (expr is TypeParameterExpr) {
8801 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8805 expr = expr.Resolve (rc, flags);
8811 var ns = expr as NamespaceExpression;
8813 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8815 if (retval == null) {
8816 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
8820 if (HasTypeArguments)
8821 return new GenericTypeExpr (retval.Type, targs, loc);
8827 TypeSpec expr_type = expr.Type;
8828 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8829 me = expr as MemberExpr;
8831 me.ResolveInstanceExpression (rc, null);
8833 Arguments args = new Arguments (1);
8834 args.Add (new Argument (expr));
8835 return new DynamicMemberBinder (Name, args, loc);
8838 if (!IsValidDotExpression (expr_type)) {
8839 Error_OperatorCannotBeApplied (rc, expr_type);
8843 var lookup_arity = Arity;
8844 bool errorMode = false;
8845 Expression member_lookup;
8847 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8848 if (member_lookup == null) {
8850 // Try to look for extension method when member lookup failed
8852 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8853 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8854 if (methods != null) {
8855 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8856 if (HasTypeArguments) {
8857 if (!targs.Resolve (rc))
8860 emg.SetTypeArguments (rc, targs);
8863 // TODO: it should really skip the checks bellow
8864 return emg.Resolve (rc);
8870 if (member_lookup == null) {
8871 var dep = expr_type.GetMissingDependencies ();
8873 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8874 } else if (expr is TypeExpr) {
8875 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8877 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8883 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8884 // Leave it to overload resolution to report correct error
8885 } else if (!(member_lookup is TypeExpr)) {
8886 // TODO: rc.SymbolRelatedToPreviousError
8887 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8892 if (member_lookup != null)
8896 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8900 TypeExpr texpr = member_lookup as TypeExpr;
8901 if (texpr != null) {
8902 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8903 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8904 Name, texpr.GetSignatureForError ());
8907 if (!texpr.Type.IsAccessible (rc)) {
8908 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8909 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8913 if (HasTypeArguments) {
8914 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8917 return member_lookup;
8920 me = member_lookup as MemberExpr;
8922 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8926 me = me.ResolveMemberAccess (rc, expr, sn);
8929 if (!targs.Resolve (rc))
8932 me.SetTypeArguments (rc, targs);
8938 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8940 FullNamedExpression fexpr = expr as FullNamedExpression;
8941 if (fexpr == null) {
8942 expr.ResolveAsType (rc);
8946 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8948 if (expr_resolved == null)
8951 var ns = expr_resolved as NamespaceExpression;
8953 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8955 if (retval == null) {
8956 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
8957 } else if (HasTypeArguments) {
8958 retval = new GenericTypeExpr (retval.Type, targs, loc);
8959 if (retval.ResolveAsType (rc) == null)
8966 var tnew_expr = expr_resolved.ResolveAsType (rc);
8967 if (tnew_expr == null)
8970 TypeSpec expr_type = tnew_expr;
8971 if (TypeManager.IsGenericParameter (expr_type)) {
8972 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8973 tnew_expr.GetSignatureForError ());
8977 var qam = this as QualifiedAliasMember;
8979 rc.Module.Compiler.Report.Error (431, loc,
8980 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8985 TypeSpec nested = null;
8986 while (expr_type != null) {
8987 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8988 if (nested == null) {
8989 if (expr_type == tnew_expr) {
8990 Error_IdentifierNotFound (rc, expr_type, Name);
8994 expr_type = tnew_expr;
8995 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8996 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9000 if (nested.IsAccessible (rc))
9004 // Keep looking after inaccessible candidate but only if
9005 // we are not in same context as the definition itself
9007 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9010 expr_type = expr_type.BaseType;
9015 if (HasTypeArguments) {
9016 texpr = new GenericTypeExpr (nested, targs, loc);
9018 texpr = new GenericOpenTypeExpr (nested, loc);
9021 texpr = new TypeExpression (nested, loc);
9024 if (texpr.ResolveAsType (rc) == null)
9030 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
9032 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9034 if (nested != null) {
9035 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9039 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9040 if (any_other_member != null) {
9041 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9045 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9046 Name, expr_type.GetSignatureForError ());
9049 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9051 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9054 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9056 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9057 ec.Report.SymbolRelatedToPreviousError (type);
9059 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9061 // a using directive or an assembly reference
9063 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9065 missing = "an assembly reference";
9068 ec.Report.Error (1061, loc,
9069 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9070 type.GetSignatureForError (), name, missing);
9074 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9077 public override string GetSignatureForError ()
9079 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9082 protected override void CloneTo (CloneContext clonectx, Expression t)
9084 MemberAccess target = (MemberAccess) t;
9086 target.expr = expr.Clone (clonectx);
9089 public override object Accept (StructuralVisitor visitor)
9091 return visitor.Visit (this);
9096 /// Implements checked expressions
9098 public class CheckedExpr : Expression {
9100 public Expression Expr;
9102 public CheckedExpr (Expression e, Location l)
9108 public override bool ContainsEmitWithAwait ()
9110 return Expr.ContainsEmitWithAwait ();
9113 public override Expression CreateExpressionTree (ResolveContext ec)
9115 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9116 return Expr.CreateExpressionTree (ec);
9119 protected override Expression DoResolve (ResolveContext ec)
9121 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9122 Expr = Expr.Resolve (ec);
9127 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9130 eclass = Expr.eclass;
9135 public override void Emit (EmitContext ec)
9137 using (ec.With (EmitContext.Options.CheckedScope, true))
9141 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9143 using (ec.With (EmitContext.Options.CheckedScope, true))
9144 Expr.EmitBranchable (ec, target, on_true);
9147 public override void FlowAnalysis (FlowAnalysisContext fc)
9149 Expr.FlowAnalysis (fc);
9152 public override SLE.Expression MakeExpression (BuilderContext ctx)
9154 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9155 return Expr.MakeExpression (ctx);
9159 protected override void CloneTo (CloneContext clonectx, Expression t)
9161 CheckedExpr target = (CheckedExpr) t;
9163 target.Expr = Expr.Clone (clonectx);
9166 public override object Accept (StructuralVisitor visitor)
9168 return visitor.Visit (this);
9173 /// Implements the unchecked expression
9175 public class UnCheckedExpr : Expression {
9177 public Expression Expr;
9179 public UnCheckedExpr (Expression e, Location l)
9185 public override bool ContainsEmitWithAwait ()
9187 return Expr.ContainsEmitWithAwait ();
9190 public override Expression CreateExpressionTree (ResolveContext ec)
9192 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9193 return Expr.CreateExpressionTree (ec);
9196 protected override Expression DoResolve (ResolveContext ec)
9198 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9199 Expr = Expr.Resolve (ec);
9204 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9207 eclass = Expr.eclass;
9212 public override void Emit (EmitContext ec)
9214 using (ec.With (EmitContext.Options.CheckedScope, false))
9218 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9220 using (ec.With (EmitContext.Options.CheckedScope, false))
9221 Expr.EmitBranchable (ec, target, on_true);
9224 public override void FlowAnalysis (FlowAnalysisContext fc)
9226 Expr.FlowAnalysis (fc);
9229 protected override void CloneTo (CloneContext clonectx, Expression t)
9231 UnCheckedExpr target = (UnCheckedExpr) t;
9233 target.Expr = Expr.Clone (clonectx);
9236 public override object Accept (StructuralVisitor visitor)
9238 return visitor.Visit (this);
9243 /// An Element Access expression.
9245 /// During semantic analysis these are transformed into
9246 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
9248 public class ElementAccess : Expression
9250 public Arguments Arguments;
9251 public Expression Expr;
9253 public ElementAccess (Expression e, Arguments args, Location loc)
9257 this.Arguments = args;
9260 public override Location StartLocation {
9262 return Expr.StartLocation;
9266 public override bool ContainsEmitWithAwait ()
9268 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
9272 // We perform some simple tests, and then to "split" the emit and store
9273 // code we create an instance of a different class, and return that.
9275 Expression CreateAccessExpression (ResolveContext ec)
9278 return (new ArrayAccess (this, loc));
9281 return MakePointerAccess (ec, type);
9283 FieldExpr fe = Expr as FieldExpr;
9285 var ff = fe.Spec as FixedFieldSpec;
9287 return MakePointerAccess (ec, ff.ElementType);
9291 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
9292 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9293 return new IndexerExpr (indexers, type, this);
9296 if (type != InternalType.ErrorType) {
9297 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
9298 type.GetSignatureForError ());
9304 public override Expression CreateExpressionTree (ResolveContext ec)
9306 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
9307 Expr.CreateExpressionTree (ec));
9309 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
9312 Expression MakePointerAccess (ResolveContext rc, TypeSpec type)
9314 if (Arguments.Count != 1){
9315 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
9319 var arg = Arguments[0];
9320 if (arg is NamedArgument)
9321 Error_NamedArgument ((NamedArgument) arg, rc.Report);
9323 var index = arg.Expr.Resolve (rc);
9327 index = ConvertExpressionToArrayIndex (rc, index, true);
9329 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, index, type, loc);
9330 return new Indirection (p, loc);
9333 protected override Expression DoResolve (ResolveContext ec)
9335 Expr = Expr.Resolve (ec);
9341 // TODO: Create 1 result for Resolve and ResolveLValue ?
9342 var res = CreateAccessExpression (ec);
9346 return res.Resolve (ec);
9349 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
9351 Expr = Expr.Resolve (ec);
9357 var res = CreateAccessExpression (ec);
9361 return res.ResolveLValue (ec, rhs);
9364 public override void Emit (EmitContext ec)
9366 throw new Exception ("Should never be reached");
9369 public static void Error_NamedArgument (NamedArgument na, Report Report)
9371 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
9374 public override void FlowAnalysis (FlowAnalysisContext fc)
9376 Expr.FlowAnalysis (fc);
9377 Arguments.FlowAnalysis (fc);
9380 public override string GetSignatureForError ()
9382 return Expr.GetSignatureForError ();
9385 protected override void CloneTo (CloneContext clonectx, Expression t)
9387 ElementAccess target = (ElementAccess) t;
9389 target.Expr = Expr.Clone (clonectx);
9390 if (Arguments != null)
9391 target.Arguments = Arguments.Clone (clonectx);
9394 public override object Accept (StructuralVisitor visitor)
9396 return visitor.Visit (this);
9401 /// Implements array access
9403 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
9405 // Points to our "data" repository
9409 LocalTemporary temp;
9411 bool? has_await_args;
9413 public ArrayAccess (ElementAccess ea_data, Location l)
9419 public void AddressOf (EmitContext ec, AddressOp mode)
9421 var ac = (ArrayContainer) ea.Expr.Type;
9423 LoadInstanceAndArguments (ec, false, false);
9425 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
9426 ec.Emit (OpCodes.Readonly);
9428 ec.EmitArrayAddress (ac);
9431 public override Expression CreateExpressionTree (ResolveContext ec)
9433 return ea.CreateExpressionTree (ec);
9436 public override bool ContainsEmitWithAwait ()
9438 return ea.ContainsEmitWithAwait ();
9441 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9443 return DoResolve (ec);
9446 protected override Expression DoResolve (ResolveContext ec)
9448 // dynamic is used per argument in ConvertExpressionToArrayIndex case
9450 ea.Arguments.Resolve (ec, out dynamic);
9452 var ac = ea.Expr.Type as ArrayContainer;
9453 int rank = ea.Arguments.Count;
9454 if (ac.Rank != rank) {
9455 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
9456 rank.ToString (), ac.Rank.ToString ());
9461 if (type.IsPointer && !ec.IsUnsafe) {
9462 UnsafeError (ec, ea.Location);
9465 foreach (Argument a in ea.Arguments) {
9466 if (a is NamedArgument)
9467 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
9469 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
9472 eclass = ExprClass.Variable;
9477 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
9479 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
9482 public override void FlowAnalysis (FlowAnalysisContext fc)
9484 ea.FlowAnalysis (fc);
9488 // Load the array arguments into the stack.
9490 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
9493 ea.Expr = ea.Expr.EmitToField (ec);
9494 } else if (duplicateArguments) {
9496 ec.Emit (OpCodes.Dup);
9498 var copy = new LocalTemporary (ea.Expr.Type);
9505 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
9506 if (dup_args != null)
9507 ea.Arguments = dup_args;
9510 public void Emit (EmitContext ec, bool leave_copy)
9512 var ac = ea.Expr.Type as ArrayContainer;
9515 ec.EmitLoadFromPtr (type);
9517 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
9518 LoadInstanceAndArguments (ec, false, true);
9521 LoadInstanceAndArguments (ec, false, false);
9522 ec.EmitArrayLoad (ac);
9526 ec.Emit (OpCodes.Dup);
9527 temp = new LocalTemporary (this.type);
9532 public override void Emit (EmitContext ec)
9537 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9539 var ac = (ArrayContainer) ea.Expr.Type;
9540 TypeSpec t = source.Type;
9542 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
9545 // When we are dealing with a struct, get the address of it to avoid value copy
9546 // Same cannot be done for reference type because array covariance and the
9547 // check in ldelema requires to specify the type of array element stored at the index
9549 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
9550 LoadInstanceAndArguments (ec, false, has_await_args.Value);
9552 if (has_await_args.Value) {
9553 if (source.ContainsEmitWithAwait ()) {
9554 source = source.EmitToField (ec);
9559 LoadInstanceAndArguments (ec, isCompound, false);
9564 ec.EmitArrayAddress (ac);
9567 ec.Emit (OpCodes.Dup);
9571 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
9573 if (has_await_args.Value) {
9574 if (source.ContainsEmitWithAwait ())
9575 source = source.EmitToField (ec);
9577 LoadInstanceAndArguments (ec, false, false);
9584 var lt = ea.Expr as LocalTemporary;
9590 ec.Emit (OpCodes.Dup);
9591 temp = new LocalTemporary (this.type);
9596 ec.EmitStoreFromPtr (t);
9598 ec.EmitArrayStore (ac);
9607 public override Expression EmitToField (EmitContext ec)
9610 // Have to be specialized for arrays to get access to
9611 // underlying element. Instead of another result copy we
9612 // need direct access to element
9616 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
9618 ea.Expr = ea.Expr.EmitToField (ec);
9622 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9624 #if NET_4_0 || MOBILE_DYNAMIC
9625 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9627 throw new NotImplementedException ();
9631 public override SLE.Expression MakeExpression (BuilderContext ctx)
9633 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9636 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
9638 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9639 return Arguments.MakeExpression (ea.Arguments, ctx);
9645 // Indexer access expression
9647 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
9649 IList<MemberSpec> indexers;
9650 Arguments arguments;
9651 TypeSpec queried_type;
9653 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
9654 : base (ea.Location)
9656 this.indexers = indexers;
9657 this.queried_type = queriedType;
9658 this.InstanceExpression = ea.Expr;
9659 this.arguments = ea.Arguments;
9664 protected override Arguments Arguments {
9673 protected override TypeSpec DeclaringType {
9675 return best_candidate.DeclaringType;
9679 public override bool IsInstance {
9685 public override bool IsStatic {
9691 public override string KindName {
9692 get { return "indexer"; }
9695 public override string Name {
9703 public override bool ContainsEmitWithAwait ()
9705 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
9708 public override Expression CreateExpressionTree (ResolveContext ec)
9710 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
9711 InstanceExpression.CreateExpressionTree (ec),
9712 new TypeOfMethod (Getter, loc));
9714 return CreateExpressionFactoryCall (ec, "Call", args);
9717 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9719 LocalTemporary await_source_arg = null;
9722 emitting_compound_assignment = true;
9723 if (source is DynamicExpressionStatement) {
9728 emitting_compound_assignment = false;
9730 if (has_await_arguments) {
9731 await_source_arg = new LocalTemporary (Type);
9732 await_source_arg.Store (ec);
9734 arguments.Add (new Argument (await_source_arg));
9737 temp = await_source_arg;
9740 has_await_arguments = false;
9745 ec.Emit (OpCodes.Dup);
9746 temp = new LocalTemporary (Type);
9752 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9753 source = source.EmitToField (ec);
9755 temp = new LocalTemporary (Type);
9762 arguments.Add (new Argument (source));
9765 var call = new CallEmitter ();
9766 call.InstanceExpression = InstanceExpression;
9767 if (arguments == null)
9768 call.InstanceExpressionOnStack = true;
9770 call.Emit (ec, Setter, arguments, loc);
9775 } else if (leave_copy) {
9779 if (await_source_arg != null) {
9780 await_source_arg.Release (ec);
9784 public override void FlowAnalysis (FlowAnalysisContext fc)
9786 // TODO: Check the order
9787 base.FlowAnalysis (fc);
9788 arguments.FlowAnalysis (fc);
9791 public override string GetSignatureForError ()
9793 return best_candidate.GetSignatureForError ();
9796 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9799 throw new NotSupportedException ();
9801 var value = new[] { source.MakeExpression (ctx) };
9802 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9803 #if NET_4_0 || MOBILE_DYNAMIC
9804 return SLE.Expression.Block (
9805 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9808 return args.First ();
9813 public override SLE.Expression MakeExpression (BuilderContext ctx)
9816 return base.MakeExpression (ctx);
9818 var args = Arguments.MakeExpression (arguments, ctx);
9819 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9823 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9825 if (best_candidate != null)
9828 eclass = ExprClass.IndexerAccess;
9831 arguments.Resolve (rc, out dynamic);
9833 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9836 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9837 res.BaseMembersProvider = this;
9838 res.InstanceQualifier = this;
9840 // TODO: Do I need 2 argument sets?
9841 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9842 if (best_candidate != null)
9843 type = res.BestCandidateReturnType;
9844 else if (!res.BestCandidateIsDynamic)
9849 // It has dynamic arguments
9852 Arguments args = new Arguments (arguments.Count + 1);
9854 rc.Report.Error (1972, loc,
9855 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9857 args.Add (new Argument (InstanceExpression));
9859 args.AddRange (arguments);
9861 best_candidate = null;
9862 return new DynamicIndexBinder (args, loc);
9866 // Try to avoid resolving left expression again
9868 if (right_side != null)
9869 ResolveInstanceExpression (rc, right_side);
9874 protected override void CloneTo (CloneContext clonectx, Expression t)
9876 IndexerExpr target = (IndexerExpr) t;
9878 if (arguments != null)
9879 target.arguments = arguments.Clone (clonectx);
9882 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9884 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9887 #region IBaseMembersProvider Members
9889 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9891 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9894 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9896 if (queried_type == member.DeclaringType)
9899 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9900 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9903 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9912 // A base access expression
9914 public class BaseThis : This
9916 public BaseThis (Location loc)
9921 public BaseThis (TypeSpec type, Location loc)
9925 eclass = ExprClass.Variable;
9930 public override string Name {
9938 public override Expression CreateExpressionTree (ResolveContext ec)
9940 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9941 return base.CreateExpressionTree (ec);
9944 public override void Emit (EmitContext ec)
9948 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
9949 var context_type = ec.CurrentType;
9950 ec.Emit (OpCodes.Ldobj, context_type);
9951 ec.Emit (OpCodes.Box, context_type);
9955 protected override void Error_ThisNotAvailable (ResolveContext ec)
9958 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9960 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9964 public override void ResolveBase (ResolveContext ec)
9966 base.ResolveBase (ec);
9967 type = ec.CurrentType.BaseType;
9970 public override object Accept (StructuralVisitor visitor)
9972 return visitor.Visit (this);
9977 /// This class exists solely to pass the Type around and to be a dummy
9978 /// that can be passed to the conversion functions (this is used by
9979 /// foreach implementation to typecast the object return value from
9980 /// get_Current into the proper type. All code has been generated and
9981 /// we only care about the side effect conversions to be performed
9983 /// This is also now used as a placeholder where a no-action expression
9984 /// is needed (the `New' class).
9986 public class EmptyExpression : Expression
9988 sealed class OutAccessExpression : EmptyExpression
9990 public OutAccessExpression (TypeSpec t)
9995 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9997 rc.Report.Error (206, right_side.Location,
9998 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
10004 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
10005 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
10006 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
10007 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
10008 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
10009 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
10010 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
10011 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
10013 public EmptyExpression (TypeSpec t)
10016 eclass = ExprClass.Value;
10017 loc = Location.Null;
10020 public override bool ContainsEmitWithAwait ()
10025 public override Expression CreateExpressionTree (ResolveContext ec)
10027 throw new NotSupportedException ("ET");
10030 protected override Expression DoResolve (ResolveContext ec)
10035 public override void Emit (EmitContext ec)
10037 // nothing, as we only exist to not do anything.
10040 public override void EmitSideEffect (EmitContext ec)
10044 public override object Accept (StructuralVisitor visitor)
10046 return visitor.Visit (this);
10050 sealed class EmptyAwaitExpression : EmptyExpression
10052 public EmptyAwaitExpression (TypeSpec type)
10057 public override bool ContainsEmitWithAwait ()
10064 // Empty statement expression
10066 public sealed class EmptyExpressionStatement : ExpressionStatement
10068 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
10070 private EmptyExpressionStatement ()
10072 loc = Location.Null;
10075 public override bool ContainsEmitWithAwait ()
10080 public override Expression CreateExpressionTree (ResolveContext ec)
10085 public override void EmitStatement (EmitContext ec)
10090 protected override Expression DoResolve (ResolveContext ec)
10092 eclass = ExprClass.Value;
10093 type = ec.BuiltinTypes.Object;
10097 public override void Emit (EmitContext ec)
10102 public override object Accept (StructuralVisitor visitor)
10104 return visitor.Visit (this);
10108 public class ErrorExpression : EmptyExpression
10110 public static readonly ErrorExpression Instance = new ErrorExpression ();
10112 private ErrorExpression ()
10113 : base (InternalType.ErrorType)
10117 public override Expression CreateExpressionTree (ResolveContext ec)
10122 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10127 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
10131 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
10135 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
10139 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
10143 public override object Accept (StructuralVisitor visitor)
10145 return visitor.Visit (this);
10149 public class UserCast : Expression {
10153 public UserCast (MethodSpec method, Expression source, Location l)
10155 if (source == null)
10156 throw new ArgumentNullException ("source");
10158 this.method = method;
10159 this.source = source;
10160 type = method.ReturnType;
10164 public Expression Source {
10170 public override bool ContainsEmitWithAwait ()
10172 return source.ContainsEmitWithAwait ();
10175 public override Expression CreateExpressionTree (ResolveContext ec)
10177 Arguments args = new Arguments (3);
10178 args.Add (new Argument (source.CreateExpressionTree (ec)));
10179 args.Add (new Argument (new TypeOf (type, loc)));
10180 args.Add (new Argument (new TypeOfMethod (method, loc)));
10181 return CreateExpressionFactoryCall (ec, "Convert", args);
10184 protected override Expression DoResolve (ResolveContext ec)
10186 ObsoleteAttribute oa = method.GetAttributeObsolete ();
10188 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
10190 eclass = ExprClass.Value;
10194 public override void Emit (EmitContext ec)
10197 ec.MarkCallEntry (loc);
10198 ec.Emit (OpCodes.Call, method);
10201 public override void FlowAnalysis (FlowAnalysisContext fc)
10203 source.FlowAnalysis (fc);
10206 public override string GetSignatureForError ()
10208 return TypeManager.CSharpSignature (method);
10211 public override SLE.Expression MakeExpression (BuilderContext ctx)
10214 return base.MakeExpression (ctx);
10216 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
10222 // Holds additional type specifiers like ?, *, []
10224 public class ComposedTypeSpecifier
10226 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
10228 public readonly int Dimension;
10229 public readonly Location Location;
10231 public ComposedTypeSpecifier (int specifier, Location loc)
10233 this.Dimension = specifier;
10234 this.Location = loc;
10238 public bool IsNullable {
10240 return Dimension == -1;
10244 public bool IsPointer {
10246 return Dimension == -2;
10250 public ComposedTypeSpecifier Next { get; set; }
10254 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
10256 return new ComposedTypeSpecifier (dimension, loc);
10259 public static ComposedTypeSpecifier CreateNullable (Location loc)
10261 return new ComposedTypeSpecifier (-1, loc);
10264 public static ComposedTypeSpecifier CreatePointer (Location loc)
10266 return new ComposedTypeSpecifier (-2, loc);
10269 public string GetSignatureForError ()
10274 ArrayContainer.GetPostfixSignature (Dimension);
10276 return Next != null ? s + Next.GetSignatureForError () : s;
10281 // This class is used to "construct" the type during a typecast
10282 // operation. Since the Type.GetType class in .NET can parse
10283 // the type specification, we just use this to construct the type
10284 // one bit at a time.
10286 public class ComposedCast : TypeExpr {
10287 FullNamedExpression left;
10288 ComposedTypeSpecifier spec;
10290 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
10293 throw new ArgumentNullException ("spec");
10297 this.loc = left.Location;
10300 public override TypeSpec ResolveAsType (IMemberContext ec)
10302 type = left.ResolveAsType (ec);
10306 eclass = ExprClass.Type;
10308 var single_spec = spec;
10310 if (single_spec.IsNullable) {
10311 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
10315 single_spec = single_spec.Next;
10316 } else if (single_spec.IsPointer) {
10317 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
10320 if (!ec.IsUnsafe) {
10321 UnsafeError (ec.Module.Compiler.Report, loc);
10325 type = PointerContainer.MakeType (ec.Module, type);
10326 single_spec = single_spec.Next;
10327 } while (single_spec != null && single_spec.IsPointer);
10330 if (single_spec != null && single_spec.Dimension > 0) {
10331 if (type.IsSpecialRuntimeType) {
10332 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
10333 } else if (type.IsStatic) {
10334 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
10335 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
10336 type.GetSignatureForError ());
10338 MakeArray (ec.Module, single_spec);
10345 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
10347 if (spec.Next != null)
10348 MakeArray (module, spec.Next);
10350 type = ArrayContainer.MakeType (module, type, spec.Dimension);
10353 public override string GetSignatureForError ()
10355 return left.GetSignatureForError () + spec.GetSignatureForError ();
10358 public override object Accept (StructuralVisitor visitor)
10360 return visitor.Visit (this);
10364 class FixedBufferPtr : Expression
10366 readonly Expression array;
10368 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
10370 this.type = array_type;
10371 this.array = array;
10375 public override bool ContainsEmitWithAwait ()
10377 throw new NotImplementedException ();
10380 public override Expression CreateExpressionTree (ResolveContext ec)
10382 Error_PointerInsideExpressionTree (ec);
10386 public override void Emit(EmitContext ec)
10391 protected override Expression DoResolve (ResolveContext ec)
10393 type = PointerContainer.MakeType (ec.Module, type);
10394 eclass = ExprClass.Value;
10401 // This class is used to represent the address of an array, used
10402 // only by the Fixed statement, this generates "&a [0]" construct
10403 // for fixed (char *pa = a)
10405 class ArrayPtr : FixedBufferPtr
10407 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
10408 base (array, array_type, l)
10412 public override void Emit (EmitContext ec)
10417 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
10422 // Encapsulates a conversion rules required for array indexes
10424 public class ArrayIndexCast : TypeCast
10426 public ArrayIndexCast (Expression expr, TypeSpec returnType)
10427 : base (expr, returnType)
10429 if (expr.Type == returnType) // int -> int
10430 throw new ArgumentException ("unnecessary array index conversion");
10433 public override Expression CreateExpressionTree (ResolveContext ec)
10435 using (ec.Set (ResolveContext.Options.CheckedScope)) {
10436 return base.CreateExpressionTree (ec);
10440 public override void Emit (EmitContext ec)
10444 switch (child.Type.BuiltinType) {
10445 case BuiltinTypeSpec.Type.UInt:
10446 ec.Emit (OpCodes.Conv_U);
10448 case BuiltinTypeSpec.Type.Long:
10449 ec.Emit (OpCodes.Conv_Ovf_I);
10451 case BuiltinTypeSpec.Type.ULong:
10452 ec.Emit (OpCodes.Conv_Ovf_I_Un);
10455 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
10461 // Implements the `stackalloc' keyword
10463 public class StackAlloc : Expression {
10468 public StackAlloc (Expression type, Expression count, Location l)
10471 this.count = count;
10475 public Expression TypeExpression {
10481 public Expression CountExpression {
10487 public override bool ContainsEmitWithAwait ()
10492 public override Expression CreateExpressionTree (ResolveContext ec)
10494 throw new NotSupportedException ("ET");
10497 protected override Expression DoResolve (ResolveContext ec)
10499 count = count.Resolve (ec);
10503 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
10504 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
10509 Constant c = count as Constant;
10510 if (c != null && c.IsNegative) {
10511 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
10514 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
10515 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
10518 otype = t.ResolveAsType (ec);
10522 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
10525 type = PointerContainer.MakeType (ec.Module, otype);
10526 eclass = ExprClass.Value;
10531 public override void Emit (EmitContext ec)
10533 int size = BuiltinTypeSpec.GetSize (otype);
10538 ec.Emit (OpCodes.Sizeof, otype);
10542 ec.Emit (OpCodes.Mul_Ovf_Un);
10543 ec.Emit (OpCodes.Localloc);
10546 protected override void CloneTo (CloneContext clonectx, Expression t)
10548 StackAlloc target = (StackAlloc) t;
10549 target.count = count.Clone (clonectx);
10550 target.t = t.Clone (clonectx);
10553 public override object Accept (StructuralVisitor visitor)
10555 return visitor.Visit (this);
10560 // An object initializer expression
10562 public class ElementInitializer : Assign
10564 public readonly string Name;
10566 public ElementInitializer (string name, Expression initializer, Location loc)
10567 : base (null, initializer, loc)
10572 protected override void CloneTo (CloneContext clonectx, Expression t)
10574 ElementInitializer target = (ElementInitializer) t;
10575 target.source = source.Clone (clonectx);
10578 public override Expression CreateExpressionTree (ResolveContext ec)
10580 Arguments args = new Arguments (2);
10581 FieldExpr fe = target as FieldExpr;
10583 args.Add (new Argument (fe.CreateTypeOfExpression ()));
10585 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
10588 Expression arg_expr;
10589 var cinit = source as CollectionOrObjectInitializers;
10590 if (cinit == null) {
10592 arg_expr = source.CreateExpressionTree (ec);
10594 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
10595 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
10598 args.Add (new Argument (arg_expr));
10599 return CreateExpressionFactoryCall (ec, mname, args);
10602 protected override Expression DoResolve (ResolveContext ec)
10604 if (source == null)
10605 return EmptyExpressionStatement.Instance;
10607 var t = ec.CurrentInitializerVariable.Type;
10608 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10609 Arguments args = new Arguments (1);
10610 args.Add (new Argument (ec.CurrentInitializerVariable));
10611 target = new DynamicMemberBinder (Name, args, loc);
10614 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10615 if (member == null) {
10616 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10618 if (member != null) {
10619 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
10620 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
10625 if (member == null) {
10626 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
10630 if (!(member is PropertyExpr || member is FieldExpr)) {
10631 ec.Report.Error (1913, loc,
10632 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
10633 member.GetSignatureForError ());
10638 var me = member as MemberExpr;
10640 ec.Report.Error (1914, loc,
10641 "Static field or property `{0}' cannot be assigned in an object initializer",
10642 me.GetSignatureForError ());
10646 me.InstanceExpression = ec.CurrentInitializerVariable;
10649 if (source is CollectionOrObjectInitializers) {
10650 Expression previous = ec.CurrentInitializerVariable;
10651 ec.CurrentInitializerVariable = target;
10652 source = source.Resolve (ec);
10653 ec.CurrentInitializerVariable = previous;
10654 if (source == null)
10657 eclass = source.eclass;
10658 type = source.Type;
10662 return base.DoResolve (ec);
10665 public override void EmitStatement (EmitContext ec)
10667 if (source is CollectionOrObjectInitializers)
10670 base.EmitStatement (ec);
10675 // A collection initializer expression
10677 class CollectionElementInitializer : Invocation
10679 public class ElementInitializerArgument : Argument
10681 public ElementInitializerArgument (Expression e)
10687 sealed class AddMemberAccess : MemberAccess
10689 public AddMemberAccess (Expression expr, Location loc)
10690 : base (expr, "Add", loc)
10694 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10696 if (TypeManager.HasElementType (type))
10699 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10703 public CollectionElementInitializer (Expression argument)
10704 : base (null, new Arguments (1))
10706 base.arguments.Add (new ElementInitializerArgument (argument));
10707 this.loc = argument.Location;
10710 public CollectionElementInitializer (List<Expression> arguments, Location loc)
10711 : base (null, new Arguments (arguments.Count))
10713 foreach (Expression e in arguments)
10714 base.arguments.Add (new ElementInitializerArgument (e));
10719 public CollectionElementInitializer (Location loc)
10720 : base (null, null)
10725 public override Expression CreateExpressionTree (ResolveContext ec)
10727 Arguments args = new Arguments (2);
10728 args.Add (new Argument (mg.CreateExpressionTree (ec)));
10730 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
10731 foreach (Argument a in arguments)
10732 expr_initializers.Add (a.CreateExpressionTree (ec));
10734 args.Add (new Argument (new ArrayCreation (
10735 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
10736 return CreateExpressionFactoryCall (ec, "ElementInit", args);
10739 protected override void CloneTo (CloneContext clonectx, Expression t)
10741 CollectionElementInitializer target = (CollectionElementInitializer) t;
10742 if (arguments != null)
10743 target.arguments = arguments.Clone (clonectx);
10746 protected override Expression DoResolve (ResolveContext ec)
10748 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
10750 return base.DoResolve (ec);
10755 // A block of object or collection initializers
10757 public class CollectionOrObjectInitializers : ExpressionStatement
10759 IList<Expression> initializers;
10760 bool is_collection_initialization;
10762 public CollectionOrObjectInitializers (Location loc)
10763 : this (new Expression[0], loc)
10767 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10769 this.initializers = initializers;
10773 public IList<Expression> Initializers {
10775 return initializers;
10779 public bool IsEmpty {
10781 return initializers.Count == 0;
10785 public bool IsCollectionInitializer {
10787 return is_collection_initialization;
10791 protected override void CloneTo (CloneContext clonectx, Expression target)
10793 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10795 t.initializers = new List<Expression> (initializers.Count);
10796 foreach (var e in initializers)
10797 t.initializers.Add (e.Clone (clonectx));
10800 public override bool ContainsEmitWithAwait ()
10802 foreach (var e in initializers) {
10803 if (e.ContainsEmitWithAwait ())
10810 public override Expression CreateExpressionTree (ResolveContext ec)
10812 return CreateExpressionTree (ec, false);
10815 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10817 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10818 foreach (Expression e in initializers) {
10819 Expression expr = e.CreateExpressionTree (ec);
10821 expr_initializers.Add (expr);
10825 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10827 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10830 protected override Expression DoResolve (ResolveContext ec)
10832 List<string> element_names = null;
10833 for (int i = 0; i < initializers.Count; ++i) {
10834 Expression initializer = initializers [i];
10835 ElementInitializer element_initializer = initializer as ElementInitializer;
10838 if (element_initializer != null) {
10839 element_names = new List<string> (initializers.Count);
10840 element_names.Add (element_initializer.Name);
10841 } else if (initializer is CompletingExpression){
10842 initializer.Resolve (ec);
10843 throw new InternalErrorException ("This line should never be reached");
10845 var t = ec.CurrentInitializerVariable.Type;
10846 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10847 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10848 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10849 "object initializer because type `{1}' does not implement `{2}' interface",
10850 ec.CurrentInitializerVariable.GetSignatureForError (),
10851 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10852 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10855 is_collection_initialization = true;
10858 if (is_collection_initialization != (element_initializer == null)) {
10859 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10860 is_collection_initialization ? "collection initializer" : "object initializer");
10864 if (!is_collection_initialization) {
10865 if (element_names.Contains (element_initializer.Name)) {
10866 ec.Report.Error (1912, element_initializer.Location,
10867 "An object initializer includes more than one member `{0}' initialization",
10868 element_initializer.Name);
10870 element_names.Add (element_initializer.Name);
10875 Expression e = initializer.Resolve (ec);
10876 if (e == EmptyExpressionStatement.Instance)
10877 initializers.RemoveAt (i--);
10879 initializers [i] = e;
10882 type = ec.CurrentInitializerVariable.Type;
10883 if (is_collection_initialization) {
10884 if (TypeManager.HasElementType (type)) {
10885 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10886 type.GetSignatureForError ());
10890 eclass = ExprClass.Variable;
10894 public override void Emit (EmitContext ec)
10896 EmitStatement (ec);
10899 public override void EmitStatement (EmitContext ec)
10901 foreach (ExpressionStatement e in initializers) {
10902 // TODO: need location region
10903 ec.Mark (e.Location);
10904 e.EmitStatement (ec);
10908 public override void FlowAnalysis (FlowAnalysisContext fc)
10910 foreach (var initializer in initializers)
10911 initializer.FlowAnalysis (fc);
10916 // New expression with element/object initializers
10918 public class NewInitialize : New
10921 // This class serves as a proxy for variable initializer target instances.
10922 // A real variable is assigned later when we resolve left side of an
10925 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10927 NewInitialize new_instance;
10929 public InitializerTargetExpression (NewInitialize newInstance)
10931 this.type = newInstance.type;
10932 this.loc = newInstance.loc;
10933 this.eclass = newInstance.eclass;
10934 this.new_instance = newInstance;
10937 public override bool ContainsEmitWithAwait ()
10942 public override Expression CreateExpressionTree (ResolveContext ec)
10944 // Should not be reached
10945 throw new NotSupportedException ("ET");
10948 protected override Expression DoResolve (ResolveContext ec)
10953 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10958 public override void Emit (EmitContext ec)
10960 Expression e = (Expression) new_instance.instance;
10964 public override Expression EmitToField (EmitContext ec)
10966 return (Expression) new_instance.instance;
10969 #region IMemoryLocation Members
10971 public void AddressOf (EmitContext ec, AddressOp mode)
10973 new_instance.instance.AddressOf (ec, mode);
10979 CollectionOrObjectInitializers initializers;
10980 IMemoryLocation instance;
10981 DynamicExpressionStatement dynamic;
10983 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10984 : base (requested_type, arguments, l)
10986 this.initializers = initializers;
10989 public CollectionOrObjectInitializers Initializers {
10991 return initializers;
10995 protected override void CloneTo (CloneContext clonectx, Expression t)
10997 base.CloneTo (clonectx, t);
10999 NewInitialize target = (NewInitialize) t;
11000 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
11003 public override bool ContainsEmitWithAwait ()
11005 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
11008 public override Expression CreateExpressionTree (ResolveContext ec)
11010 Arguments args = new Arguments (2);
11011 args.Add (new Argument (base.CreateExpressionTree (ec)));
11012 if (!initializers.IsEmpty)
11013 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
11015 return CreateExpressionFactoryCall (ec,
11016 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
11020 protected override Expression DoResolve (ResolveContext ec)
11022 Expression e = base.DoResolve (ec);
11026 if (type.IsDelegate) {
11027 ec.Report.Error (1958, Initializers.Location,
11028 "Object and collection initializers cannot be used to instantiate a delegate");
11031 Expression previous = ec.CurrentInitializerVariable;
11032 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
11033 initializers.Resolve (ec);
11034 ec.CurrentInitializerVariable = previous;
11036 dynamic = e as DynamicExpressionStatement;
11037 if (dynamic != null)
11043 public override bool Emit (EmitContext ec, IMemoryLocation target)
11045 bool left_on_stack;
11046 if (dynamic != null) {
11048 left_on_stack = true;
11050 left_on_stack = base.Emit (ec, target);
11053 if (initializers.IsEmpty)
11054 return left_on_stack;
11056 LocalTemporary temp = null;
11058 instance = target as LocalTemporary;
11060 if (instance == null) {
11061 if (!left_on_stack) {
11062 VariableReference vr = target as VariableReference;
11064 // FIXME: This still does not work correctly for pre-set variables
11065 if (vr != null && vr.IsRef)
11066 target.AddressOf (ec, AddressOp.Load);
11068 ((Expression) target).Emit (ec);
11069 left_on_stack = true;
11072 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
11073 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
11075 temp = new LocalTemporary (type);
11080 if (left_on_stack && temp != null)
11083 initializers.Emit (ec);
11085 if (left_on_stack) {
11086 if (temp != null) {
11090 ((Expression) instance).Emit (ec);
11094 return left_on_stack;
11097 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
11099 instance = base.EmitAddressOf (ec, Mode);
11101 if (!initializers.IsEmpty)
11102 initializers.Emit (ec);
11107 public override void FlowAnalysis (FlowAnalysisContext fc)
11109 base.FlowAnalysis (fc);
11110 initializers.FlowAnalysis (fc);
11113 public override object Accept (StructuralVisitor visitor)
11115 return visitor.Visit (this);
11119 public class NewAnonymousType : New
11121 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
11123 List<AnonymousTypeParameter> parameters;
11124 readonly TypeContainer parent;
11125 AnonymousTypeClass anonymous_type;
11127 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
11128 : base (null, null, loc)
11130 this.parameters = parameters;
11131 this.parent = parent;
11134 public List<AnonymousTypeParameter> Parameters {
11136 return this.parameters;
11140 protected override void CloneTo (CloneContext clonectx, Expression target)
11142 if (parameters == null)
11145 NewAnonymousType t = (NewAnonymousType) target;
11146 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
11147 foreach (AnonymousTypeParameter atp in parameters)
11148 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
11151 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
11153 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
11157 type = AnonymousTypeClass.Create (parent, parameters, loc);
11161 int errors = ec.Report.Errors;
11162 type.CreateContainer ();
11163 type.DefineContainer ();
11165 if ((ec.Report.Errors - errors) == 0) {
11166 parent.Module.AddAnonymousType (type);
11172 public override Expression CreateExpressionTree (ResolveContext ec)
11174 if (parameters == null)
11175 return base.CreateExpressionTree (ec);
11177 var init = new ArrayInitializer (parameters.Count, loc);
11178 foreach (var m in anonymous_type.Members) {
11179 var p = m as Property;
11181 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
11184 var ctor_args = new ArrayInitializer (arguments.Count, loc);
11185 foreach (Argument a in arguments)
11186 ctor_args.Add (a.CreateExpressionTree (ec));
11188 Arguments args = new Arguments (3);
11189 args.Add (new Argument (new TypeOfMethod (method, loc)));
11190 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
11191 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
11193 return CreateExpressionFactoryCall (ec, "New", args);
11196 protected override Expression DoResolve (ResolveContext ec)
11198 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
11199 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
11203 if (parameters == null) {
11204 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
11205 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
11206 return base.DoResolve (ec);
11209 bool error = false;
11210 arguments = new Arguments (parameters.Count);
11211 var t_args = new TypeSpec [parameters.Count];
11212 for (int i = 0; i < parameters.Count; ++i) {
11213 Expression e = parameters [i].Resolve (ec);
11219 arguments.Add (new Argument (e));
11220 t_args [i] = e.Type;
11226 anonymous_type = CreateAnonymousType (ec, parameters);
11227 if (anonymous_type == null)
11230 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
11231 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
11232 eclass = ExprClass.Value;
11236 public override object Accept (StructuralVisitor visitor)
11238 return visitor.Visit (this);
11242 public class AnonymousTypeParameter : ShimExpression
11244 public readonly string Name;
11246 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
11247 : base (initializer)
11253 public AnonymousTypeParameter (Parameter parameter)
11254 : base (new SimpleName (parameter.Name, parameter.Location))
11256 this.Name = parameter.Name;
11257 this.loc = parameter.Location;
11260 public override bool Equals (object o)
11262 AnonymousTypeParameter other = o as AnonymousTypeParameter;
11263 return other != null && Name == other.Name;
11266 public override int GetHashCode ()
11268 return Name.GetHashCode ();
11271 protected override Expression DoResolve (ResolveContext ec)
11273 Expression e = expr.Resolve (ec);
11277 if (e.eclass == ExprClass.MethodGroup) {
11278 Error_InvalidInitializer (ec, e.ExprClassName);
11283 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
11284 Error_InvalidInitializer (ec, type.GetSignatureForError ());
11291 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
11293 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
11294 Name, initializer);