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 override void FlowAnalysis (FlowAnalysisContext fc)
582 if (Oper == Operator.AddressOf) {
583 var vr = Expr as VariableReference;
584 if (vr != null && vr.VariableInfo != null)
585 fc.SetVariableAssigned (vr.VariableInfo);
590 Expr.FlowAnalysis (fc);
592 if (Oper == Operator.LogicalNot) {
593 var temp = fc.DefiniteAssignmentOnTrue;
594 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
595 fc.DefiniteAssignmentOnFalse = temp;
600 // Converts operator to System.Linq.Expressions.ExpressionType enum name
602 string GetOperatorExpressionTypeName ()
605 case Operator.OnesComplement:
606 return "OnesComplement";
607 case Operator.LogicalNot:
609 case Operator.UnaryNegation:
611 case Operator.UnaryPlus:
614 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
618 static bool IsFloat (TypeSpec t)
620 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
624 // Returns a stringified representation of the Operator
626 public static string OperName (Operator oper)
629 case Operator.UnaryPlus:
631 case Operator.UnaryNegation:
633 case Operator.LogicalNot:
635 case Operator.OnesComplement:
637 case Operator.AddressOf:
641 throw new NotImplementedException (oper.ToString ());
644 public override SLE.Expression MakeExpression (BuilderContext ctx)
646 var expr = Expr.MakeExpression (ctx);
647 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
650 case Operator.UnaryNegation:
651 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
652 case Operator.LogicalNot:
653 return SLE.Expression.Not (expr);
654 #if NET_4_0 || MONODROID
655 case Operator.OnesComplement:
656 return SLE.Expression.OnesComplement (expr);
659 throw new NotImplementedException (Oper.ToString ());
663 Expression ResolveAddressOf (ResolveContext ec)
666 UnsafeError (ec, loc);
668 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
669 if (Expr == null || Expr.eclass != ExprClass.Variable) {
670 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
674 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
678 IVariableReference vr = Expr as IVariableReference;
681 is_fixed = vr.IsFixed;
682 vr.SetHasAddressTaken ();
685 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
688 IFixedExpression fe = Expr as IFixedExpression;
689 is_fixed = fe != null && fe.IsFixed;
692 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
693 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
696 type = PointerContainer.MakeType (ec.Module, Expr.Type);
697 eclass = ExprClass.Value;
701 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
703 expr = DoNumericPromotion (rc, Oper, expr);
704 TypeSpec expr_type = expr.Type;
705 foreach (TypeSpec t in predefined) {
713 // Perform user-operator overload resolution
715 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
717 CSharp.Operator.OpType op_type;
719 case Operator.LogicalNot:
720 op_type = CSharp.Operator.OpType.LogicalNot; break;
721 case Operator.OnesComplement:
722 op_type = CSharp.Operator.OpType.OnesComplement; break;
723 case Operator.UnaryNegation:
724 op_type = CSharp.Operator.OpType.UnaryNegation; break;
725 case Operator.UnaryPlus:
726 op_type = CSharp.Operator.OpType.UnaryPlus; break;
728 throw new InternalErrorException (Oper.ToString ());
731 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
735 Arguments args = new Arguments (1);
736 args.Add (new Argument (expr));
738 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
739 var oper = res.ResolveOperator (ec, ref args);
744 Expr = args [0].Expr;
745 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
749 // Unary user type overload resolution
751 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
753 Expression best_expr = ResolveUserOperator (ec, expr);
754 if (best_expr != null)
757 foreach (TypeSpec t in predefined) {
758 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
759 if (oper_expr == null)
762 if (oper_expr == ErrorExpression.Instance)
766 // decimal type is predefined but has user-operators
768 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
769 oper_expr = ResolveUserType (ec, oper_expr, predefined);
771 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
773 if (oper_expr == null)
776 if (best_expr == null) {
777 best_expr = oper_expr;
781 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
783 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
784 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
785 OperName (Oper), expr.Type.GetSignatureForError ());
787 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
794 best_expr = oper_expr;
797 if (best_expr == null)
801 // HACK: Decimal user-operator is included in standard operators
803 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
807 type = best_expr.Type;
811 protected override void CloneTo (CloneContext clonectx, Expression t)
813 Unary target = (Unary) t;
815 target.Expr = Expr.Clone (clonectx);
818 public override object Accept (StructuralVisitor visitor)
820 return visitor.Visit (this);
826 // Unary operators are turned into Indirection expressions
827 // after semantic analysis (this is so we can take the address
828 // of an indirection).
830 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
832 LocalTemporary temporary;
835 public Indirection (Expression expr, Location l)
841 public Expression Expr {
847 public bool IsFixed {
851 public override Location StartLocation {
853 return expr.StartLocation;
857 protected override void CloneTo (CloneContext clonectx, Expression t)
859 Indirection target = (Indirection) t;
860 target.expr = expr.Clone (clonectx);
863 public override bool ContainsEmitWithAwait ()
865 throw new NotImplementedException ();
868 public override Expression CreateExpressionTree (ResolveContext ec)
870 Error_PointerInsideExpressionTree (ec);
874 public override void Emit (EmitContext ec)
879 ec.EmitLoadFromPtr (Type);
882 public void Emit (EmitContext ec, bool leave_copy)
886 ec.Emit (OpCodes.Dup);
887 temporary = new LocalTemporary (expr.Type);
888 temporary.Store (ec);
892 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
894 prepared = isCompound;
899 ec.Emit (OpCodes.Dup);
903 ec.Emit (OpCodes.Dup);
904 temporary = new LocalTemporary (source.Type);
905 temporary.Store (ec);
908 ec.EmitStoreFromPtr (type);
910 if (temporary != null) {
912 temporary.Release (ec);
916 public void AddressOf (EmitContext ec, AddressOp Mode)
921 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
923 return DoResolve (ec);
926 protected override Expression DoResolve (ResolveContext ec)
928 expr = expr.Resolve (ec);
933 UnsafeError (ec, loc);
935 var pc = expr.Type as PointerContainer;
938 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
944 if (type.Kind == MemberKind.Void) {
945 Error_VoidPointerOperation (ec);
949 eclass = ExprClass.Variable;
953 public override object Accept (StructuralVisitor visitor)
955 return visitor.Visit (this);
960 /// Unary Mutator expressions (pre and post ++ and --)
964 /// UnaryMutator implements ++ and -- expressions. It derives from
965 /// ExpressionStatement becuase the pre/post increment/decrement
966 /// operators can be used in a statement context.
968 /// FIXME: Idea, we could split this up in two classes, one simpler
969 /// for the common case, and one with the extra fields for more complex
970 /// classes (indexers require temporary access; overloaded require method)
973 public class UnaryMutator : ExpressionStatement
975 class DynamicPostMutator : Expression, IAssignMethod
980 public DynamicPostMutator (Expression expr)
983 this.type = expr.Type;
984 this.loc = expr.Location;
987 public override Expression CreateExpressionTree (ResolveContext ec)
989 throw new NotImplementedException ("ET");
992 protected override Expression DoResolve (ResolveContext rc)
994 eclass = expr.eclass;
998 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1000 expr.DoResolveLValue (ec, right_side);
1001 return DoResolve (ec);
1004 public override void Emit (EmitContext ec)
1009 public void Emit (EmitContext ec, bool leave_copy)
1011 throw new NotImplementedException ();
1015 // Emits target assignment using unmodified source value
1017 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1020 // Allocate temporary variable to keep original value before it's modified
1022 temp = new LocalTemporary (type);
1026 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1037 public enum Mode : byte {
1044 PreDecrement = IsDecrement,
1045 PostIncrement = IsPost,
1046 PostDecrement = IsPost | IsDecrement
1050 bool is_expr, recurse;
1052 protected Expression expr;
1054 // Holds the real operation
1055 Expression operation;
1057 public UnaryMutator (Mode m, Expression e, Location loc)
1064 public Mode UnaryMutatorMode {
1070 public Expression Expr {
1076 public override Location StartLocation {
1078 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1082 public override bool ContainsEmitWithAwait ()
1084 return expr.ContainsEmitWithAwait ();
1087 public override Expression CreateExpressionTree (ResolveContext ec)
1089 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1092 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1095 // Predefined ++ and -- operators exist for the following types:
1096 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1098 return new TypeSpec[] {
1114 protected override Expression DoResolve (ResolveContext ec)
1116 expr = expr.Resolve (ec);
1121 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1123 // Handle postfix unary operators using local
1124 // temporary variable
1126 if ((mode & Mode.IsPost) != 0)
1127 expr = new DynamicPostMutator (expr);
1129 Arguments args = new Arguments (1);
1130 args.Add (new Argument (expr));
1131 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1134 if (expr.Type.IsNullableType)
1135 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1137 return DoResolveOperation (ec);
1140 protected Expression DoResolveOperation (ResolveContext ec)
1142 eclass = ExprClass.Value;
1145 if (expr is RuntimeValueExpression) {
1148 // Use itself at the top of the stack
1149 operation = new EmptyExpression (type);
1153 // The operand of the prefix/postfix increment decrement operators
1154 // should be an expression that is classified as a variable,
1155 // a property access or an indexer access
1157 // TODO: Move to parser, expr is ATypeNameExpression
1158 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1159 expr = expr.ResolveLValue (ec, expr);
1161 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1165 // Step 1: Try to find a user operator, it has priority over predefined ones
1167 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1168 var methods = MemberCache.GetUserOperator (type, user_op, false);
1170 if (methods != null) {
1171 Arguments args = new Arguments (1);
1172 args.Add (new Argument (expr));
1174 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1175 var method = res.ResolveOperator (ec, ref args);
1179 args[0].Expr = operation;
1180 operation = new UserOperatorCall (method, args, null, loc);
1181 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1186 // Step 2: Try predefined types
1189 Expression source = null;
1190 bool primitive_type;
1193 // Predefined without user conversion first for speed-up
1195 // Predefined ++ and -- operators exist for the following types:
1196 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1198 switch (type.BuiltinType) {
1199 case BuiltinTypeSpec.Type.Byte:
1200 case BuiltinTypeSpec.Type.SByte:
1201 case BuiltinTypeSpec.Type.Short:
1202 case BuiltinTypeSpec.Type.UShort:
1203 case BuiltinTypeSpec.Type.Int:
1204 case BuiltinTypeSpec.Type.UInt:
1205 case BuiltinTypeSpec.Type.Long:
1206 case BuiltinTypeSpec.Type.ULong:
1207 case BuiltinTypeSpec.Type.Char:
1208 case BuiltinTypeSpec.Type.Float:
1209 case BuiltinTypeSpec.Type.Double:
1210 case BuiltinTypeSpec.Type.Decimal:
1212 primitive_type = true;
1215 primitive_type = false;
1217 // ++/-- on pointer variables of all types except void*
1218 if (type.IsPointer) {
1219 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1220 Error_VoidPointerOperation (ec);
1226 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1227 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1229 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1230 if (source != null) {
1236 // ++/-- on enum types
1237 if (source == null && type.IsEnum)
1240 if (source == null) {
1241 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1248 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1249 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1250 operation = new Binary (op, source, one);
1251 operation = operation.Resolve (ec);
1252 if (operation == null)
1253 throw new NotImplementedException ("should not be reached");
1255 if (operation.Type != type) {
1257 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1259 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1265 void EmitCode (EmitContext ec, bool is_expr)
1268 this.is_expr = is_expr;
1269 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1272 public override void Emit (EmitContext ec)
1275 // We use recurse to allow ourselfs to be the source
1276 // of an assignment. This little hack prevents us from
1277 // having to allocate another expression
1280 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1288 EmitCode (ec, true);
1291 protected virtual void EmitOperation (EmitContext ec)
1293 operation.Emit (ec);
1296 public override void EmitStatement (EmitContext ec)
1298 EmitCode (ec, false);
1301 public override void FlowAnalysis (FlowAnalysisContext fc)
1303 expr.FlowAnalysis (fc);
1307 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1309 string GetOperatorExpressionTypeName ()
1311 return IsDecrement ? "Decrement" : "Increment";
1315 get { return (mode & Mode.IsDecrement) != 0; }
1319 #if NET_4_0 || MONODROID
1320 public override SLE.Expression MakeExpression (BuilderContext ctx)
1322 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1323 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1324 return SLE.Expression.Assign (target, source);
1328 protected override void CloneTo (CloneContext clonectx, Expression t)
1330 UnaryMutator target = (UnaryMutator) t;
1332 target.expr = expr.Clone (clonectx);
1335 public override object Accept (StructuralVisitor visitor)
1337 return visitor.Visit (this);
1343 // Base class for the `is' and `as' operators
1345 public abstract class Probe : Expression
1347 public Expression ProbeType;
1348 protected Expression expr;
1349 protected TypeSpec probe_type_expr;
1351 protected Probe (Expression expr, Expression probe_type, Location l)
1353 ProbeType = probe_type;
1358 public Expression Expr {
1364 public override bool ContainsEmitWithAwait ()
1366 return expr.ContainsEmitWithAwait ();
1369 protected override Expression DoResolve (ResolveContext ec)
1371 probe_type_expr = ProbeType.ResolveAsType (ec);
1372 if (probe_type_expr == null)
1375 expr = expr.Resolve (ec);
1379 if (probe_type_expr.IsStatic) {
1380 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1384 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1385 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1390 if (expr.Type == InternalType.AnonymousMethod) {
1391 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1399 public override void FlowAnalysis (FlowAnalysisContext fc)
1401 expr.FlowAnalysis (fc);
1404 protected abstract string OperatorName { get; }
1406 protected override void CloneTo (CloneContext clonectx, Expression t)
1408 Probe target = (Probe) t;
1410 target.expr = expr.Clone (clonectx);
1411 target.ProbeType = ProbeType.Clone (clonectx);
1417 /// Implementation of the `is' operator.
1419 public class Is : Probe
1421 Nullable.Unwrap expr_unwrap;
1423 public Is (Expression expr, Expression probe_type, Location l)
1424 : base (expr, probe_type, l)
1428 protected override string OperatorName {
1429 get { return "is"; }
1432 public override Expression CreateExpressionTree (ResolveContext ec)
1434 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1435 expr.CreateExpressionTree (ec),
1436 new TypeOf (probe_type_expr, loc));
1438 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1441 public override void Emit (EmitContext ec)
1443 if (expr_unwrap != null) {
1444 expr_unwrap.EmitCheck (ec);
1450 // Only to make verifier happy
1451 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1452 ec.Emit (OpCodes.Box, expr.Type);
1454 ec.Emit (OpCodes.Isinst, probe_type_expr);
1456 ec.Emit (OpCodes.Cgt_Un);
1459 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1461 if (expr_unwrap != null) {
1462 expr_unwrap.EmitCheck (ec);
1465 ec.Emit (OpCodes.Isinst, probe_type_expr);
1467 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1470 Expression CreateConstantResult (ResolveContext ec, bool result)
1473 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1474 probe_type_expr.GetSignatureForError ());
1476 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1477 probe_type_expr.GetSignatureForError ());
1479 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, result, loc), this);
1482 protected override Expression DoResolve (ResolveContext ec)
1484 if (base.DoResolve (ec) == null)
1487 TypeSpec d = expr.Type;
1488 bool d_is_nullable = false;
1491 // If E is a method group or the null literal, or if the type of E is a reference
1492 // type or a nullable type and the value of E is null, the result is false
1494 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1495 return CreateConstantResult (ec, false);
1497 if (d.IsNullableType) {
1498 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1499 if (!ut.IsGenericParameter) {
1501 d_is_nullable = true;
1505 type = ec.BuiltinTypes.Bool;
1506 eclass = ExprClass.Value;
1507 TypeSpec t = probe_type_expr;
1508 bool t_is_nullable = false;
1509 if (t.IsNullableType) {
1510 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1511 if (!ut.IsGenericParameter) {
1513 t_is_nullable = true;
1520 // D and T are the same value types but D can be null
1522 if (d_is_nullable && !t_is_nullable) {
1523 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1528 // The result is true if D and T are the same value types
1530 return CreateConstantResult (ec, true);
1533 var tp = d as TypeParameterSpec;
1535 return ResolveGenericParameter (ec, t, tp);
1538 // An unboxing conversion exists
1540 if (Convert.ExplicitReferenceConversionExists (d, t))
1544 // open generic type
1546 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1549 var tps = t as TypeParameterSpec;
1551 return ResolveGenericParameter (ec, d, tps);
1553 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1554 ec.Report.Warning (1981, 3, loc,
1555 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1556 OperatorName, t.GetSignatureForError ());
1559 if (TypeManager.IsGenericParameter (d))
1560 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1562 if (TypeSpec.IsValueType (d)) {
1563 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1564 if (d_is_nullable && !t_is_nullable) {
1565 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1569 return CreateConstantResult (ec, true);
1572 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1573 var c = expr as Constant;
1575 return CreateConstantResult (ec, !c.IsNull);
1578 // Do not optimize for imported type
1580 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1581 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1586 // Turn is check into simple null check for implicitly convertible reference types
1588 return ReducedExpression.Create (
1589 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1593 if (Convert.ExplicitReferenceConversionExists (d, t))
1597 // open generic type
1599 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1604 return CreateConstantResult (ec, false);
1607 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1609 if (t.IsReferenceType) {
1611 return CreateConstantResult (ec, false);
1614 if (expr.Type.IsGenericParameter) {
1615 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1616 return CreateConstantResult (ec, true);
1618 expr = new BoxedCast (expr, d);
1624 public override object Accept (StructuralVisitor visitor)
1626 return visitor.Visit (this);
1631 /// Implementation of the `as' operator.
1633 public class As : Probe {
1634 Expression resolved_type;
1636 public As (Expression expr, Expression probe_type, Location l)
1637 : base (expr, probe_type, l)
1641 protected override string OperatorName {
1642 get { return "as"; }
1645 public override Expression CreateExpressionTree (ResolveContext ec)
1647 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1648 expr.CreateExpressionTree (ec),
1649 new TypeOf (probe_type_expr, loc));
1651 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1654 public override void Emit (EmitContext ec)
1658 ec.Emit (OpCodes.Isinst, type);
1660 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1661 ec.Emit (OpCodes.Unbox_Any, type);
1664 protected override Expression DoResolve (ResolveContext ec)
1666 if (resolved_type == null) {
1667 resolved_type = base.DoResolve (ec);
1669 if (resolved_type == null)
1673 type = probe_type_expr;
1674 eclass = ExprClass.Value;
1675 TypeSpec etype = expr.Type;
1677 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1678 if (TypeManager.IsGenericParameter (type)) {
1679 ec.Report.Error (413, loc,
1680 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1681 probe_type_expr.GetSignatureForError ());
1683 ec.Report.Error (77, loc,
1684 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1685 type.GetSignatureForError ());
1690 if (expr.IsNull && type.IsNullableType) {
1691 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1694 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1695 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1699 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1701 e = EmptyCast.Create (e, type);
1702 return ReducedExpression.Create (e, this).Resolve (ec);
1705 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1706 if (TypeManager.IsGenericParameter (etype))
1707 expr = new BoxedCast (expr, etype);
1712 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1713 expr = new BoxedCast (expr, etype);
1717 if (etype != InternalType.ErrorType) {
1718 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1719 etype.GetSignatureForError (), type.GetSignatureForError ());
1725 public override object Accept (StructuralVisitor visitor)
1727 return visitor.Visit (this);
1732 // This represents a typecast in the source language.
1734 public class Cast : ShimExpression {
1735 Expression target_type;
1737 public Cast (Expression cast_type, Expression expr, Location loc)
1740 this.target_type = cast_type;
1744 public Expression TargetType {
1745 get { return target_type; }
1748 protected override Expression DoResolve (ResolveContext ec)
1750 expr = expr.Resolve (ec);
1754 type = target_type.ResolveAsType (ec);
1758 if (type.IsStatic) {
1759 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
1763 if (type.IsPointer && !ec.IsUnsafe) {
1764 UnsafeError (ec, loc);
1767 eclass = ExprClass.Value;
1769 Constant c = expr as Constant;
1771 c = c.Reduce (ec, type);
1776 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1778 return EmptyCast.Create (res, type);
1783 protected override void CloneTo (CloneContext clonectx, Expression t)
1785 Cast target = (Cast) t;
1787 target.target_type = target_type.Clone (clonectx);
1788 target.expr = expr.Clone (clonectx);
1791 public override object Accept (StructuralVisitor visitor)
1793 return visitor.Visit (this);
1797 public class ImplicitCast : ShimExpression
1801 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1804 this.loc = expr.Location;
1806 this.arrayAccess = arrayAccess;
1809 protected override Expression DoResolve (ResolveContext ec)
1811 expr = expr.Resolve (ec);
1816 expr = ConvertExpressionToArrayIndex (ec, expr);
1818 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1825 // C# 2.0 Default value expression
1827 public class DefaultValueExpression : Expression
1831 public DefaultValueExpression (Expression expr, Location loc)
1837 public Expression Expr {
1843 public override bool IsSideEffectFree {
1849 public override bool ContainsEmitWithAwait ()
1854 public override Expression CreateExpressionTree (ResolveContext ec)
1856 Arguments args = new Arguments (2);
1857 args.Add (new Argument (this));
1858 args.Add (new Argument (new TypeOf (type, loc)));
1859 return CreateExpressionFactoryCall (ec, "Constant", args);
1862 protected override Expression DoResolve (ResolveContext ec)
1864 type = expr.ResolveAsType (ec);
1868 if (type.IsStatic) {
1869 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1873 return new NullLiteral (Location).ConvertImplicitly (type);
1875 if (TypeSpec.IsReferenceType (type))
1876 return new NullConstant (type, loc);
1878 Constant c = New.Constantify (type, expr.Location);
1882 eclass = ExprClass.Variable;
1886 public override void Emit (EmitContext ec)
1888 LocalTemporary temp_storage = new LocalTemporary(type);
1890 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1891 ec.Emit(OpCodes.Initobj, type);
1892 temp_storage.Emit(ec);
1893 temp_storage.Release (ec);
1896 #if (NET_4_0 || MONODROID) && !STATIC
1897 public override SLE.Expression MakeExpression (BuilderContext ctx)
1899 return SLE.Expression.Default (type.GetMetaInfo ());
1903 protected override void CloneTo (CloneContext clonectx, Expression t)
1905 DefaultValueExpression target = (DefaultValueExpression) t;
1907 target.expr = expr.Clone (clonectx);
1910 public override object Accept (StructuralVisitor visitor)
1912 return visitor.Visit (this);
1917 /// Binary operators
1919 public class Binary : Expression, IDynamicBinder
1921 public class PredefinedOperator
1923 protected readonly TypeSpec left;
1924 protected readonly TypeSpec right;
1925 protected readonly TypeSpec left_unwrap;
1926 protected readonly TypeSpec right_unwrap;
1927 public readonly Operator OperatorsMask;
1928 public TypeSpec ReturnType;
1930 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1931 : this (ltype, rtype, op_mask, ltype)
1935 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1936 : this (type, type, op_mask, return_type)
1940 public PredefinedOperator (TypeSpec type, Operator op_mask)
1941 : this (type, type, op_mask, type)
1945 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1947 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1948 throw new InternalErrorException ("Only masked values can be used");
1950 if ((op_mask & Operator.NullableMask) != 0) {
1951 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
1952 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
1954 left_unwrap = ltype;
1955 right_unwrap = rtype;
1960 this.OperatorsMask = op_mask;
1961 this.ReturnType = return_type;
1964 public bool IsLifted {
1966 return (OperatorsMask & Operator.NullableMask) != 0;
1970 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
1974 var left_expr = b.left;
1975 var right_expr = b.right;
1977 b.type = ReturnType;
1980 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
1981 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1982 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1985 if (right_expr.IsNull) {
1986 if ((b.oper & Operator.EqualityMask) != 0) {
1987 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
1988 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
1989 } else if ((b.oper & Operator.BitwiseMask) != 0) {
1990 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
1991 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1993 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1994 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1996 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
1997 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1999 return b.CreateLiftedValueTypeResult (rc, left);
2001 } else if (left_expr.IsNull) {
2002 if ((b.oper & Operator.EqualityMask) != 0) {
2003 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2004 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2005 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2006 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2007 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2009 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2010 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2012 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2013 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2015 return b.CreateLiftedValueTypeResult (rc, right);
2021 // A user operators does not support multiple user conversions, but decimal type
2022 // is considered to be predefined type therefore we apply predefined operators rules
2023 // and then look for decimal user-operator implementation
2025 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2026 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2027 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2029 return b.ResolveUserOperator (rc, b.left, b.right);
2032 c = right_expr as Constant;
2034 if (c.IsDefaultValue) {
2038 // (expr + 0) to expr
2039 // (expr - 0) to expr
2040 // (bool? | false) to bool?
2042 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2043 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2044 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2045 return ReducedExpression.Create (b.left, b).Resolve (rc);
2049 // Optimizes (value &/&& 0) to 0
2051 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2052 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2053 return ReducedExpression.Create (side_effect, b);
2057 // Optimizes (bool? & true) to bool?
2059 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2060 return ReducedExpression.Create (b.left, b).Resolve (rc);
2064 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2065 return ReducedExpression.Create (b.left, b).Resolve (rc);
2067 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2068 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2072 c = b.left as Constant;
2074 if (c.IsDefaultValue) {
2078 // (0 + expr) to expr
2079 // (false | bool?) to bool?
2081 if (b.oper == Operator.Addition ||
2082 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2083 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2084 return ReducedExpression.Create (b.right, b).Resolve (rc);
2088 // Optimizes (false && expr) to false
2090 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2091 // No rhs side-effects
2092 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2093 return ReducedExpression.Create (c, b);
2097 // Optimizes (0 & value) to 0
2099 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2100 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2101 return ReducedExpression.Create (side_effect, b);
2105 // Optimizes (true & bool?) to bool?
2107 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2108 return ReducedExpression.Create (b.right, b).Resolve (rc);
2112 // Optimizes (true || expr) to true
2114 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2115 // No rhs side-effects
2116 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2117 return ReducedExpression.Create (c, b);
2121 if (b.oper == Operator.Multiply && c.IsOneInteger)
2122 return ReducedExpression.Create (b.right, b).Resolve (rc);
2126 var lifted = new Nullable.LiftedBinaryOperator (b);
2128 TypeSpec ltype, rtype;
2129 if (b.left.Type.IsNullableType) {
2130 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2131 ltype = left_unwrap;
2136 if (b.right.Type.IsNullableType) {
2137 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2138 rtype = right_unwrap;
2143 lifted.Left = b.left.IsNull ?
2145 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2147 lifted.Right = b.right.IsNull ?
2149 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2151 return lifted.Resolve (rc);
2154 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2155 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2160 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2163 // We are dealing with primitive types only
2165 return left == ltype && ltype == rtype;
2168 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2171 if (left == lexpr.Type && right == rexpr.Type)
2174 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2175 Convert.ImplicitConversionExists (ec, rexpr, right);
2178 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2180 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2181 return best_operator;
2183 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2187 if (left != null && best_operator.left != null) {
2188 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2192 // When second argument is same as the first one, the result is same
2194 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2195 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2198 if (result == 0 || result > 2)
2201 return result == 1 ? best_operator : this;
2205 sealed class PredefinedStringOperator : PredefinedOperator
2207 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2208 : base (type, type, op_mask, retType)
2212 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2213 : base (ltype, rtype, op_mask, retType)
2217 public override Expression ConvertResult (ResolveContext ec, Binary b)
2220 // Use original expression for nullable arguments
2222 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2224 b.left = unwrap.Original;
2226 unwrap = b.right as Nullable.Unwrap;
2228 b.right = unwrap.Original;
2230 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2231 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2234 // Start a new concat expression using converted expression
2236 return StringConcat.Create (ec, b.left, b.right, b.loc);
2240 sealed class PredefinedEqualityOperator : PredefinedOperator
2242 MethodSpec equal_method, inequal_method;
2244 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
2245 : base (arg, arg, Operator.EqualityMask, retType)
2249 public override Expression ConvertResult (ResolveContext ec, Binary b)
2251 b.type = ReturnType;
2253 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2254 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2256 Arguments args = new Arguments (2);
2257 args.Add (new Argument (b.left));
2258 args.Add (new Argument (b.right));
2261 if (b.oper == Operator.Equality) {
2262 if (equal_method == null) {
2263 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2264 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2265 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2266 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2268 throw new NotImplementedException (left.GetSignatureForError ());
2271 method = equal_method;
2273 if (inequal_method == null) {
2274 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2275 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2276 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2277 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2279 throw new NotImplementedException (left.GetSignatureForError ());
2282 method = inequal_method;
2285 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2289 class PredefinedPointerOperator : PredefinedOperator
2291 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2292 : base (ltype, rtype, op_mask)
2296 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2297 : base (ltype, rtype, op_mask, retType)
2301 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2302 : base (type, op_mask, return_type)
2306 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2309 if (!lexpr.Type.IsPointer)
2312 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2316 if (right == null) {
2317 if (!rexpr.Type.IsPointer)
2320 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2327 public override Expression ConvertResult (ResolveContext ec, Binary b)
2330 b.left = EmptyCast.Create (b.left, left);
2331 } else if (right != null) {
2332 b.right = EmptyCast.Create (b.right, right);
2335 TypeSpec r_type = ReturnType;
2336 Expression left_arg, right_arg;
2337 if (r_type == null) {
2340 right_arg = b.right;
2341 r_type = b.left.Type;
2345 r_type = b.right.Type;
2349 right_arg = b.right;
2352 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2357 public enum Operator {
2358 Multiply = 0 | ArithmeticMask,
2359 Division = 1 | ArithmeticMask,
2360 Modulus = 2 | ArithmeticMask,
2361 Addition = 3 | ArithmeticMask | AdditionMask,
2362 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2364 LeftShift = 5 | ShiftMask,
2365 RightShift = 6 | ShiftMask,
2367 LessThan = 7 | ComparisonMask | RelationalMask,
2368 GreaterThan = 8 | ComparisonMask | RelationalMask,
2369 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2370 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2371 Equality = 11 | ComparisonMask | EqualityMask,
2372 Inequality = 12 | ComparisonMask | EqualityMask,
2374 BitwiseAnd = 13 | BitwiseMask,
2375 ExclusiveOr = 14 | BitwiseMask,
2376 BitwiseOr = 15 | BitwiseMask,
2378 LogicalAnd = 16 | LogicalMask,
2379 LogicalOr = 17 | LogicalMask,
2384 ValuesOnlyMask = ArithmeticMask - 1,
2385 ArithmeticMask = 1 << 5,
2387 ComparisonMask = 1 << 7,
2388 EqualityMask = 1 << 8,
2389 BitwiseMask = 1 << 9,
2390 LogicalMask = 1 << 10,
2391 AdditionMask = 1 << 11,
2392 SubtractionMask = 1 << 12,
2393 RelationalMask = 1 << 13,
2395 DecomposedMask = 1 << 19,
2396 NullableMask = 1 << 20,
2406 readonly Operator oper;
2407 Expression left, right;
2409 ConvCast.Mode enum_conversion;
2411 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
2412 : this (oper, left, right)
2415 state |= State.Compound;
2418 public Binary (Operator oper, Expression left, Expression right)
2423 this.loc = left.Location;
2428 public bool IsCompound {
2430 return (state & State.Compound) != 0;
2434 public Operator Oper {
2440 public Expression Left {
2446 public Expression Right {
2452 public override Location StartLocation {
2454 return left.StartLocation;
2461 /// Returns a stringified representation of the Operator
2463 string OperName (Operator oper)
2467 case Operator.Multiply:
2470 case Operator.Division:
2473 case Operator.Modulus:
2476 case Operator.Addition:
2479 case Operator.Subtraction:
2482 case Operator.LeftShift:
2485 case Operator.RightShift:
2488 case Operator.LessThan:
2491 case Operator.GreaterThan:
2494 case Operator.LessThanOrEqual:
2497 case Operator.GreaterThanOrEqual:
2500 case Operator.Equality:
2503 case Operator.Inequality:
2506 case Operator.BitwiseAnd:
2509 case Operator.BitwiseOr:
2512 case Operator.ExclusiveOr:
2515 case Operator.LogicalOr:
2518 case Operator.LogicalAnd:
2522 s = oper.ToString ();
2532 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2534 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2537 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2539 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
2543 l = left.Type.GetSignatureForError ();
2544 r = right.Type.GetSignatureForError ();
2546 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2550 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2552 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2555 public override void FlowAnalysis (FlowAnalysisContext fc)
2557 if ((oper & Operator.LogicalMask) == 0) {
2558 left.FlowAnalysis (fc);
2559 right.FlowAnalysis (fc);
2564 // Optimized version when on-true/on-false data are not needed
2566 bool set_on_true_false;
2567 if (fc.DefiniteAssignmentOnTrue == null && fc.DefiniteAssignmentOnFalse == null) {
2568 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignment;
2569 set_on_true_false = false;
2571 set_on_true_false = true;
2574 left.FlowAnalysis (fc);
2575 var left_fc = fc.DefiniteAssignment;
2576 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
2577 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
2579 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
2580 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
2581 right.FlowAnalysis (fc);
2582 fc.DefiniteAssignment = left_fc;
2584 if (!set_on_true_false) {
2585 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue = null;
2589 if (oper == Operator.LogicalOr) {
2590 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue);
2591 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
2593 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
2594 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet (left_fc_onfalse);
2599 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2601 string GetOperatorExpressionTypeName ()
2604 case Operator.Addition:
2605 return IsCompound ? "AddAssign" : "Add";
2606 case Operator.BitwiseAnd:
2607 return IsCompound ? "AndAssign" : "And";
2608 case Operator.BitwiseOr:
2609 return IsCompound ? "OrAssign" : "Or";
2610 case Operator.Division:
2611 return IsCompound ? "DivideAssign" : "Divide";
2612 case Operator.ExclusiveOr:
2613 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2614 case Operator.Equality:
2616 case Operator.GreaterThan:
2617 return "GreaterThan";
2618 case Operator.GreaterThanOrEqual:
2619 return "GreaterThanOrEqual";
2620 case Operator.Inequality:
2622 case Operator.LeftShift:
2623 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2624 case Operator.LessThan:
2626 case Operator.LessThanOrEqual:
2627 return "LessThanOrEqual";
2628 case Operator.LogicalAnd:
2630 case Operator.LogicalOr:
2632 case Operator.Modulus:
2633 return IsCompound ? "ModuloAssign" : "Modulo";
2634 case Operator.Multiply:
2635 return IsCompound ? "MultiplyAssign" : "Multiply";
2636 case Operator.RightShift:
2637 return IsCompound ? "RightShiftAssign" : "RightShift";
2638 case Operator.Subtraction:
2639 return IsCompound ? "SubtractAssign" : "Subtract";
2641 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2645 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2648 case Operator.Addition:
2649 return CSharp.Operator.OpType.Addition;
2650 case Operator.BitwiseAnd:
2651 case Operator.LogicalAnd:
2652 return CSharp.Operator.OpType.BitwiseAnd;
2653 case Operator.BitwiseOr:
2654 case Operator.LogicalOr:
2655 return CSharp.Operator.OpType.BitwiseOr;
2656 case Operator.Division:
2657 return CSharp.Operator.OpType.Division;
2658 case Operator.Equality:
2659 return CSharp.Operator.OpType.Equality;
2660 case Operator.ExclusiveOr:
2661 return CSharp.Operator.OpType.ExclusiveOr;
2662 case Operator.GreaterThan:
2663 return CSharp.Operator.OpType.GreaterThan;
2664 case Operator.GreaterThanOrEqual:
2665 return CSharp.Operator.OpType.GreaterThanOrEqual;
2666 case Operator.Inequality:
2667 return CSharp.Operator.OpType.Inequality;
2668 case Operator.LeftShift:
2669 return CSharp.Operator.OpType.LeftShift;
2670 case Operator.LessThan:
2671 return CSharp.Operator.OpType.LessThan;
2672 case Operator.LessThanOrEqual:
2673 return CSharp.Operator.OpType.LessThanOrEqual;
2674 case Operator.Modulus:
2675 return CSharp.Operator.OpType.Modulus;
2676 case Operator.Multiply:
2677 return CSharp.Operator.OpType.Multiply;
2678 case Operator.RightShift:
2679 return CSharp.Operator.OpType.RightShift;
2680 case Operator.Subtraction:
2681 return CSharp.Operator.OpType.Subtraction;
2683 throw new InternalErrorException (op.ToString ());
2687 public override bool ContainsEmitWithAwait ()
2689 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2692 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
2697 case Operator.Multiply:
2698 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2699 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2700 opcode = OpCodes.Mul_Ovf;
2701 else if (!IsFloat (l))
2702 opcode = OpCodes.Mul_Ovf_Un;
2704 opcode = OpCodes.Mul;
2706 opcode = OpCodes.Mul;
2710 case Operator.Division:
2712 opcode = OpCodes.Div_Un;
2714 opcode = OpCodes.Div;
2717 case Operator.Modulus:
2719 opcode = OpCodes.Rem_Un;
2721 opcode = OpCodes.Rem;
2724 case Operator.Addition:
2725 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2726 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2727 opcode = OpCodes.Add_Ovf;
2728 else if (!IsFloat (l))
2729 opcode = OpCodes.Add_Ovf_Un;
2731 opcode = OpCodes.Add;
2733 opcode = OpCodes.Add;
2736 case Operator.Subtraction:
2737 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2738 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2739 opcode = OpCodes.Sub_Ovf;
2740 else if (!IsFloat (l))
2741 opcode = OpCodes.Sub_Ovf_Un;
2743 opcode = OpCodes.Sub;
2745 opcode = OpCodes.Sub;
2748 case Operator.RightShift:
2749 if (!(right is IntConstant)) {
2750 ec.EmitInt (GetShiftMask (l));
2751 ec.Emit (OpCodes.And);
2755 opcode = OpCodes.Shr_Un;
2757 opcode = OpCodes.Shr;
2760 case Operator.LeftShift:
2761 if (!(right is IntConstant)) {
2762 ec.EmitInt (GetShiftMask (l));
2763 ec.Emit (OpCodes.And);
2766 opcode = OpCodes.Shl;
2769 case Operator.Equality:
2770 opcode = OpCodes.Ceq;
2773 case Operator.Inequality:
2774 ec.Emit (OpCodes.Ceq);
2777 opcode = OpCodes.Ceq;
2780 case Operator.LessThan:
2782 opcode = OpCodes.Clt_Un;
2784 opcode = OpCodes.Clt;
2787 case Operator.GreaterThan:
2789 opcode = OpCodes.Cgt_Un;
2791 opcode = OpCodes.Cgt;
2794 case Operator.LessThanOrEqual:
2795 if (IsUnsigned (l) || IsFloat (l))
2796 ec.Emit (OpCodes.Cgt_Un);
2798 ec.Emit (OpCodes.Cgt);
2801 opcode = OpCodes.Ceq;
2804 case Operator.GreaterThanOrEqual:
2805 if (IsUnsigned (l) || IsFloat (l))
2806 ec.Emit (OpCodes.Clt_Un);
2808 ec.Emit (OpCodes.Clt);
2812 opcode = OpCodes.Ceq;
2815 case Operator.BitwiseOr:
2816 opcode = OpCodes.Or;
2819 case Operator.BitwiseAnd:
2820 opcode = OpCodes.And;
2823 case Operator.ExclusiveOr:
2824 opcode = OpCodes.Xor;
2828 throw new InternalErrorException (oper.ToString ());
2834 static int GetShiftMask (TypeSpec type)
2836 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
2839 static bool IsUnsigned (TypeSpec t)
2841 switch (t.BuiltinType) {
2842 case BuiltinTypeSpec.Type.Char:
2843 case BuiltinTypeSpec.Type.UInt:
2844 case BuiltinTypeSpec.Type.ULong:
2845 case BuiltinTypeSpec.Type.UShort:
2846 case BuiltinTypeSpec.Type.Byte:
2853 static bool IsFloat (TypeSpec t)
2855 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2858 public Expression ResolveOperator (ResolveContext rc)
2860 eclass = ExprClass.Value;
2862 TypeSpec l = left.Type;
2863 TypeSpec r = right.Type;
2865 bool primitives_only = false;
2868 // Handles predefined primitive types
2870 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
2871 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
2872 if ((oper & Operator.ShiftMask) == 0) {
2873 if (!DoBinaryOperatorPromotion (rc))
2876 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
2880 if (l.IsPointer || r.IsPointer)
2881 return ResolveOperatorPointer (rc, l, r);
2884 expr = ResolveUserOperator (rc, left, right);
2889 bool lenum = l.IsEnum;
2890 bool renum = r.IsEnum;
2891 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2895 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2896 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
2901 if ((oper & Operator.BitwiseMask) != 0) {
2902 expr = EmptyCast.Create (expr, type);
2903 AddEnumResultCast (type);
2905 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
2906 expr = OptimizeAndOperation (expr);
2910 left = ConvertEnumOperandToUnderlyingType (rc, left);
2911 right = ConvertEnumOperandToUnderlyingType (rc, right);
2914 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
2915 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2919 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
2922 // We cannot break here there is also Enum + String possible match
2923 // which is not ambiguous with predefined enum operators
2926 left = ConvertEnumOperandToUnderlyingType (rc, left);
2927 right = ConvertEnumOperandToUnderlyingType (rc, right);
2931 } else if (l.IsDelegate || r.IsDelegate) {
2935 expr = ResolveOperatorDelegate (rc, l, r);
2937 // TODO: Can this be ambiguous
2945 // Equality operators are more complicated
2947 if ((oper & Operator.EqualityMask) != 0) {
2948 return ResolveEquality (rc, l, r, primitives_only);
2951 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
2955 if (primitives_only)
2959 // Lifted operators have lower priority
2961 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
2964 static bool IsEnumOrNullableEnum (TypeSpec type)
2966 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
2970 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2971 // if 'left' is not an enumeration constant, create one from the type of 'right'
2972 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
2975 case Operator.BitwiseOr:
2976 case Operator.BitwiseAnd:
2977 case Operator.ExclusiveOr:
2978 case Operator.Equality:
2979 case Operator.Inequality:
2980 case Operator.LessThan:
2981 case Operator.LessThanOrEqual:
2982 case Operator.GreaterThan:
2983 case Operator.GreaterThanOrEqual:
2984 if (left.Type.IsEnum)
2987 if (left.IsZeroInteger)
2988 return left.Reduce (ec, right.Type);
2992 case Operator.Addition:
2993 case Operator.Subtraction:
2996 case Operator.Multiply:
2997 case Operator.Division:
2998 case Operator.Modulus:
2999 case Operator.LeftShift:
3000 case Operator.RightShift:
3001 if (right.Type.IsEnum || left.Type.IsEnum)
3010 // The `|' operator used on types which were extended is dangerous
3012 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3014 OpcodeCast lcast = left as OpcodeCast;
3015 if (lcast != null) {
3016 if (IsUnsigned (lcast.UnderlyingType))
3020 OpcodeCast rcast = right as OpcodeCast;
3021 if (rcast != null) {
3022 if (IsUnsigned (rcast.UnderlyingType))
3026 if (lcast == null && rcast == null)
3029 // FIXME: consider constants
3031 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3032 ec.Report.Warning (675, 3, loc,
3033 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3034 ltype.GetSignatureForError ());
3037 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3039 return new PredefinedOperator[] {
3041 // Pointer arithmetic:
3043 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3044 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3045 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3046 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3048 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3049 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3050 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3051 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3054 // T* operator + (int y, T* x);
3055 // T* operator + (uint y, T *x);
3056 // T* operator + (long y, T *x);
3057 // T* operator + (ulong y, T *x);
3059 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3060 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3061 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3062 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3065 // long operator - (T* x, T *y)
3067 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3071 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3073 TypeSpec bool_type = types.Bool;
3076 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3077 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3078 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3079 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3080 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3081 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3082 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3084 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3085 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3086 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3087 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3088 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3089 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3090 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3092 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3093 // Remaining string operators are in lifted tables
3095 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3097 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3098 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3099 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3103 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3105 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3106 if (nullable == null)
3107 return new PredefinedOperator [0];
3109 var types = module.Compiler.BuiltinTypes;
3110 var bool_type = types.Bool;
3112 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3113 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3114 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3115 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3116 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3117 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3118 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3119 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3122 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3123 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3124 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3125 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3126 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3127 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3128 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3130 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3131 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3132 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3133 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3134 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3135 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3136 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3138 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3140 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3141 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3142 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3145 // Not strictly lifted but need to be in second group otherwise expressions like
3146 // int + null would resolve to +(object, string) instead of +(int?, int?)
3148 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3149 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3154 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3156 TypeSpec bool_type = types.Bool;
3159 new PredefinedEqualityOperator (types.String, bool_type),
3160 new PredefinedEqualityOperator (types.Delegate, bool_type),
3161 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3162 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3163 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3164 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3165 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3166 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3167 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3168 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3172 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3174 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3176 if (nullable == null)
3177 return new PredefinedOperator [0];
3179 var types = module.Compiler.BuiltinTypes;
3180 var bool_type = types.Bool;
3181 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3182 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3183 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3184 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3185 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3186 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3187 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3188 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3191 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3192 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3193 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3194 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3195 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3196 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3197 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3198 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3203 // 7.2.6.2 Binary numeric promotions
3205 bool DoBinaryOperatorPromotion (ResolveContext rc)
3207 TypeSpec ltype = left.Type;
3208 if (ltype.IsNullableType) {
3209 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
3213 // This is numeric promotion code only
3215 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
3218 TypeSpec rtype = right.Type;
3219 if (rtype.IsNullableType) {
3220 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
3223 var lb = ltype.BuiltinType;
3224 var rb = rtype.BuiltinType;
3228 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
3229 type = rc.BuiltinTypes.Decimal;
3230 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
3231 type = rc.BuiltinTypes.Double;
3232 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
3233 type = rc.BuiltinTypes.Float;
3234 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
3235 type = rc.BuiltinTypes.ULong;
3237 if (IsSignedType (lb)) {
3238 expr = ConvertSignedConstant (left, type);
3242 } else if (IsSignedType (rb)) {
3243 expr = ConvertSignedConstant (right, type);
3249 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
3250 type = rc.BuiltinTypes.Long;
3251 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
3252 type = rc.BuiltinTypes.UInt;
3254 if (IsSignedType (lb)) {
3255 expr = ConvertSignedConstant (left, type);
3257 type = rc.BuiltinTypes.Long;
3258 } else if (IsSignedType (rb)) {
3259 expr = ConvertSignedConstant (right, type);
3261 type = rc.BuiltinTypes.Long;
3264 type = rc.BuiltinTypes.Int;
3267 if (ltype != type) {
3268 expr = PromoteExpression (rc, left, type);
3275 if (rtype != type) {
3276 expr = PromoteExpression (rc, right, type);
3286 static bool IsSignedType (BuiltinTypeSpec.Type type)
3289 case BuiltinTypeSpec.Type.Int:
3290 case BuiltinTypeSpec.Type.Short:
3291 case BuiltinTypeSpec.Type.SByte:
3292 case BuiltinTypeSpec.Type.Long:
3299 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
3301 var c = expr as Constant;
3305 return c.ConvertImplicitly (type);
3308 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
3310 if (expr.Type.IsNullableType) {
3311 return Convert.ImplicitConversionStandard (rc, expr,
3312 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
3315 var c = expr as Constant;
3317 return c.ConvertImplicitly (type);
3319 return Convert.ImplicitNumericConversion (expr, type);
3322 protected override Expression DoResolve (ResolveContext ec)
3327 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
3328 left = ((ParenthesizedExpression) left).Expr;
3329 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
3333 if (left.eclass == ExprClass.Type) {
3334 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
3338 left = left.Resolve (ec);
3343 right = right.Resolve (ec);
3347 Constant lc = left as Constant;
3348 Constant rc = right as Constant;
3350 // The conversion rules are ignored in enum context but why
3351 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
3352 lc = EnumLiftUp (ec, lc, rc);
3354 rc = EnumLiftUp (ec, rc, lc);
3357 if (rc != null && lc != null) {
3358 int prev_e = ec.Report.Errors;
3359 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
3360 if (e != null || ec.Report.Errors != prev_e)
3364 // Comparison warnings
3365 if ((oper & Operator.ComparisonMask) != 0) {
3366 if (left.Equals (right)) {
3367 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
3369 CheckOutOfRangeComparison (ec, lc, right.Type);
3370 CheckOutOfRangeComparison (ec, rc, left.Type);
3373 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3374 return DoResolveDynamic (ec);
3376 return DoResolveCore (ec, left, right);
3379 Expression DoResolveDynamic (ResolveContext rc)
3382 var rt = right.Type;
3383 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
3384 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
3385 Error_OperatorCannotBeApplied (rc, left, right);
3392 // Special handling for logical boolean operators which require rhs not to be
3393 // evaluated based on lhs value
3395 if ((oper & Operator.LogicalMask) != 0) {
3396 Expression cond_left, cond_right, expr;
3398 args = new Arguments (2);
3400 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3401 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
3403 var cond_args = new Arguments (1);
3404 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
3407 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
3408 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
3410 left = temp.CreateReferenceExpression (rc, loc);
3411 if (oper == Operator.LogicalAnd) {
3412 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
3415 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
3419 args.Add (new Argument (left));
3420 args.Add (new Argument (right));
3421 cond_right = new DynamicExpressionStatement (this, args, loc);
3423 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
3425 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
3426 args.Add (new Argument (right));
3427 right = new DynamicExpressionStatement (this, args, loc);
3430 // bool && dynamic => (temp = left) ? temp && right : temp;
3431 // bool || dynamic => (temp = left) ? temp : temp || right;
3433 if (oper == Operator.LogicalAnd) {
3435 cond_right = temp.CreateReferenceExpression (rc, loc);
3437 cond_left = temp.CreateReferenceExpression (rc, loc);
3441 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
3444 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
3447 args = new Arguments (2);
3448 args.Add (new Argument (left));
3449 args.Add (new Argument (right));
3450 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
3453 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3455 Expression expr = ResolveOperator (ec);
3457 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3459 if (left == null || right == null)
3460 throw new InternalErrorException ("Invalid conversion");
3462 if (oper == Operator.BitwiseOr)
3463 CheckBitwiseOrOnSignExtended (ec);
3468 public override SLE.Expression MakeExpression (BuilderContext ctx)
3470 return MakeExpression (ctx, left, right);
3473 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
3475 var le = left.MakeExpression (ctx);
3476 var re = right.MakeExpression (ctx);
3477 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3480 case Operator.Addition:
3481 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3482 case Operator.BitwiseAnd:
3483 return SLE.Expression.And (le, re);
3484 case Operator.BitwiseOr:
3485 return SLE.Expression.Or (le, re);
3486 case Operator.Division:
3487 return SLE.Expression.Divide (le, re);
3488 case Operator.Equality:
3489 return SLE.Expression.Equal (le, re);
3490 case Operator.ExclusiveOr:
3491 return SLE.Expression.ExclusiveOr (le, re);
3492 case Operator.GreaterThan:
3493 return SLE.Expression.GreaterThan (le, re);
3494 case Operator.GreaterThanOrEqual:
3495 return SLE.Expression.GreaterThanOrEqual (le, re);
3496 case Operator.Inequality:
3497 return SLE.Expression.NotEqual (le, re);
3498 case Operator.LeftShift:
3499 return SLE.Expression.LeftShift (le, re);
3500 case Operator.LessThan:
3501 return SLE.Expression.LessThan (le, re);
3502 case Operator.LessThanOrEqual:
3503 return SLE.Expression.LessThanOrEqual (le, re);
3504 case Operator.LogicalAnd:
3505 return SLE.Expression.AndAlso (le, re);
3506 case Operator.LogicalOr:
3507 return SLE.Expression.OrElse (le, re);
3508 case Operator.Modulus:
3509 return SLE.Expression.Modulo (le, re);
3510 case Operator.Multiply:
3511 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3512 case Operator.RightShift:
3513 return SLE.Expression.RightShift (le, re);
3514 case Operator.Subtraction:
3515 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3517 throw new NotImplementedException (oper.ToString ());
3522 // D operator + (D x, D y)
3523 // D operator - (D x, D y)
3525 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3527 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3529 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3530 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3535 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3536 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3546 MethodSpec method = null;
3547 Arguments args = new Arguments (2);
3548 args.Add (new Argument (left));
3549 args.Add (new Argument (right));
3551 if (oper == Operator.Addition) {
3552 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3553 } else if (oper == Operator.Subtraction) {
3554 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3558 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3560 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
3561 return new ClassCast (expr, l);
3565 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
3567 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3570 // bool operator == (E x, E y);
3571 // bool operator != (E x, E y);
3572 // bool operator < (E x, E y);
3573 // bool operator > (E x, E y);
3574 // bool operator <= (E x, E y);
3575 // bool operator >= (E x, E y);
3577 // E operator & (E x, E y);
3578 // E operator | (E x, E y);
3579 // E operator ^ (E x, E y);
3582 if ((oper & Operator.ComparisonMask) != 0) {
3583 type = rc.BuiltinTypes.Bool;
3589 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3595 if (ltype == rtype) {
3599 var lifted = new Nullable.LiftedBinaryOperator (this);
3601 lifted.Right = right;
3602 return lifted.Resolve (rc);
3605 if (renum && !ltype.IsNullableType) {
3606 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
3611 } else if (lenum && !rtype.IsNullableType) {
3612 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
3620 // Now try lifted version of predefined operator
3622 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
3623 if (nullable_type != null) {
3624 if (renum && !ltype.IsNullableType) {
3625 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
3627 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3630 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3633 if ((oper & Operator.BitwiseMask) != 0)
3637 if ((oper & Operator.BitwiseMask) != 0)
3638 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3640 return CreateLiftedValueTypeResult (rc, rtype);
3644 var lifted = new Nullable.LiftedBinaryOperator (this);
3646 lifted.Right = right;
3647 return lifted.Resolve (rc);
3649 } else if (lenum && !rtype.IsNullableType) {
3650 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
3652 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3655 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3658 if ((oper & Operator.BitwiseMask) != 0)
3662 if ((oper & Operator.BitwiseMask) != 0)
3663 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3665 return CreateLiftedValueTypeResult (rc, ltype);
3669 var lifted = new Nullable.LiftedBinaryOperator (this);
3671 lifted.Right = expr;
3672 return lifted.Resolve (rc);
3674 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
3676 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3677 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
3679 if ((oper & Operator.RelationalMask) != 0)
3680 return CreateLiftedValueTypeResult (rc, rtype);
3682 if ((oper & Operator.BitwiseMask) != 0)
3683 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3685 // Equality operators are valid between E? and null
3688 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
3694 var lifted = new Nullable.LiftedBinaryOperator (this);
3696 lifted.Right = right;
3697 return lifted.Resolve (rc);
3699 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
3701 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3702 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
3704 if ((oper & Operator.RelationalMask) != 0)
3705 return CreateLiftedValueTypeResult (rc, ltype);
3707 if ((oper & Operator.BitwiseMask) != 0)
3708 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3710 // Equality operators are valid between E? and null
3713 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
3719 var lifted = new Nullable.LiftedBinaryOperator (this);
3721 lifted.Right = expr;
3722 return lifted.Resolve (rc);
3730 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr)
3732 TypeSpec underlying_type;
3733 if (expr.Type.IsNullableType) {
3734 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
3736 underlying_type = EnumSpec.GetUnderlyingType (nt);
3738 underlying_type = nt;
3739 } else if (expr.Type.IsEnum) {
3740 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
3742 underlying_type = expr.Type;
3745 switch (underlying_type.BuiltinType) {
3746 case BuiltinTypeSpec.Type.SByte:
3747 case BuiltinTypeSpec.Type.Byte:
3748 case BuiltinTypeSpec.Type.Short:
3749 case BuiltinTypeSpec.Type.UShort:
3750 underlying_type = rc.BuiltinTypes.Int;
3754 if (expr.Type.IsNullableType)
3755 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
3757 if (expr.Type == underlying_type)
3760 return EmptyCast.Create (expr, underlying_type);
3763 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3766 // U operator - (E e, E f)
3767 // E operator - (E e, U x) // Internal decomposition operator
3768 // E operator - (U x, E e) // Internal decomposition operator
3770 // E operator + (E e, U x)
3771 // E operator + (U x, E e)
3780 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3786 if (!enum_type.IsNullableType) {
3787 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
3789 if (oper == Operator.Subtraction)
3790 expr = ConvertEnumSubtractionResult (rc, expr);
3792 expr = ConvertEnumAdditionalResult (expr, enum_type);
3794 AddEnumResultCast (expr.Type);
3799 enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
3802 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
3804 if (oper == Operator.Subtraction)
3805 expr = ConvertEnumSubtractionResult (rc, expr);
3807 expr = ConvertEnumAdditionalResult (expr, enum_type);
3809 AddEnumResultCast (expr.Type);
3815 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
3817 return EmptyCast.Create (expr, enumType);
3820 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
3823 // Enumeration subtraction has different result type based on
3826 TypeSpec result_type;
3827 if (left.Type == right.Type) {
3828 var c = right as EnumConstant;
3829 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
3831 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
3832 // E which is not what expressions E - 1 or 0 - E return
3834 result_type = left.Type;
3836 result_type = left.Type.IsNullableType ?
3837 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
3838 EnumSpec.GetUnderlyingType (left.Type);
3841 if (IsEnumOrNullableEnum (left.Type)) {
3842 result_type = left.Type;
3844 result_type = right.Type;
3847 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
3848 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
3851 return EmptyCast.Create (expr, result_type);
3854 void AddEnumResultCast (TypeSpec type)
3856 if (type.IsNullableType)
3857 type = Nullable.NullableInfo.GetUnderlyingType (type);
3860 type = EnumSpec.GetUnderlyingType (type);
3862 switch (type.BuiltinType) {
3863 case BuiltinTypeSpec.Type.SByte:
3864 enum_conversion = ConvCast.Mode.I4_I1;
3866 case BuiltinTypeSpec.Type.Byte:
3867 enum_conversion = ConvCast.Mode.I4_U1;
3869 case BuiltinTypeSpec.Type.Short:
3870 enum_conversion = ConvCast.Mode.I4_I2;
3872 case BuiltinTypeSpec.Type.UShort:
3873 enum_conversion = ConvCast.Mode.I4_U2;
3879 // Equality operators rules
3881 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
3884 type = ec.BuiltinTypes.Bool;
3885 bool no_arg_conv = false;
3887 if (!primitives_only) {
3890 // a, Both operands are reference-type values or the value null
3891 // b, One operand is a value of type T where T is a type-parameter and
3892 // the other operand is the value null. Furthermore T does not have the
3893 // value type constraint
3895 // LAMESPEC: Very confusing details in the specification, basically any
3896 // reference like type-parameter is allowed
3898 var tparam_l = l as TypeParameterSpec;
3899 var tparam_r = r as TypeParameterSpec;
3900 if (tparam_l != null) {
3901 if (right is NullLiteral) {
3902 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3905 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3909 if (!tparam_l.IsReferenceType)
3912 l = tparam_l.GetEffectiveBase ();
3913 left = new BoxedCast (left, l);
3914 } else if (left is NullLiteral && tparam_r == null) {
3915 if (TypeSpec.IsReferenceType (r))
3918 if (r.Kind == MemberKind.InternalCompilerType)
3922 if (tparam_r != null) {
3923 if (left is NullLiteral) {
3924 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3927 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3931 if (!tparam_r.IsReferenceType)
3934 r = tparam_r.GetEffectiveBase ();
3935 right = new BoxedCast (right, r);
3936 } else if (right is NullLiteral) {
3937 if (TypeSpec.IsReferenceType (l))
3940 if (l.Kind == MemberKind.InternalCompilerType)
3945 // LAMESPEC: method groups can be compared when they convert to other side delegate
3948 if (right.eclass == ExprClass.MethodGroup) {
3949 result = Convert.ImplicitConversion (ec, right, l, loc);
3955 } else if (r.IsDelegate && l != r) {
3958 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3959 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3966 no_arg_conv = l == r && !l.IsStruct;
3971 // bool operator != (string a, string b)
3972 // bool operator == (string a, string b)
3974 // bool operator != (Delegate a, Delegate b)
3975 // bool operator == (Delegate a, Delegate b)
3977 // bool operator != (bool a, bool b)
3978 // bool operator == (bool a, bool b)
3980 // LAMESPEC: Reference equality comparison can apply to value/reference types when
3981 // they implement an implicit conversion to any of types above. This does
3982 // not apply when both operands are of same reference type
3984 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3985 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
3990 // Now try lifted version of predefined operators
3992 if (no_arg_conv && !l.IsNullableType) {
3994 // Optimizes cases which won't match
3997 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4003 // The == and != operators permit one operand to be a value of a nullable
4004 // type and the other to be the null literal, even if no predefined or user-defined
4005 // operator (in unlifted or lifted form) exists for the operation.
4007 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4008 var lifted = new Nullable.LiftedBinaryOperator (this);
4010 lifted.Right = right;
4011 return lifted.Resolve (ec);
4016 // bool operator != (object a, object b)
4017 // bool operator == (object a, object b)
4019 // An explicit reference conversion exists from the
4020 // type of either operand to the type of the other operand.
4023 // Optimize common path
4025 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4028 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4029 !Convert.ExplicitReferenceConversionExists (r, l))
4032 // Reject allowed explicit conversions like int->object
4033 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4036 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4037 ec.Report.Warning (253, 2, loc,
4038 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4039 l.GetSignatureForError ());
4041 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4042 ec.Report.Warning (252, 2, loc,
4043 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4044 r.GetSignatureForError ());
4050 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4053 // bool operator == (void* x, void* y);
4054 // bool operator != (void* x, void* y);
4055 // bool operator < (void* x, void* y);
4056 // bool operator > (void* x, void* y);
4057 // bool operator <= (void* x, void* y);
4058 // bool operator >= (void* x, void* y);
4060 if ((oper & Operator.ComparisonMask) != 0) {
4063 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4070 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4076 type = ec.BuiltinTypes.Bool;
4080 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4084 // Build-in operators method overloading
4086 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4088 PredefinedOperator best_operator = null;
4089 TypeSpec l = left.Type;
4090 TypeSpec r = right.Type;
4091 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4093 foreach (PredefinedOperator po in operators) {
4094 if ((po.OperatorsMask & oper_mask) == 0)
4097 if (primitives_only) {
4098 if (!po.IsPrimitiveApplicable (l, r))
4101 if (!po.IsApplicable (ec, left, right))
4105 if (best_operator == null) {
4107 if (primitives_only)
4113 best_operator = po.ResolveBetterOperator (ec, best_operator);
4115 if (best_operator == null) {
4116 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4117 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4124 if (best_operator == null)
4127 return best_operator.ConvertResult (ec, this);
4131 // Optimize & constant expressions with 0 value
4133 Expression OptimizeAndOperation (Expression expr)
4135 Constant rc = right as Constant;
4136 Constant lc = left as Constant;
4137 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4139 // The result is a constant with side-effect
4141 Constant side_effect = rc == null ?
4142 new SideEffectConstant (lc, right, loc) :
4143 new SideEffectConstant (rc, left, loc);
4145 return ReducedExpression.Create (side_effect, expr);
4152 // Value types can be compared with the null literal because of the lifting
4153 // language rules. However the result is always true or false.
4155 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4157 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4158 type = rc.BuiltinTypes.Bool;
4162 // FIXME: Handle side effect constants
4163 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4165 if ((Oper & Operator.EqualityMask) != 0) {
4166 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4167 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4169 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4170 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4177 // Performs user-operator overloading
4179 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4181 Expression oper_expr;
4183 var op = ConvertBinaryToUserOperator (oper);
4185 if (l.IsNullableType)
4186 l = Nullable.NullableInfo.GetUnderlyingType (l);
4188 if (r.IsNullableType)
4189 r = Nullable.NullableInfo.GetUnderlyingType (r);
4191 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
4192 IList<MemberSpec> right_operators = null;
4195 right_operators = MemberCache.GetUserOperator (r, op, false);
4196 if (right_operators == null && left_operators == null)
4198 } else if (left_operators == null) {
4202 Arguments args = new Arguments (2);
4203 Argument larg = new Argument (left);
4205 Argument rarg = new Argument (right);
4209 // User-defined operator implementations always take precedence
4210 // over predefined operator implementations
4212 if (left_operators != null && right_operators != null) {
4213 left_operators = CombineUserOperators (left_operators, right_operators);
4214 } else if (right_operators != null) {
4215 left_operators = right_operators;
4218 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
4219 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
4221 var res = new OverloadResolver (left_operators, restr, loc);
4223 var oper_method = res.ResolveOperator (rc, ref args);
4224 if (oper_method == null) {
4226 // Logical && and || cannot be lifted
4228 if ((oper & Operator.LogicalMask) != 0)
4232 // Apply lifted user operators only for liftable types. Implicit conversion
4233 // to nullable types is not allowed
4235 if (!IsLiftedOperatorApplicable ())
4238 // TODO: Cache the result in module container
4239 var lifted_methods = CreateLiftedOperators (rc, left_operators);
4240 if (lifted_methods == null)
4243 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
4245 oper_method = res.ResolveOperator (rc, ref args);
4246 if (oper_method == null)
4249 MethodSpec best_original = null;
4250 foreach (MethodSpec ms in left_operators) {
4251 if (ms.MemberDefinition == oper_method.MemberDefinition) {
4257 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4259 // Expression trees use lifted notation in this case
4261 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
4262 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
4265 var ptypes = best_original.Parameters.Types;
4267 if (left.IsNull || right.IsNull) {
4269 // The lifted operator produces the value false if one or both operands are null for
4270 // relational operators.
4272 if ((oper & Operator.ComparisonMask) != 0) {
4274 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
4275 // because return type is actually bool
4277 // For some reason CSC does not report this warning for equality operators
4279 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
4282 // The lifted operator produces a null value if one or both operands are null
4284 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
4285 type = oper_method.ReturnType;
4286 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4290 type = oper_method.ReturnType;
4291 var lifted = new Nullable.LiftedBinaryOperator (this);
4292 lifted.UserOperator = best_original;
4294 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
4295 lifted.UnwrapLeft = new Nullable.Unwrap (left);
4298 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
4299 lifted.UnwrapRight = new Nullable.Unwrap (right);
4302 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
4303 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
4305 return lifted.Resolve (rc);
4308 if ((oper & Operator.LogicalMask) != 0) {
4309 // TODO: CreateExpressionTree is allocated every time
4310 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
4311 oper == Operator.LogicalAnd, loc).Resolve (rc);
4313 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
4316 this.left = larg.Expr;
4317 this.right = rarg.Expr;
4322 bool IsLiftedOperatorApplicable ()
4324 if (left.Type.IsNullableType) {
4325 if ((oper & Operator.EqualityMask) != 0)
4326 return !right.IsNull;
4331 if (right.Type.IsNullableType) {
4332 if ((oper & Operator.EqualityMask) != 0)
4333 return !left.IsNull;
4338 if (TypeSpec.IsValueType (left.Type))
4339 return right.IsNull;
4341 if (TypeSpec.IsValueType (right.Type))
4347 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
4349 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4350 if (nullable_type == null)
4354 // Lifted operators permit predefined and user-defined operators that operate
4355 // on non-nullable value types to also be used with nullable forms of those types.
4356 // Lifted operators are constructed from predefined and user-defined operators
4357 // that meet certain requirements
4359 List<MemberSpec> lifted = null;
4360 foreach (MethodSpec oper in operators) {
4362 if ((Oper & Operator.ComparisonMask) != 0) {
4364 // Result type must be of type bool for lifted comparison operators
4366 rt = oper.ReturnType;
4367 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
4370 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
4376 var ptypes = oper.Parameters.Types;
4377 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
4381 // LAMESPEC: I am not sure why but for equality operators to be lifted
4382 // both types have to match
4384 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
4388 lifted = new List<MemberSpec> ();
4391 // The lifted form is constructed by adding a single ? modifier to each operand and
4392 // result type except for comparison operators where return type is bool
4395 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
4397 var parameters = ParametersCompiled.CreateFullyResolved (
4398 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
4399 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
4401 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
4402 rt, parameters, oper.Modifiers);
4404 lifted.Add (lifted_op);
4411 // Merge two sets of user operators into one, they are mostly distinguish
4412 // except when they share base type and it contains an operator
4414 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
4416 var combined = new List<MemberSpec> (left.Count + right.Count);
4417 combined.AddRange (left);
4418 foreach (var r in right) {
4420 foreach (var l in left) {
4421 if (l.DeclaringType == r.DeclaringType) {
4434 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
4436 if (c is IntegralConstant || c is CharConstant) {
4438 c.ConvertExplicitly (true, type);
4439 } catch (OverflowException) {
4440 ec.Report.Warning (652, 2, loc,
4441 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
4442 type.GetSignatureForError ());
4448 /// EmitBranchable is called from Statement.EmitBoolExpression in the
4449 /// context of a conditional bool expression. This function will return
4450 /// false if it is was possible to use EmitBranchable, or true if it was.
4452 /// The expression's code is generated, and we will generate a branch to `target'
4453 /// if the resulting expression value is equal to isTrue
4455 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
4457 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4458 left = left.EmitToField (ec);
4460 if ((oper & Operator.LogicalMask) == 0) {
4461 right = right.EmitToField (ec);
4466 // This is more complicated than it looks, but its just to avoid
4467 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
4468 // but on top of that we want for == and != to use a special path
4469 // if we are comparing against null
4471 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
4472 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
4475 // put the constant on the rhs, for simplicity
4477 if (left is Constant) {
4478 Expression swap = right;
4484 // brtrue/brfalse works with native int only
4486 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
4487 left.EmitBranchable (ec, target, my_on_true);
4490 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
4491 // right is a boolean, and it's not 'false' => it is 'true'
4492 left.EmitBranchable (ec, target, !my_on_true);
4496 } else if (oper == Operator.LogicalAnd) {
4499 Label tests_end = ec.DefineLabel ();
4501 left.EmitBranchable (ec, tests_end, false);
4502 right.EmitBranchable (ec, target, true);
4503 ec.MarkLabel (tests_end);
4506 // This optimizes code like this
4507 // if (true && i > 4)
4509 if (!(left is Constant))
4510 left.EmitBranchable (ec, target, false);
4512 if (!(right is Constant))
4513 right.EmitBranchable (ec, target, false);
4518 } else if (oper == Operator.LogicalOr){
4520 left.EmitBranchable (ec, target, true);
4521 right.EmitBranchable (ec, target, true);
4524 Label tests_end = ec.DefineLabel ();
4525 left.EmitBranchable (ec, tests_end, true);
4526 right.EmitBranchable (ec, target, false);
4527 ec.MarkLabel (tests_end);
4532 } else if ((oper & Operator.ComparisonMask) == 0) {
4533 base.EmitBranchable (ec, target, on_true);
4540 TypeSpec t = left.Type;
4541 bool is_float = IsFloat (t);
4542 bool is_unsigned = is_float || IsUnsigned (t);
4545 case Operator.Equality:
4547 ec.Emit (OpCodes.Beq, target);
4549 ec.Emit (OpCodes.Bne_Un, target);
4552 case Operator.Inequality:
4554 ec.Emit (OpCodes.Bne_Un, target);
4556 ec.Emit (OpCodes.Beq, target);
4559 case Operator.LessThan:
4561 if (is_unsigned && !is_float)
4562 ec.Emit (OpCodes.Blt_Un, target);
4564 ec.Emit (OpCodes.Blt, target);
4567 ec.Emit (OpCodes.Bge_Un, target);
4569 ec.Emit (OpCodes.Bge, target);
4572 case Operator.GreaterThan:
4574 if (is_unsigned && !is_float)
4575 ec.Emit (OpCodes.Bgt_Un, target);
4577 ec.Emit (OpCodes.Bgt, target);
4580 ec.Emit (OpCodes.Ble_Un, target);
4582 ec.Emit (OpCodes.Ble, target);
4585 case Operator.LessThanOrEqual:
4587 if (is_unsigned && !is_float)
4588 ec.Emit (OpCodes.Ble_Un, target);
4590 ec.Emit (OpCodes.Ble, target);
4593 ec.Emit (OpCodes.Bgt_Un, target);
4595 ec.Emit (OpCodes.Bgt, target);
4599 case Operator.GreaterThanOrEqual:
4601 if (is_unsigned && !is_float)
4602 ec.Emit (OpCodes.Bge_Un, target);
4604 ec.Emit (OpCodes.Bge, target);
4607 ec.Emit (OpCodes.Blt_Un, target);
4609 ec.Emit (OpCodes.Blt, target);
4612 throw new InternalErrorException (oper.ToString ());
4616 public override void Emit (EmitContext ec)
4618 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4619 left = left.EmitToField (ec);
4621 if ((oper & Operator.LogicalMask) == 0) {
4622 right = right.EmitToField (ec);
4627 // Handle short-circuit operators differently
4630 if ((oper & Operator.LogicalMask) != 0) {
4631 Label load_result = ec.DefineLabel ();
4632 Label end = ec.DefineLabel ();
4634 bool is_or = oper == Operator.LogicalOr;
4635 left.EmitBranchable (ec, load_result, is_or);
4637 ec.Emit (OpCodes.Br_S, end);
4639 ec.MarkLabel (load_result);
4640 ec.EmitInt (is_or ? 1 : 0);
4646 // Optimize zero-based operations which cannot be optimized at expression level
4648 if (oper == Operator.Subtraction) {
4649 var lc = left as IntegralConstant;
4650 if (lc != null && lc.IsDefaultValue) {
4652 ec.Emit (OpCodes.Neg);
4657 EmitOperator (ec, left, right);
4660 public void EmitOperator (EmitContext ec, Expression left, Expression right)
4665 EmitOperatorOpcode (ec, oper, left.Type, right);
4668 // Emit result enumerable conversion this way because it's quite complicated get it
4669 // to resolved tree because expression tree cannot see it.
4671 if (enum_conversion != 0)
4672 ConvCast.Emit (ec, enum_conversion);
4675 public override void EmitSideEffect (EmitContext ec)
4677 if ((oper & Operator.LogicalMask) != 0 ||
4678 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
4679 base.EmitSideEffect (ec);
4681 left.EmitSideEffect (ec);
4682 right.EmitSideEffect (ec);
4686 public override Expression EmitToField (EmitContext ec)
4688 if ((oper & Operator.LogicalMask) == 0) {
4689 var await_expr = left as Await;
4690 if (await_expr != null && right.IsSideEffectFree) {
4691 await_expr.Statement.EmitPrologue (ec);
4692 left = await_expr.Statement.GetResultExpression (ec);
4696 await_expr = right as Await;
4697 if (await_expr != null && left.IsSideEffectFree) {
4698 await_expr.Statement.EmitPrologue (ec);
4699 right = await_expr.Statement.GetResultExpression (ec);
4704 return base.EmitToField (ec);
4707 protected override void CloneTo (CloneContext clonectx, Expression t)
4709 Binary target = (Binary) t;
4711 target.left = left.Clone (clonectx);
4712 target.right = right.Clone (clonectx);
4715 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
4717 Arguments binder_args = new Arguments (4);
4719 MemberAccess sle = new MemberAccess (new MemberAccess (
4720 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
4722 CSharpBinderFlags flags = 0;
4723 if (ec.HasSet (ResolveContext.Options.CheckedScope))
4724 flags = CSharpBinderFlags.CheckedContext;
4726 if ((oper & Operator.LogicalMask) != 0)
4727 flags |= CSharpBinderFlags.BinaryOperationLogical;
4729 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
4730 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
4731 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
4732 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
4734 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
4737 public override Expression CreateExpressionTree (ResolveContext ec)
4739 return CreateExpressionTree (ec, null);
4742 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
4745 bool lift_arg = false;
4748 case Operator.Addition:
4749 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4750 method_name = "AddChecked";
4752 method_name = "Add";
4754 case Operator.BitwiseAnd:
4755 method_name = "And";
4757 case Operator.BitwiseOr:
4760 case Operator.Division:
4761 method_name = "Divide";
4763 case Operator.Equality:
4764 method_name = "Equal";
4767 case Operator.ExclusiveOr:
4768 method_name = "ExclusiveOr";
4770 case Operator.GreaterThan:
4771 method_name = "GreaterThan";
4774 case Operator.GreaterThanOrEqual:
4775 method_name = "GreaterThanOrEqual";
4778 case Operator.Inequality:
4779 method_name = "NotEqual";
4782 case Operator.LeftShift:
4783 method_name = "LeftShift";
4785 case Operator.LessThan:
4786 method_name = "LessThan";
4789 case Operator.LessThanOrEqual:
4790 method_name = "LessThanOrEqual";
4793 case Operator.LogicalAnd:
4794 method_name = "AndAlso";
4796 case Operator.LogicalOr:
4797 method_name = "OrElse";
4799 case Operator.Modulus:
4800 method_name = "Modulo";
4802 case Operator.Multiply:
4803 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4804 method_name = "MultiplyChecked";
4806 method_name = "Multiply";
4808 case Operator.RightShift:
4809 method_name = "RightShift";
4811 case Operator.Subtraction:
4812 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4813 method_name = "SubtractChecked";
4815 method_name = "Subtract";
4819 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4822 Arguments args = new Arguments (2);
4823 args.Add (new Argument (left.CreateExpressionTree (ec)));
4824 args.Add (new Argument (right.CreateExpressionTree (ec)));
4825 if (method != null) {
4827 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4829 args.Add (new Argument (method));
4832 return CreateExpressionFactoryCall (ec, method_name, args);
4835 public override object Accept (StructuralVisitor visitor)
4837 return visitor.Visit (this);
4843 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4844 // b, c, d... may be strings or objects.
4846 public class StringConcat : Expression
4848 Arguments arguments;
4850 StringConcat (Location loc)
4853 arguments = new Arguments (2);
4856 public override bool ContainsEmitWithAwait ()
4858 return arguments.ContainsEmitWithAwait ();
4861 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4863 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4864 throw new ArgumentException ();
4866 var s = new StringConcat (loc);
4867 s.type = rc.BuiltinTypes.String;
4868 s.eclass = ExprClass.Value;
4870 s.Append (rc, left);
4871 s.Append (rc, right);
4875 public override Expression CreateExpressionTree (ResolveContext ec)
4877 Argument arg = arguments [0];
4878 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4882 // Creates nested calls tree from an array of arguments used for IL emit
4884 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4886 Arguments concat_args = new Arguments (2);
4887 Arguments add_args = new Arguments (3);
4889 concat_args.Add (left);
4890 add_args.Add (new Argument (left_etree));
4892 concat_args.Add (arguments [pos]);
4893 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4895 var methods = GetConcatMethodCandidates ();
4896 if (methods == null)
4899 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4900 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4904 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4906 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4907 if (++pos == arguments.Count)
4910 left = new Argument (new EmptyExpression (method.ReturnType));
4911 return CreateExpressionAddCall (ec, left, expr, pos);
4914 protected override Expression DoResolve (ResolveContext ec)
4919 void Append (ResolveContext rc, Expression operand)
4924 StringConstant sc = operand as StringConstant;
4926 if (arguments.Count != 0) {
4927 Argument last_argument = arguments [arguments.Count - 1];
4928 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4929 if (last_expr_constant != null) {
4930 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4936 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4938 StringConcat concat_oper = operand as StringConcat;
4939 if (concat_oper != null) {
4940 arguments.AddRange (concat_oper.arguments);
4945 arguments.Add (new Argument (operand));
4948 IList<MemberSpec> GetConcatMethodCandidates ()
4950 return MemberCache.FindMembers (type, "Concat", true);
4953 public override void Emit (EmitContext ec)
4955 // Optimize by removing any extra null arguments, they are no-op
4956 for (int i = 0; i < arguments.Count; ++i) {
4957 if (arguments[i].Expr is NullConstant)
4958 arguments.RemoveAt (i--);
4961 var members = GetConcatMethodCandidates ();
4962 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4963 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4964 if (method != null) {
4965 var call = new CallEmitter ();
4966 call.EmitPredefined (ec, method, arguments);
4970 public override void FlowAnalysis (FlowAnalysisContext fc)
4972 arguments.FlowAnalysis (fc);
4975 public override SLE.Expression MakeExpression (BuilderContext ctx)
4977 if (arguments.Count != 2)
4978 throw new NotImplementedException ("arguments.Count != 2");
4980 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4981 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4986 // User-defined conditional logical operator
4988 public class ConditionalLogicalOperator : UserOperatorCall
4990 readonly bool is_and;
4991 Expression oper_expr;
4993 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4994 : base (oper, arguments, expr_tree, loc)
4996 this.is_and = is_and;
4997 eclass = ExprClass.Unresolved;
5000 protected override Expression DoResolve (ResolveContext ec)
5002 AParametersCollection pd = oper.Parameters;
5003 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5004 ec.Report.Error (217, loc,
5005 "A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
5006 oper.GetSignatureForError ());
5010 Expression left_dup = new EmptyExpression (type);
5011 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5012 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5013 if (op_true == null || op_false == null) {
5014 ec.Report.Error (218, loc,
5015 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5016 type.GetSignatureForError (), oper.GetSignatureForError ());
5020 oper_expr = is_and ? op_false : op_true;
5021 eclass = ExprClass.Value;
5025 public override void Emit (EmitContext ec)
5027 Label end_target = ec.DefineLabel ();
5030 // Emit and duplicate left argument
5032 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5033 if (right_contains_await) {
5034 arguments[0] = arguments[0].EmitToField (ec, false);
5035 arguments[0].Expr.Emit (ec);
5037 arguments[0].Expr.Emit (ec);
5038 ec.Emit (OpCodes.Dup);
5039 arguments.RemoveAt (0);
5042 oper_expr.EmitBranchable (ec, end_target, true);
5046 if (right_contains_await) {
5048 // Special handling when right expression contains await and left argument
5049 // could not be left on stack before logical branch
5051 Label skip_left_load = ec.DefineLabel ();
5052 ec.Emit (OpCodes.Br_S, skip_left_load);
5053 ec.MarkLabel (end_target);
5054 arguments[0].Expr.Emit (ec);
5055 ec.MarkLabel (skip_left_load);
5057 ec.MarkLabel (end_target);
5062 public class PointerArithmetic : Expression {
5063 Expression left, right;
5064 readonly Binary.Operator op;
5067 // We assume that `l' is always a pointer
5069 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5078 public override bool ContainsEmitWithAwait ()
5080 throw new NotImplementedException ();
5083 public override Expression CreateExpressionTree (ResolveContext ec)
5085 Error_PointerInsideExpressionTree (ec);
5089 protected override Expression DoResolve (ResolveContext ec)
5091 eclass = ExprClass.Variable;
5093 var pc = left.Type as PointerContainer;
5094 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5095 Error_VoidPointerOperation (ec);
5102 public override void Emit (EmitContext ec)
5104 TypeSpec op_type = left.Type;
5106 // It must be either array or fixed buffer
5108 if (TypeManager.HasElementType (op_type)) {
5109 element = TypeManager.GetElementType (op_type);
5111 FieldExpr fe = left as FieldExpr;
5113 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5118 int size = BuiltinTypeSpec.GetSize(element);
5119 TypeSpec rtype = right.Type;
5121 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5123 // handle (pointer - pointer)
5127 ec.Emit (OpCodes.Sub);
5131 ec.Emit (OpCodes.Sizeof, element);
5134 ec.Emit (OpCodes.Div);
5136 ec.Emit (OpCodes.Conv_I8);
5139 // handle + and - on (pointer op int)
5141 Constant left_const = left as Constant;
5142 if (left_const != null) {
5144 // Optimize ((T*)null) pointer operations
5146 if (left_const.IsDefaultValue) {
5147 left = EmptyExpression.Null;
5155 var right_const = right as Constant;
5156 if (right_const != null) {
5158 // Optimize 0-based arithmetic
5160 if (right_const.IsDefaultValue)
5164 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5166 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5168 // TODO: Should be the checks resolve context sensitive?
5169 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5170 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5176 switch (rtype.BuiltinType) {
5177 case BuiltinTypeSpec.Type.SByte:
5178 case BuiltinTypeSpec.Type.Byte:
5179 case BuiltinTypeSpec.Type.Short:
5180 case BuiltinTypeSpec.Type.UShort:
5181 ec.Emit (OpCodes.Conv_I);
5183 case BuiltinTypeSpec.Type.UInt:
5184 ec.Emit (OpCodes.Conv_U);
5188 if (right_const == null && size != 1){
5190 ec.Emit (OpCodes.Sizeof, element);
5193 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5194 ec.Emit (OpCodes.Conv_I8);
5196 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
5199 if (left_const == null) {
5200 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
5201 ec.Emit (OpCodes.Conv_I);
5202 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5203 ec.Emit (OpCodes.Conv_U);
5205 Binary.EmitOperatorOpcode (ec, op, op_type, right);
5212 // A boolean-expression is an expression that yields a result
5215 public class BooleanExpression : ShimExpression
5217 public BooleanExpression (Expression expr)
5220 this.loc = expr.Location;
5223 public override Expression CreateExpressionTree (ResolveContext ec)
5225 // TODO: We should emit IsTrue (v4) instead of direct user operator
5226 // call but that would break csc compatibility
5227 return base.CreateExpressionTree (ec);
5230 protected override Expression DoResolve (ResolveContext ec)
5232 // A boolean-expression is required to be of a type
5233 // that can be implicitly converted to bool or of
5234 // a type that implements operator true
5236 expr = expr.Resolve (ec);
5240 Assign ass = expr as Assign;
5241 if (ass != null && ass.Source is Constant) {
5242 ec.Report.Warning (665, 3, loc,
5243 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
5246 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
5249 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5250 Arguments args = new Arguments (1);
5251 args.Add (new Argument (expr));
5252 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
5255 type = ec.BuiltinTypes.Bool;
5256 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
5257 if (converted != null)
5261 // If no implicit conversion to bool exists, try using `operator true'
5263 converted = GetOperatorTrue (ec, expr, loc);
5264 if (converted == null) {
5265 expr.Error_ValueCannotBeConverted (ec, type, false);
5272 public override object Accept (StructuralVisitor visitor)
5274 return visitor.Visit (this);
5278 public class BooleanExpressionFalse : Unary
5280 public BooleanExpressionFalse (Expression expr)
5281 : base (Operator.LogicalNot, expr, expr.Location)
5285 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
5287 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
5292 /// Implements the ternary conditional operator (?:)
5294 public class Conditional : Expression {
5295 Expression expr, true_expr, false_expr;
5297 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
5300 this.true_expr = true_expr;
5301 this.false_expr = false_expr;
5307 public Expression Expr {
5313 public Expression TrueExpr {
5319 public Expression FalseExpr {
5327 public override bool ContainsEmitWithAwait ()
5329 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
5332 public override Expression CreateExpressionTree (ResolveContext ec)
5334 Arguments args = new Arguments (3);
5335 args.Add (new Argument (expr.CreateExpressionTree (ec)));
5336 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
5337 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
5338 return CreateExpressionFactoryCall (ec, "Condition", args);
5341 protected override Expression DoResolve (ResolveContext ec)
5343 expr = expr.Resolve (ec);
5344 true_expr = true_expr.Resolve (ec);
5345 false_expr = false_expr.Resolve (ec);
5347 if (true_expr == null || false_expr == null || expr == null)
5350 eclass = ExprClass.Value;
5351 TypeSpec true_type = true_expr.Type;
5352 TypeSpec false_type = false_expr.Type;
5356 // First, if an implicit conversion exists from true_expr
5357 // to false_expr, then the result type is of type false_expr.Type
5359 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
5360 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
5361 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5363 // Check if both can convert implicitly to each other's type
5367 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5368 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
5370 // LAMESPEC: There seems to be hardcoded promotition to int type when
5371 // both sides are numeric constants and one side is int constant and
5372 // other side is numeric constant convertible to int.
5374 // var res = condition ? (short)1 : 1;
5376 // Type of res is int even if according to the spec the conversion is
5377 // ambiguous because 1 literal can be converted to short.
5379 if (conv_false_expr != null) {
5380 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
5382 conv_false_expr = null;
5383 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
5384 conv_false_expr = null;
5388 if (conv_false_expr != null) {
5389 ec.Report.Error (172, true_expr.Location,
5390 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
5391 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5396 if (true_expr.Type != type)
5397 true_expr = EmptyCast.Create (true_expr, type);
5398 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
5401 ec.Report.Error (173, true_expr.Location,
5402 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
5403 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5408 Constant c = expr as Constant;
5410 bool is_false = c.IsDefaultValue;
5413 // Don't issue the warning for constant expressions
5415 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
5416 // CSC: Missing warning
5417 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
5420 return ReducedExpression.Create (
5421 is_false ? false_expr : true_expr, this,
5422 false_expr is Constant && true_expr is Constant).Resolve (ec);
5428 public override void Emit (EmitContext ec)
5430 Label false_target = ec.DefineLabel ();
5431 Label end_target = ec.DefineLabel ();
5433 expr.EmitBranchable (ec, false_target, false);
5434 true_expr.Emit (ec);
5437 // Verifier doesn't support interface merging. When there are two types on
5438 // the stack without common type hint and the common type is an interface.
5439 // Use temporary local to give verifier hint on what type to unify the stack
5441 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
5442 var temp = ec.GetTemporaryLocal (type);
5443 ec.Emit (OpCodes.Stloc, temp);
5444 ec.Emit (OpCodes.Ldloc, temp);
5445 ec.FreeTemporaryLocal (temp, type);
5448 ec.Emit (OpCodes.Br, end_target);
5449 ec.MarkLabel (false_target);
5450 false_expr.Emit (ec);
5451 ec.MarkLabel (end_target);
5454 public override void FlowAnalysis (FlowAnalysisContext fc)
5456 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
5458 expr.FlowAnalysis (fc);
5459 var da_true = fc.DefiniteAssignmentOnTrue;
5460 var da_false = fc.DefiniteAssignmentOnFalse;
5462 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da_true);
5463 true_expr.FlowAnalysis (fc);
5464 var true_fc = fc.DefiniteAssignment;
5466 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da_false);
5467 false_expr.FlowAnalysis (fc);
5469 fc.DefiniteAssignment &= true_fc;
5470 if (fc.DefiniteAssignmentOnTrue != null)
5471 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignment;
5472 if (fc.DefiniteAssignmentOnFalse != null)
5473 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
5476 protected override void CloneTo (CloneContext clonectx, Expression t)
5478 Conditional target = (Conditional) t;
5480 target.expr = expr.Clone (clonectx);
5481 target.true_expr = true_expr.Clone (clonectx);
5482 target.false_expr = false_expr.Clone (clonectx);
5486 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
5488 LocalTemporary temp;
5491 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
5492 public abstract void SetHasAddressTaken ();
5494 public abstract bool IsLockedByStatement { get; set; }
5496 public abstract bool IsFixed { get; }
5497 public abstract bool IsRef { get; }
5498 public abstract string Name { get; }
5501 // Variable IL data, it has to be protected to encapsulate hoisted variables
5503 protected abstract ILocalVariable Variable { get; }
5506 // Variable flow-analysis data
5508 public abstract VariableInfo VariableInfo { get; }
5511 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5513 HoistedVariable hv = GetHoistedVariable (ec);
5515 hv.AddressOf (ec, mode);
5519 Variable.EmitAddressOf (ec);
5522 public override bool ContainsEmitWithAwait ()
5527 public override Expression CreateExpressionTree (ResolveContext ec)
5529 HoistedVariable hv = GetHoistedVariable (ec);
5531 return hv.CreateExpressionTree ();
5533 Arguments arg = new Arguments (1);
5534 arg.Add (new Argument (this));
5535 return CreateExpressionFactoryCall (ec, "Constant", arg);
5538 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
5540 if (IsLockedByStatement) {
5541 rc.Report.Warning (728, 2, loc,
5542 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
5549 public override void Emit (EmitContext ec)
5554 public override void EmitSideEffect (EmitContext ec)
5560 // This method is used by parameters that are references, that are
5561 // being passed as references: we only want to pass the pointer (that
5562 // is already stored in the parameter, not the address of the pointer,
5563 // and not the value of the variable).
5565 public void EmitLoad (EmitContext ec)
5570 public void Emit (EmitContext ec, bool leave_copy)
5572 HoistedVariable hv = GetHoistedVariable (ec);
5574 hv.Emit (ec, leave_copy);
5582 // If we are a reference, we loaded on the stack a pointer
5583 // Now lets load the real value
5585 ec.EmitLoadFromPtr (type);
5589 ec.Emit (OpCodes.Dup);
5592 temp = new LocalTemporary (Type);
5598 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
5599 bool prepare_for_load)
5601 HoistedVariable hv = GetHoistedVariable (ec);
5603 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
5607 New n_source = source as New;
5608 if (n_source != null) {
5609 if (!n_source.Emit (ec, this)) {
5613 ec.EmitLoadFromPtr (type);
5625 ec.Emit (OpCodes.Dup);
5627 temp = new LocalTemporary (Type);
5633 ec.EmitStoreFromPtr (type);
5635 Variable.EmitAssign (ec);
5643 public override Expression EmitToField (EmitContext ec)
5645 HoistedVariable hv = GetHoistedVariable (ec);
5647 return hv.EmitToField (ec);
5650 return base.EmitToField (ec);
5653 public HoistedVariable GetHoistedVariable (ResolveContext rc)
5655 return GetHoistedVariable (rc.CurrentAnonymousMethod);
5658 public HoistedVariable GetHoistedVariable (EmitContext ec)
5660 return GetHoistedVariable (ec.CurrentAnonymousMethod);
5663 public override string GetSignatureForError ()
5668 public bool IsHoisted {
5669 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
5674 // Resolved reference to a local variable
5676 public class LocalVariableReference : VariableReference
5678 public LocalVariable local_info;
5680 public LocalVariableReference (LocalVariable li, Location l)
5682 this.local_info = li;
5686 public override VariableInfo VariableInfo {
5687 get { return local_info.VariableInfo; }
5690 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5692 return local_info.HoistedVariant;
5698 // A local variable is always fixed
5700 public override bool IsFixed {
5706 public override bool IsLockedByStatement {
5708 return local_info.IsLocked;
5711 local_info.IsLocked = value;
5715 public override bool IsRef {
5716 get { return false; }
5719 public override string Name {
5720 get { return local_info.Name; }
5725 public override void FlowAnalysis (FlowAnalysisContext fc)
5727 VariableInfo variable_info = VariableInfo;
5728 if (variable_info == null)
5731 if (fc.IsDefinitelyAssigned (variable_info))
5734 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
5735 variable_info.SetAssigned (fc.DefiniteAssignment, true);
5738 public override void SetHasAddressTaken ()
5740 local_info.SetHasAddressTaken ();
5743 void DoResolveBase (ResolveContext ec)
5746 // If we are referencing a variable from the external block
5747 // flag it for capturing
5749 if (ec.MustCaptureVariable (local_info)) {
5750 if (local_info.AddressTaken) {
5751 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5752 } else if (local_info.IsFixed) {
5753 ec.Report.Error (1764, loc,
5754 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
5755 GetSignatureForError ());
5758 if (ec.IsVariableCapturingRequired) {
5759 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
5760 storey.CaptureLocalVariable (ec, local_info);
5764 eclass = ExprClass.Variable;
5765 type = local_info.Type;
5768 protected override Expression DoResolve (ResolveContext ec)
5770 local_info.SetIsUsed ();
5776 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5779 // Don't be too pedantic when variable is used as out param or for some broken code
5780 // which uses property/indexer access to run some initialization
5782 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5783 local_info.SetIsUsed ();
5785 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5786 if (rhs == EmptyExpression.LValueMemberAccess) {
5787 // CS1654 already reported
5791 if (rhs == EmptyExpression.OutAccess) {
5792 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5793 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5794 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5795 } else if (rhs == EmptyExpression.UnaryAddress) {
5796 code = 459; msg = "Cannot take the address of {1} `{0}'";
5798 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5800 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5804 if (eclass == ExprClass.Unresolved)
5807 return base.DoResolveLValue (ec, rhs);
5810 public override int GetHashCode ()
5812 return local_info.GetHashCode ();
5815 public override bool Equals (object obj)
5817 LocalVariableReference lvr = obj as LocalVariableReference;
5821 return local_info == lvr.local_info;
5824 protected override ILocalVariable Variable {
5825 get { return local_info; }
5828 public override string ToString ()
5830 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5833 protected override void CloneTo (CloneContext clonectx, Expression t)
5840 /// This represents a reference to a parameter in the intermediate
5843 public class ParameterReference : VariableReference
5845 protected ParametersBlock.ParameterInfo pi;
5847 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5855 public override bool IsLockedByStatement {
5860 pi.IsLocked = value;
5864 public override bool IsRef {
5865 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5868 bool HasOutModifier {
5869 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5872 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5874 return pi.Parameter.HoistedVariant;
5878 // A ref or out parameter is classified as a moveable variable, even
5879 // if the argument given for the parameter is a fixed variable
5881 public override bool IsFixed {
5882 get { return !IsRef; }
5885 public override string Name {
5886 get { return Parameter.Name; }
5889 public Parameter Parameter {
5890 get { return pi.Parameter; }
5893 public override VariableInfo VariableInfo {
5894 get { return pi.VariableInfo; }
5897 protected override ILocalVariable Variable {
5898 get { return Parameter; }
5903 public override void AddressOf (EmitContext ec, AddressOp mode)
5906 // ParameterReferences might already be a reference
5913 base.AddressOf (ec, mode);
5916 public override void SetHasAddressTaken ()
5918 Parameter.HasAddressTaken = true;
5921 bool DoResolveBase (ResolveContext ec)
5923 if (eclass != ExprClass.Unresolved)
5926 type = pi.ParameterType;
5927 eclass = ExprClass.Variable;
5930 // If we are referencing a parameter from the external block
5931 // flag it for capturing
5933 if (ec.MustCaptureVariable (pi)) {
5934 if (Parameter.HasAddressTaken)
5935 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5938 ec.Report.Error (1628, loc,
5939 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5940 Name, ec.CurrentAnonymousMethod.ContainerType);
5943 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5944 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5945 storey.CaptureParameter (ec, pi, this);
5952 public override int GetHashCode ()
5954 return Name.GetHashCode ();
5957 public override bool Equals (object obj)
5959 ParameterReference pr = obj as ParameterReference;
5963 return Name == pr.Name;
5966 protected override void CloneTo (CloneContext clonectx, Expression target)
5972 public override Expression CreateExpressionTree (ResolveContext ec)
5974 HoistedVariable hv = GetHoistedVariable (ec);
5976 return hv.CreateExpressionTree ();
5978 return Parameter.ExpressionTreeVariableReference ();
5981 protected override Expression DoResolve (ResolveContext ec)
5983 if (!DoResolveBase (ec))
5989 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5991 if (!DoResolveBase (ec))
5994 if (Parameter.HoistedVariant != null)
5995 Parameter.HoistedVariant.IsAssigned = true;
5997 return base.DoResolveLValue (ec, right_side);
6000 public override void FlowAnalysis (FlowAnalysisContext fc)
6002 VariableInfo variable_info = VariableInfo;
6003 if (variable_info == null)
6006 if (fc.IsDefinitelyAssigned (variable_info))
6009 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6010 fc.SetVariableAssigned (variable_info);
6015 /// Invocation of methods or delegates.
6017 public class Invocation : ExpressionStatement
6019 protected Arguments arguments;
6020 protected Expression expr;
6021 protected MethodGroupExpr mg;
6023 public Invocation (Expression expr, Arguments arguments)
6026 this.arguments = arguments;
6028 loc = expr.Location;
6033 public Arguments Arguments {
6039 public Expression Exp {
6045 public MethodGroupExpr MethodGroup {
6051 public override Location StartLocation {
6053 return expr.StartLocation;
6059 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6061 if (MethodGroup == null)
6064 var candidate = MethodGroup.BestCandidate;
6065 if (candidate == null || !(candidate.IsStatic || Exp is This))
6068 var args_count = arguments == null ? 0 : arguments.Count;
6069 if (args_count != body.Parameters.Count)
6072 var lambda_parameters = body.Block.Parameters.FixedParameters;
6073 for (int i = 0; i < args_count; ++i) {
6074 var pr = arguments[i].Expr as ParameterReference;
6078 if (lambda_parameters[i] != pr.Parameter)
6081 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6085 var emg = MethodGroup as ExtensionMethodGroupExpr;
6087 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6088 if (candidate.IsGeneric) {
6089 var targs = new TypeExpression [candidate.Arity];
6090 for (int i = 0; i < targs.Length; ++i) {
6091 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6094 mg.SetTypeArguments (null, new TypeArguments (targs));
6103 protected override void CloneTo (CloneContext clonectx, Expression t)
6105 Invocation target = (Invocation) t;
6107 if (arguments != null)
6108 target.arguments = arguments.Clone (clonectx);
6110 target.expr = expr.Clone (clonectx);
6113 public override bool ContainsEmitWithAwait ()
6115 if (arguments != null && arguments.ContainsEmitWithAwait ())
6118 return mg.ContainsEmitWithAwait ();
6121 public override Expression CreateExpressionTree (ResolveContext ec)
6123 Expression instance = mg.IsInstance ?
6124 mg.InstanceExpression.CreateExpressionTree (ec) :
6125 new NullLiteral (loc);
6127 var args = Arguments.CreateForExpressionTree (ec, arguments,
6129 mg.CreateExpressionTree (ec));
6131 return CreateExpressionFactoryCall (ec, "Call", args);
6134 protected override Expression DoResolve (ResolveContext ec)
6136 Expression member_expr;
6137 var atn = expr as ATypeNameExpression;
6139 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
6140 if (member_expr != null)
6141 member_expr = member_expr.Resolve (ec);
6143 member_expr = expr.Resolve (ec);
6146 if (member_expr == null)
6150 // Next, evaluate all the expressions in the argument list
6152 bool dynamic_arg = false;
6153 if (arguments != null)
6154 arguments.Resolve (ec, out dynamic_arg);
6156 TypeSpec expr_type = member_expr.Type;
6157 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6158 return DoResolveDynamic (ec, member_expr);
6160 mg = member_expr as MethodGroupExpr;
6161 Expression invoke = null;
6164 if (expr_type != null && expr_type.IsDelegate) {
6165 invoke = new DelegateInvocation (member_expr, arguments, loc);
6166 invoke = invoke.Resolve (ec);
6167 if (invoke == null || !dynamic_arg)
6170 if (member_expr is RuntimeValueExpression) {
6171 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
6172 member_expr.Type.GetSignatureForError ());
6176 MemberExpr me = member_expr as MemberExpr;
6178 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
6182 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
6183 member_expr.GetSignatureForError ());
6188 if (invoke == null) {
6189 mg = DoResolveOverload (ec);
6195 return DoResolveDynamic (ec, member_expr);
6197 var method = mg.BestCandidate;
6198 type = mg.BestCandidateReturnType;
6200 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
6202 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
6204 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
6208 IsSpecialMethodInvocation (ec, method, loc);
6210 eclass = ExprClass.Value;
6214 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
6217 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
6219 args = dmb.Arguments;
6220 if (arguments != null)
6221 args.AddRange (arguments);
6222 } else if (mg == null) {
6223 if (arguments == null)
6224 args = new Arguments (1);
6228 args.Insert (0, new Argument (memberExpr));
6232 ec.Report.Error (1971, loc,
6233 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
6238 if (arguments == null)
6239 args = new Arguments (1);
6243 MemberAccess ma = expr as MemberAccess;
6245 var left_type = ma.LeftExpression as TypeExpr;
6246 if (left_type != null) {
6247 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6250 // Any value type has to be pass as by-ref to get back the same
6251 // instance on which the member was called
6253 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
6254 Argument.AType.Ref : Argument.AType.None;
6255 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
6257 } else { // is SimpleName
6259 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6261 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
6266 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
6269 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
6271 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
6274 public override void FlowAnalysis (FlowAnalysisContext fc)
6276 if (mg.IsConditionallyExcluded)
6279 mg.FlowAnalysis (fc);
6281 if (arguments != null)
6282 arguments.FlowAnalysis (fc);
6285 public override string GetSignatureForError ()
6287 return mg.GetSignatureForError ();
6291 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
6292 // or the type dynamic, then the member is invocable
6294 public static bool IsMemberInvocable (MemberSpec member)
6296 switch (member.Kind) {
6297 case MemberKind.Event:
6299 case MemberKind.Field:
6300 case MemberKind.Property:
6301 var m = member as IInterfaceMemberSpec;
6302 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
6308 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
6310 if (!method.IsReservedMethod)
6313 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
6316 ec.Report.SymbolRelatedToPreviousError (method);
6317 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
6318 method.GetSignatureForError ());
6323 public override void Emit (EmitContext ec)
6325 if (mg.IsConditionallyExcluded)
6328 mg.EmitCall (ec, arguments);
6331 public override void EmitStatement (EmitContext ec)
6336 // Pop the return value if there is one
6338 if (type.Kind != MemberKind.Void)
6339 ec.Emit (OpCodes.Pop);
6342 public override SLE.Expression MakeExpression (BuilderContext ctx)
6344 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
6347 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
6350 throw new NotSupportedException ();
6352 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
6353 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
6357 public override object Accept (StructuralVisitor visitor)
6359 return visitor.Visit (this);
6364 // Implements simple new expression
6366 public class New : ExpressionStatement, IMemoryLocation
6368 protected Arguments arguments;
6371 // During bootstrap, it contains the RequestedType,
6372 // but if `type' is not null, it *might* contain a NewDelegate
6373 // (because of field multi-initialization)
6375 protected Expression RequestedType;
6377 protected MethodSpec method;
6379 public New (Expression requested_type, Arguments arguments, Location l)
6381 RequestedType = requested_type;
6382 this.arguments = arguments;
6387 public Arguments Arguments {
6394 // Returns true for resolved `new S()'
6396 public bool IsDefaultStruct {
6398 return arguments == null && type.IsStruct && GetType () == typeof (New);
6402 public Expression TypeExpression {
6404 return RequestedType;
6411 /// Converts complex core type syntax like 'new int ()' to simple constant
6413 public static Constant Constantify (TypeSpec t, Location loc)
6415 switch (t.BuiltinType) {
6416 case BuiltinTypeSpec.Type.Int:
6417 return new IntConstant (t, 0, loc);
6418 case BuiltinTypeSpec.Type.UInt:
6419 return new UIntConstant (t, 0, loc);
6420 case BuiltinTypeSpec.Type.Long:
6421 return new LongConstant (t, 0, loc);
6422 case BuiltinTypeSpec.Type.ULong:
6423 return new ULongConstant (t, 0, loc);
6424 case BuiltinTypeSpec.Type.Float:
6425 return new FloatConstant (t, 0, loc);
6426 case BuiltinTypeSpec.Type.Double:
6427 return new DoubleConstant (t, 0, loc);
6428 case BuiltinTypeSpec.Type.Short:
6429 return new ShortConstant (t, 0, loc);
6430 case BuiltinTypeSpec.Type.UShort:
6431 return new UShortConstant (t, 0, loc);
6432 case BuiltinTypeSpec.Type.SByte:
6433 return new SByteConstant (t, 0, loc);
6434 case BuiltinTypeSpec.Type.Byte:
6435 return new ByteConstant (t, 0, loc);
6436 case BuiltinTypeSpec.Type.Char:
6437 return new CharConstant (t, '\0', loc);
6438 case BuiltinTypeSpec.Type.Bool:
6439 return new BoolConstant (t, false, loc);
6440 case BuiltinTypeSpec.Type.Decimal:
6441 return new DecimalConstant (t, 0, loc);
6445 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
6447 if (t.IsNullableType)
6448 return Nullable.LiftedNull.Create (t, loc);
6453 public override bool ContainsEmitWithAwait ()
6455 return arguments != null && arguments.ContainsEmitWithAwait ();
6459 // Checks whether the type is an interface that has the
6460 // [ComImport, CoClass] attributes and must be treated
6463 public Expression CheckComImport (ResolveContext ec)
6465 if (!type.IsInterface)
6469 // Turn the call into:
6470 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
6472 var real_class = type.MemberDefinition.GetAttributeCoClass ();
6473 if (real_class == null)
6476 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
6477 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
6478 return cast.Resolve (ec);
6481 public override Expression CreateExpressionTree (ResolveContext ec)
6484 if (method == null) {
6485 args = new Arguments (1);
6486 args.Add (new Argument (new TypeOf (type, loc)));
6488 args = Arguments.CreateForExpressionTree (ec,
6489 arguments, new TypeOfMethod (method, loc));
6492 return CreateExpressionFactoryCall (ec, "New", args);
6495 protected override Expression DoResolve (ResolveContext ec)
6497 type = RequestedType.ResolveAsType (ec);
6501 eclass = ExprClass.Value;
6503 if (type.IsPointer) {
6504 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
6505 type.GetSignatureForError ());
6509 if (arguments == null) {
6510 Constant c = Constantify (type, RequestedType.Location);
6512 return ReducedExpression.Create (c, this);
6515 if (type.IsDelegate) {
6516 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
6519 var tparam = type as TypeParameterSpec;
6520 if (tparam != null) {
6522 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
6523 // where type parameter constraint is inflated to struct
6525 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
6526 ec.Report.Error (304, loc,
6527 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
6528 type.GetSignatureForError ());
6531 if ((arguments != null) && (arguments.Count != 0)) {
6532 ec.Report.Error (417, loc,
6533 "`{0}': cannot provide arguments when creating an instance of a variable type",
6534 type.GetSignatureForError ());
6540 if (type.IsStatic) {
6541 ec.Report.SymbolRelatedToPreviousError (type);
6542 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
6546 if (type.IsInterface || type.IsAbstract){
6547 if (!TypeManager.IsGenericType (type)) {
6548 RequestedType = CheckComImport (ec);
6549 if (RequestedType != null)
6550 return RequestedType;
6553 ec.Report.SymbolRelatedToPreviousError (type);
6554 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
6559 // Any struct always defines parameterless constructor
6561 if (type.IsStruct && arguments == null)
6565 if (arguments != null) {
6566 arguments.Resolve (ec, out dynamic);
6571 method = ConstructorLookup (ec, type, ref arguments, loc);
6574 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6575 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
6581 bool DoEmitTypeParameter (EmitContext ec)
6583 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
6587 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
6588 var tparam = (TypeParameterSpec) type;
6590 if (tparam.IsReferenceType) {
6591 ec.Emit (OpCodes.Call, ctor_factory);
6595 // Allow DoEmit() to be called multiple times.
6596 // We need to create a new LocalTemporary each time since
6597 // you can't share LocalBuilders among ILGeneators.
6598 LocalTemporary temp = new LocalTemporary (type);
6600 Label label_activator = ec.DefineLabel ();
6601 Label label_end = ec.DefineLabel ();
6603 temp.AddressOf (ec, AddressOp.Store);
6604 ec.Emit (OpCodes.Initobj, type);
6607 ec.Emit (OpCodes.Box, type);
6608 ec.Emit (OpCodes.Brfalse, label_activator);
6610 temp.AddressOf (ec, AddressOp.Store);
6611 ec.Emit (OpCodes.Initobj, type);
6614 ec.Emit (OpCodes.Br_S, label_end);
6616 ec.MarkLabel (label_activator);
6618 ec.Emit (OpCodes.Call, ctor_factory);
6619 ec.MarkLabel (label_end);
6624 // This Emit can be invoked in two contexts:
6625 // * As a mechanism that will leave a value on the stack (new object)
6626 // * As one that wont (init struct)
6628 // If we are dealing with a ValueType, we have a few
6629 // situations to deal with:
6631 // * The target is a ValueType, and we have been provided
6632 // the instance (this is easy, we are being assigned).
6634 // * The target of New is being passed as an argument,
6635 // to a boxing operation or a function that takes a
6638 // In this case, we need to create a temporary variable
6639 // that is the argument of New.
6641 // Returns whether a value is left on the stack
6643 // *** Implementation note ***
6645 // To benefit from this optimization, each assignable expression
6646 // has to manually cast to New and call this Emit.
6648 // TODO: It's worth to implement it for arrays and fields
6650 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
6652 bool is_value_type = TypeSpec.IsValueType (type);
6653 VariableReference vr = target as VariableReference;
6655 if (target != null && is_value_type && (vr != null || method == null)) {
6656 target.AddressOf (ec, AddressOp.Store);
6657 } else if (vr != null && vr.IsRef) {
6661 if (arguments != null) {
6662 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
6663 arguments = arguments.Emit (ec, false, true);
6665 arguments.Emit (ec);
6668 if (is_value_type) {
6669 if (method == null) {
6670 ec.Emit (OpCodes.Initobj, type);
6675 ec.MarkCallEntry (loc);
6676 ec.Emit (OpCodes.Call, method);
6681 if (type is TypeParameterSpec)
6682 return DoEmitTypeParameter (ec);
6684 ec.MarkCallEntry (loc);
6685 ec.Emit (OpCodes.Newobj, method);
6689 public override void Emit (EmitContext ec)
6691 LocalTemporary v = null;
6692 if (method == null && TypeSpec.IsValueType (type)) {
6693 // TODO: Use temporary variable from pool
6694 v = new LocalTemporary (type);
6701 public override void EmitStatement (EmitContext ec)
6703 LocalTemporary v = null;
6704 if (method == null && TypeSpec.IsValueType (type)) {
6705 // TODO: Use temporary variable from pool
6706 v = new LocalTemporary (type);
6710 ec.Emit (OpCodes.Pop);
6713 public override void FlowAnalysis (FlowAnalysisContext fc)
6715 if (arguments != null)
6716 arguments.FlowAnalysis (fc);
6719 public void AddressOf (EmitContext ec, AddressOp mode)
6721 EmitAddressOf (ec, mode);
6724 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
6726 LocalTemporary value_target = new LocalTemporary (type);
6728 if (type is TypeParameterSpec) {
6729 DoEmitTypeParameter (ec);
6730 value_target.Store (ec);
6731 value_target.AddressOf (ec, mode);
6732 return value_target;
6735 value_target.AddressOf (ec, AddressOp.Store);
6737 if (method == null) {
6738 ec.Emit (OpCodes.Initobj, type);
6740 if (arguments != null)
6741 arguments.Emit (ec);
6743 ec.Emit (OpCodes.Call, method);
6746 value_target.AddressOf (ec, mode);
6747 return value_target;
6750 protected override void CloneTo (CloneContext clonectx, Expression t)
6752 New target = (New) t;
6754 target.RequestedType = RequestedType.Clone (clonectx);
6755 if (arguments != null){
6756 target.arguments = arguments.Clone (clonectx);
6760 public override SLE.Expression MakeExpression (BuilderContext ctx)
6763 return base.MakeExpression (ctx);
6765 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
6769 public override object Accept (StructuralVisitor visitor)
6771 return visitor.Visit (this);
6776 // Array initializer expression, the expression is allowed in
6777 // variable or field initialization only which makes it tricky as
6778 // the type has to be infered based on the context either from field
6779 // type or variable type (think of multiple declarators)
6781 public class ArrayInitializer : Expression
6783 List<Expression> elements;
6784 BlockVariable variable;
6786 public ArrayInitializer (List<Expression> init, Location loc)
6792 public ArrayInitializer (int count, Location loc)
6793 : this (new List<Expression> (count), loc)
6797 public ArrayInitializer (Location loc)
6805 get { return elements.Count; }
6808 public List<Expression> Elements {
6814 public Expression this [int index] {
6816 return elements [index];
6820 public BlockVariable VariableDeclaration {
6831 public void Add (Expression expr)
6833 elements.Add (expr);
6836 public override bool ContainsEmitWithAwait ()
6838 throw new NotSupportedException ();
6841 public override Expression CreateExpressionTree (ResolveContext ec)
6843 throw new NotSupportedException ("ET");
6846 protected override void CloneTo (CloneContext clonectx, Expression t)
6848 var target = (ArrayInitializer) t;
6850 target.elements = new List<Expression> (elements.Count);
6851 foreach (var element in elements)
6852 target.elements.Add (element.Clone (clonectx));
6855 protected override Expression DoResolve (ResolveContext rc)
6857 var current_field = rc.CurrentMemberDefinition as FieldBase;
6858 TypeExpression type;
6859 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6860 type = new TypeExpression (current_field.MemberType, current_field.Location);
6861 } else if (variable != null) {
6862 if (variable.TypeExpression is VarExpr) {
6863 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6864 return EmptyExpression.Null;
6867 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6869 throw new NotImplementedException ("Unexpected array initializer context");
6872 return new ArrayCreation (type, this).Resolve (rc);
6875 public override void Emit (EmitContext ec)
6877 throw new InternalErrorException ("Missing Resolve call");
6880 public override void FlowAnalysis (FlowAnalysisContext fc)
6882 throw new InternalErrorException ("Missing Resolve call");
6885 public override object Accept (StructuralVisitor visitor)
6887 return visitor.Visit (this);
6892 /// 14.5.10.2: Represents an array creation expression.
6896 /// There are two possible scenarios here: one is an array creation
6897 /// expression that specifies the dimensions and optionally the
6898 /// initialization data and the other which does not need dimensions
6899 /// specified but where initialization data is mandatory.
6901 public class ArrayCreation : Expression
6903 FullNamedExpression requested_base_type;
6904 ArrayInitializer initializers;
6907 // The list of Argument types.
6908 // This is used to construct the `newarray' or constructor signature
6910 protected List<Expression> arguments;
6912 protected TypeSpec array_element_type;
6914 protected int dimensions;
6915 protected readonly ComposedTypeSpecifier rank;
6916 Expression first_emit;
6917 LocalTemporary first_emit_temp;
6919 protected List<Expression> array_data;
6921 Dictionary<int, int> bounds;
6924 // The number of constants in array initializers
6925 int const_initializers_count;
6926 bool only_constant_initializers;
6928 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6929 : this (requested_base_type, rank, initializers, l)
6931 arguments = new List<Expression> (exprs);
6932 num_arguments = arguments.Count;
6936 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6938 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6940 this.requested_base_type = requested_base_type;
6942 this.initializers = initializers;
6946 num_arguments = rank.Dimension;
6950 // For compiler generated single dimensional arrays only
6952 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6953 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6958 // For expressions like int[] foo = { 1, 2, 3 };
6960 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6961 : this (requested_base_type, null, initializers, initializers.Location)
6965 public ComposedTypeSpecifier Rank {
6971 public FullNamedExpression TypeExpression {
6973 return this.requested_base_type;
6977 public ArrayInitializer Initializers {
6979 return this.initializers;
6983 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6985 if (initializers != null && bounds == null) {
6987 // We use this to store all the data values in the order in which we
6988 // will need to store them in the byte blob later
6990 array_data = new List<Expression> (probe.Count);
6991 bounds = new Dictionary<int, int> ();
6994 if (specified_dims) {
6995 Expression a = arguments [idx];
7000 a = ConvertExpressionToArrayIndex (ec, a);
7006 if (initializers != null) {
7007 Constant c = a as Constant;
7008 if (c == null && a is ArrayIndexCast)
7009 c = ((ArrayIndexCast) a).Child as Constant;
7012 ec.Report.Error (150, a.Location, "A constant value is expected");
7018 value = System.Convert.ToInt32 (c.GetValue ());
7020 ec.Report.Error (150, a.Location, "A constant value is expected");
7024 // TODO: probe.Count does not fit ulong in
7025 if (value != probe.Count) {
7026 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7030 bounds[idx] = value;
7034 if (initializers == null)
7037 for (int i = 0; i < probe.Count; ++i) {
7039 if (o is ArrayInitializer) {
7040 var sub_probe = o as ArrayInitializer;
7041 if (idx + 1 >= dimensions){
7042 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7046 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7047 if (!bounds.ContainsKey(idx + 1))
7048 bounds[idx + 1] = sub_probe.Count;
7050 if (bounds[idx + 1] != sub_probe.Count) {
7051 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7055 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7058 } else if (child_bounds > 1) {
7059 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7061 Expression element = ResolveArrayElement (ec, o);
7062 if (element == null)
7065 // Initializers with the default values can be ignored
7066 Constant c = element as Constant;
7068 if (!c.IsDefaultInitializer (array_element_type)) {
7069 ++const_initializers_count;
7072 only_constant_initializers = false;
7075 array_data.Add (element);
7082 public override bool ContainsEmitWithAwait ()
7084 foreach (var arg in arguments) {
7085 if (arg.ContainsEmitWithAwait ())
7089 return InitializersContainAwait ();
7092 public override Expression CreateExpressionTree (ResolveContext ec)
7096 if (array_data == null) {
7097 args = new Arguments (arguments.Count + 1);
7098 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7099 foreach (Expression a in arguments)
7100 args.Add (new Argument (a.CreateExpressionTree (ec)));
7102 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7105 if (dimensions > 1) {
7106 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7110 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7111 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7112 if (array_data != null) {
7113 for (int i = 0; i < array_data.Count; ++i) {
7114 Expression e = array_data [i];
7115 args.Add (new Argument (e.CreateExpressionTree (ec)));
7119 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7122 void UpdateIndices (ResolveContext rc)
7125 for (var probe = initializers; probe != null;) {
7126 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7128 bounds[i++] = probe.Count;
7130 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7131 probe = (ArrayInitializer) probe[0];
7132 } else if (dimensions > i) {
7140 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7142 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
7145 public override void FlowAnalysis (FlowAnalysisContext fc)
7147 foreach (var arg in arguments)
7148 arg.FlowAnalysis (fc);
7150 if (array_data != null) {
7151 foreach (var ad in array_data)
7152 ad.FlowAnalysis (fc);
7156 bool InitializersContainAwait ()
7158 if (array_data == null)
7161 foreach (var expr in array_data) {
7162 if (expr.ContainsEmitWithAwait ())
7169 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
7171 element = element.Resolve (ec);
7172 if (element == null)
7175 if (element is CompoundAssign.TargetExpression) {
7176 if (first_emit != null)
7177 throw new InternalErrorException ("Can only handle one mutator at a time");
7178 first_emit = element;
7179 element = first_emit_temp = new LocalTemporary (element.Type);
7182 return Convert.ImplicitConversionRequired (
7183 ec, element, array_element_type, loc);
7186 protected bool ResolveInitializers (ResolveContext ec)
7189 only_constant_initializers = true;
7192 if (arguments != null) {
7194 for (int i = 0; i < arguments.Count; ++i) {
7195 res &= CheckIndices (ec, initializers, i, true, dimensions);
7196 if (initializers != null)
7203 arguments = new List<Expression> ();
7205 if (!CheckIndices (ec, initializers, 0, false, dimensions))
7214 // Resolved the type of the array
7216 bool ResolveArrayType (ResolveContext ec)
7221 FullNamedExpression array_type_expr;
7222 if (num_arguments > 0) {
7223 array_type_expr = new ComposedCast (requested_base_type, rank);
7225 array_type_expr = requested_base_type;
7228 type = array_type_expr.ResolveAsType (ec);
7229 if (array_type_expr == null)
7232 var ac = type as ArrayContainer;
7234 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
7238 array_element_type = ac.Element;
7239 dimensions = ac.Rank;
7244 protected override Expression DoResolve (ResolveContext ec)
7249 if (!ResolveArrayType (ec))
7253 // validate the initializers and fill in any missing bits
7255 if (!ResolveInitializers (ec))
7258 eclass = ExprClass.Value;
7262 byte [] MakeByteBlob ()
7267 int count = array_data.Count;
7269 TypeSpec element_type = array_element_type;
7270 if (element_type.IsEnum)
7271 element_type = EnumSpec.GetUnderlyingType (element_type);
7273 factor = BuiltinTypeSpec.GetSize (element_type);
7275 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
7277 data = new byte [(count * factor + 3) & ~3];
7280 for (int i = 0; i < count; ++i) {
7281 var c = array_data[i] as Constant;
7287 object v = c.GetValue ();
7289 switch (element_type.BuiltinType) {
7290 case BuiltinTypeSpec.Type.Long:
7291 long lval = (long) v;
7293 for (int j = 0; j < factor; ++j) {
7294 data[idx + j] = (byte) (lval & 0xFF);
7298 case BuiltinTypeSpec.Type.ULong:
7299 ulong ulval = (ulong) v;
7301 for (int j = 0; j < factor; ++j) {
7302 data[idx + j] = (byte) (ulval & 0xFF);
7303 ulval = (ulval >> 8);
7306 case BuiltinTypeSpec.Type.Float:
7307 var fval = SingleConverter.SingleToInt32Bits((float) v);
7309 data[idx] = (byte) (fval & 0xff);
7310 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
7311 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
7312 data[idx + 3] = (byte) (fval >> 24);
7314 case BuiltinTypeSpec.Type.Double:
7315 element = BitConverter.GetBytes ((double) v);
7317 for (int j = 0; j < factor; ++j)
7318 data[idx + j] = element[j];
7320 // FIXME: Handle the ARM float format.
7321 if (!BitConverter.IsLittleEndian)
7322 System.Array.Reverse (data, idx, 8);
7324 case BuiltinTypeSpec.Type.Char:
7325 int chval = (int) ((char) v);
7327 data[idx] = (byte) (chval & 0xff);
7328 data[idx + 1] = (byte) (chval >> 8);
7330 case BuiltinTypeSpec.Type.Short:
7331 int sval = (int) ((short) v);
7333 data[idx] = (byte) (sval & 0xff);
7334 data[idx + 1] = (byte) (sval >> 8);
7336 case BuiltinTypeSpec.Type.UShort:
7337 int usval = (int) ((ushort) v);
7339 data[idx] = (byte) (usval & 0xff);
7340 data[idx + 1] = (byte) (usval >> 8);
7342 case BuiltinTypeSpec.Type.Int:
7345 data[idx] = (byte) (val & 0xff);
7346 data[idx + 1] = (byte) ((val >> 8) & 0xff);
7347 data[idx + 2] = (byte) ((val >> 16) & 0xff);
7348 data[idx + 3] = (byte) (val >> 24);
7350 case BuiltinTypeSpec.Type.UInt:
7351 uint uval = (uint) v;
7353 data[idx] = (byte) (uval & 0xff);
7354 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
7355 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
7356 data[idx + 3] = (byte) (uval >> 24);
7358 case BuiltinTypeSpec.Type.SByte:
7359 data[idx] = (byte) (sbyte) v;
7361 case BuiltinTypeSpec.Type.Byte:
7362 data[idx] = (byte) v;
7364 case BuiltinTypeSpec.Type.Bool:
7365 data[idx] = (byte) ((bool) v ? 1 : 0);
7367 case BuiltinTypeSpec.Type.Decimal:
7368 int[] bits = Decimal.GetBits ((decimal) v);
7371 // FIXME: For some reason, this doesn't work on the MS runtime.
7372 int[] nbits = new int[4];
7378 for (int j = 0; j < 4; j++) {
7379 data[p++] = (byte) (nbits[j] & 0xff);
7380 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
7381 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
7382 data[p++] = (byte) (nbits[j] >> 24);
7386 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
7395 #if NET_4_0 || MONODROID
7396 public override SLE.Expression MakeExpression (BuilderContext ctx)
7399 return base.MakeExpression (ctx);
7401 var initializers = new SLE.Expression [array_data.Count];
7402 for (var i = 0; i < initializers.Length; i++) {
7403 if (array_data [i] == null)
7404 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
7406 initializers [i] = array_data [i].MakeExpression (ctx);
7409 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
7415 // Emits the initializers for the array
7417 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
7419 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
7424 // First, the static data
7426 byte [] data = MakeByteBlob ();
7427 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
7429 if (stackArray == null) {
7430 ec.Emit (OpCodes.Dup);
7432 stackArray.Emit (ec);
7435 ec.Emit (OpCodes.Ldtoken, fb);
7436 ec.Emit (OpCodes.Call, m);
7441 // Emits pieces of the array that can not be computed at compile
7442 // time (variables and string locations).
7444 // This always expect the top value on the stack to be the array
7446 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
7448 int dims = bounds.Count;
7449 var current_pos = new int [dims];
7451 for (int i = 0; i < array_data.Count; i++){
7453 Expression e = array_data [i];
7454 var c = e as Constant;
7456 // Constant can be initialized via StaticInitializer
7457 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
7461 if (stackArray != null) {
7462 if (e.ContainsEmitWithAwait ()) {
7463 e = e.EmitToField (ec);
7466 stackArray.Emit (ec);
7468 ec.Emit (OpCodes.Dup);
7471 for (int idx = 0; idx < dims; idx++)
7472 ec.EmitInt (current_pos [idx]);
7475 // If we are dealing with a struct, get the
7476 // address of it, so we can store it.
7478 if (dims == 1 && etype.IsStruct) {
7479 switch (etype.BuiltinType) {
7480 case BuiltinTypeSpec.Type.Byte:
7481 case BuiltinTypeSpec.Type.SByte:
7482 case BuiltinTypeSpec.Type.Bool:
7483 case BuiltinTypeSpec.Type.Short:
7484 case BuiltinTypeSpec.Type.UShort:
7485 case BuiltinTypeSpec.Type.Char:
7486 case BuiltinTypeSpec.Type.Int:
7487 case BuiltinTypeSpec.Type.UInt:
7488 case BuiltinTypeSpec.Type.Long:
7489 case BuiltinTypeSpec.Type.ULong:
7490 case BuiltinTypeSpec.Type.Float:
7491 case BuiltinTypeSpec.Type.Double:
7494 ec.Emit (OpCodes.Ldelema, etype);
7501 ec.EmitArrayStore ((ArrayContainer) type);
7507 for (int j = dims - 1; j >= 0; j--){
7509 if (current_pos [j] < bounds [j])
7511 current_pos [j] = 0;
7516 public override void Emit (EmitContext ec)
7518 EmitToFieldSource (ec);
7521 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
7523 if (first_emit != null) {
7524 first_emit.Emit (ec);
7525 first_emit_temp.Store (ec);
7528 FieldExpr await_stack_field;
7529 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
7530 await_stack_field = ec.GetTemporaryField (type);
7533 await_stack_field = null;
7536 EmitExpressionsList (ec, arguments);
7538 ec.EmitArrayNew ((ArrayContainer) type);
7540 if (initializers == null)
7541 return await_stack_field;
7543 if (await_stack_field != null)
7544 await_stack_field.EmitAssignFromStack (ec);
7548 // Emit static initializer for arrays which contain more than 2 items and
7549 // the static initializer will initialize at least 25% of array values or there
7550 // is more than 10 items to be initialized
7552 // NOTE: const_initializers_count does not contain default constant values.
7554 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
7555 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
7556 EmitStaticInitializers (ec, await_stack_field);
7558 if (!only_constant_initializers)
7559 EmitDynamicInitializers (ec, false, await_stack_field);
7563 EmitDynamicInitializers (ec, true, await_stack_field);
7566 if (first_emit_temp != null)
7567 first_emit_temp.Release (ec);
7569 return await_stack_field;
7572 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7574 // no multi dimensional or jagged arrays
7575 if (arguments.Count != 1 || array_element_type.IsArray) {
7576 base.EncodeAttributeValue (rc, enc, targetType);
7580 // No array covariance, except for array -> object
7581 if (type != targetType) {
7582 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
7583 base.EncodeAttributeValue (rc, enc, targetType);
7587 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
7588 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7593 // Single dimensional array of 0 size
7594 if (array_data == null) {
7595 IntConstant ic = arguments[0] as IntConstant;
7596 if (ic == null || !ic.IsDefaultValue) {
7597 base.EncodeAttributeValue (rc, enc, targetType);
7605 enc.Encode (array_data.Count);
7606 foreach (var element in array_data) {
7607 element.EncodeAttributeValue (rc, enc, array_element_type);
7611 protected override void CloneTo (CloneContext clonectx, Expression t)
7613 ArrayCreation target = (ArrayCreation) t;
7615 if (requested_base_type != null)
7616 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
7618 if (arguments != null){
7619 target.arguments = new List<Expression> (arguments.Count);
7620 foreach (Expression e in arguments)
7621 target.arguments.Add (e.Clone (clonectx));
7624 if (initializers != null)
7625 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
7628 public override object Accept (StructuralVisitor visitor)
7630 return visitor.Visit (this);
7635 // Represents an implicitly typed array epxression
7637 class ImplicitlyTypedArrayCreation : ArrayCreation
7639 TypeInferenceContext best_type_inference;
7641 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7642 : base (null, rank, initializers, loc)
7646 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
7647 : base (null, initializers, loc)
7651 protected override Expression DoResolve (ResolveContext ec)
7656 dimensions = rank.Dimension;
7658 best_type_inference = new TypeInferenceContext ();
7660 if (!ResolveInitializers (ec))
7663 best_type_inference.FixAllTypes (ec);
7664 array_element_type = best_type_inference.InferredTypeArguments[0];
7665 best_type_inference = null;
7667 if (array_element_type == null ||
7668 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
7669 arguments.Count != rank.Dimension) {
7670 ec.Report.Error (826, loc,
7671 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
7676 // At this point we found common base type for all initializer elements
7677 // but we have to be sure that all static initializer elements are of
7680 UnifyInitializerElement (ec);
7682 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
7683 eclass = ExprClass.Value;
7688 // Converts static initializer only
7690 void UnifyInitializerElement (ResolveContext ec)
7692 for (int i = 0; i < array_data.Count; ++i) {
7693 Expression e = array_data[i];
7695 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
7699 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
7701 element = element.Resolve (ec);
7702 if (element != null)
7703 best_type_inference.AddCommonTypeBound (element.Type);
7709 sealed class CompilerGeneratedThis : This
7711 public CompilerGeneratedThis (TypeSpec type, Location loc)
7715 eclass = ExprClass.Variable;
7718 protected override Expression DoResolve (ResolveContext ec)
7723 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7730 /// Represents the `this' construct
7733 public class This : VariableReference
7735 sealed class ThisVariable : ILocalVariable
7737 public static readonly ILocalVariable Instance = new ThisVariable ();
7739 public void Emit (EmitContext ec)
7744 public void EmitAssign (EmitContext ec)
7746 throw new InvalidOperationException ();
7749 public void EmitAddressOf (EmitContext ec)
7755 VariableInfo variable_info;
7757 public This (Location loc)
7764 public override string Name {
7765 get { return "this"; }
7768 public override bool IsLockedByStatement {
7776 public override bool IsRef {
7777 get { return type.IsStruct; }
7780 public override bool IsSideEffectFree {
7786 protected override ILocalVariable Variable {
7787 get { return ThisVariable.Instance; }
7790 public override VariableInfo VariableInfo {
7791 get { return variable_info; }
7794 public override bool IsFixed {
7795 get { return false; }
7800 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
7803 // It's null for all cases when we don't need to check `this'
7804 // definitive assignment
7806 if (variable_info == null)
7809 if (fc.IsDefinitelyAssigned (variable_info))
7812 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
7815 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7817 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7818 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7819 } else if (ec.CurrentAnonymousMethod != null) {
7820 ec.Report.Error (1673, loc,
7821 "Anonymous methods inside structs cannot access instance members of `this'. " +
7822 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7824 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7828 public override void FlowAnalysis (FlowAnalysisContext fc)
7830 CheckStructThisDefiniteAssignment (fc);
7833 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7838 AnonymousMethodStorey storey = ae.Storey;
7839 return storey != null ? storey.HoistedThis : null;
7842 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7844 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7847 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7850 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7856 public virtual void ResolveBase (ResolveContext ec)
7858 eclass = ExprClass.Variable;
7859 type = ec.CurrentType;
7861 if (!IsThisAvailable (ec, false)) {
7862 Error_ThisNotAvailable (ec);
7866 var block = ec.CurrentBlock;
7867 if (block != null) {
7868 var top = block.ParametersBlock.TopBlock;
7869 if (top.ThisVariable != null)
7870 variable_info = top.ThisVariable.VariableInfo;
7872 AnonymousExpression am = ec.CurrentAnonymousMethod;
7873 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7875 // Hoisted this is almost like hoisted variable but not exactly. When
7876 // there is no variable hoisted we can simply emit an instance method
7877 // without lifting this into a storey. Unfotunatelly this complicates
7878 // things in other cases because we don't know where this will be hoisted
7879 // until top-level block is fully resolved
7881 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7882 am.SetHasThisAccess ();
7887 protected override Expression DoResolve (ResolveContext ec)
7893 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7895 if (eclass == ExprClass.Unresolved)
7899 if (right_side == EmptyExpression.UnaryAddress)
7900 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7901 else if (right_side == EmptyExpression.OutAccess)
7902 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7904 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7910 public override int GetHashCode()
7912 throw new NotImplementedException ();
7915 public override bool Equals (object obj)
7917 This t = obj as This;
7924 protected override void CloneTo (CloneContext clonectx, Expression t)
7929 public override void SetHasAddressTaken ()
7934 public override object Accept (StructuralVisitor visitor)
7936 return visitor.Visit (this);
7941 /// Represents the `__arglist' construct
7943 public class ArglistAccess : Expression
7945 public ArglistAccess (Location loc)
7950 protected override void CloneTo (CloneContext clonectx, Expression target)
7955 public override bool ContainsEmitWithAwait ()
7960 public override Expression CreateExpressionTree (ResolveContext ec)
7962 throw new NotSupportedException ("ET");
7965 protected override Expression DoResolve (ResolveContext ec)
7967 eclass = ExprClass.Variable;
7968 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
7970 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7971 ec.Report.Error (190, loc,
7972 "The __arglist construct is valid only within a variable argument method");
7978 public override void Emit (EmitContext ec)
7980 ec.Emit (OpCodes.Arglist);
7983 public override object Accept (StructuralVisitor visitor)
7985 return visitor.Visit (this);
7990 /// Represents the `__arglist (....)' construct
7992 public class Arglist : Expression
7994 Arguments arguments;
7996 public Arglist (Location loc)
8001 public Arglist (Arguments args, Location l)
8007 public Arguments Arguments {
8013 public MetaType[] ArgumentTypes {
8015 if (arguments == null)
8016 return MetaType.EmptyTypes;
8018 var retval = new MetaType[arguments.Count];
8019 for (int i = 0; i < retval.Length; i++)
8020 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8026 public override bool ContainsEmitWithAwait ()
8028 throw new NotImplementedException ();
8031 public override Expression CreateExpressionTree (ResolveContext ec)
8033 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8037 protected override Expression DoResolve (ResolveContext ec)
8039 eclass = ExprClass.Variable;
8040 type = InternalType.Arglist;
8041 if (arguments != null) {
8042 bool dynamic; // Can be ignored as there is always only 1 overload
8043 arguments.Resolve (ec, out dynamic);
8049 public override void Emit (EmitContext ec)
8051 if (arguments != null)
8052 arguments.Emit (ec);
8055 protected override void CloneTo (CloneContext clonectx, Expression t)
8057 Arglist target = (Arglist) t;
8059 if (arguments != null)
8060 target.arguments = arguments.Clone (clonectx);
8063 public override object Accept (StructuralVisitor visitor)
8065 return visitor.Visit (this);
8069 public class RefValueExpr : ShimExpression, IAssignMethod
8071 FullNamedExpression texpr;
8073 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8080 public FullNamedExpression TypeExpression {
8086 public override bool ContainsEmitWithAwait ()
8091 protected override Expression DoResolve (ResolveContext rc)
8093 expr = expr.Resolve (rc);
8094 type = texpr.ResolveAsType (rc);
8095 if (expr == null || type == null)
8098 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8099 eclass = ExprClass.Value;
8103 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8105 return DoResolve (rc);
8108 public override void Emit (EmitContext ec)
8111 ec.Emit (OpCodes.Refanyval, type);
8112 ec.EmitLoadFromPtr (type);
8115 public void Emit (EmitContext ec, bool leave_copy)
8117 throw new NotImplementedException ();
8120 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8123 ec.Emit (OpCodes.Refanyval, type);
8126 LocalTemporary temporary = null;
8128 ec.Emit (OpCodes.Dup);
8129 temporary = new LocalTemporary (source.Type);
8130 temporary.Store (ec);
8133 ec.EmitStoreFromPtr (type);
8135 if (temporary != null) {
8136 temporary.Emit (ec);
8137 temporary.Release (ec);
8141 public override object Accept (StructuralVisitor visitor)
8143 return visitor.Visit (this);
8147 public class RefTypeExpr : ShimExpression
8149 public RefTypeExpr (Expression expr, Location loc)
8155 protected override Expression DoResolve (ResolveContext rc)
8157 expr = expr.Resolve (rc);
8161 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8165 type = rc.BuiltinTypes.Type;
8166 eclass = ExprClass.Value;
8170 public override void Emit (EmitContext ec)
8173 ec.Emit (OpCodes.Refanytype);
8174 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8176 ec.Emit (OpCodes.Call, m);
8179 public override object Accept (StructuralVisitor visitor)
8181 return visitor.Visit (this);
8185 public class MakeRefExpr : ShimExpression
8187 public MakeRefExpr (Expression expr, Location loc)
8193 public override bool ContainsEmitWithAwait ()
8195 throw new NotImplementedException ();
8198 protected override Expression DoResolve (ResolveContext rc)
8200 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8201 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8202 eclass = ExprClass.Value;
8206 public override void Emit (EmitContext ec)
8208 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8209 ec.Emit (OpCodes.Mkrefany, expr.Type);
8212 public override object Accept (StructuralVisitor visitor)
8214 return visitor.Visit (this);
8219 /// Implements the typeof operator
8221 public class TypeOf : Expression {
8222 FullNamedExpression QueriedType;
8225 public TypeOf (FullNamedExpression queried_type, Location l)
8227 QueriedType = queried_type;
8232 // Use this constructor for any compiler generated typeof expression
8234 public TypeOf (TypeSpec type, Location loc)
8236 this.typearg = type;
8242 public override bool IsSideEffectFree {
8248 public TypeSpec TypeArgument {
8254 public FullNamedExpression TypeExpression {
8263 protected override void CloneTo (CloneContext clonectx, Expression t)
8265 TypeOf target = (TypeOf) t;
8266 if (QueriedType != null)
8267 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
8270 public override bool ContainsEmitWithAwait ()
8275 public override Expression CreateExpressionTree (ResolveContext ec)
8277 Arguments args = new Arguments (2);
8278 args.Add (new Argument (this));
8279 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8280 return CreateExpressionFactoryCall (ec, "Constant", args);
8283 protected override Expression DoResolve (ResolveContext ec)
8285 if (eclass != ExprClass.Unresolved)
8288 if (typearg == null) {
8290 // Pointer types are allowed without explicit unsafe, they are just tokens
8292 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
8293 typearg = QueriedType.ResolveAsType (ec);
8296 if (typearg == null)
8299 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8300 ec.Report.Error (1962, QueriedType.Location,
8301 "The typeof operator cannot be used on the dynamic type");
8305 type = ec.BuiltinTypes.Type;
8307 // Even though what is returned is a type object, it's treated as a value by the compiler.
8308 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
8309 eclass = ExprClass.Value;
8313 static bool ContainsDynamicType (TypeSpec type)
8315 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
8318 var element_container = type as ElementTypeSpec;
8319 if (element_container != null)
8320 return ContainsDynamicType (element_container.Element);
8322 foreach (var t in type.TypeArguments) {
8323 if (ContainsDynamicType (t)) {
8331 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
8333 // Target type is not System.Type therefore must be object
8334 // and we need to use different encoding sequence
8335 if (targetType != type)
8338 if (typearg is InflatedTypeSpec) {
8341 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
8342 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
8343 typearg.GetSignatureForError ());
8347 gt = gt.DeclaringType;
8348 } while (gt != null);
8351 if (ContainsDynamicType (typearg)) {
8352 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8356 enc.EncodeTypeName (typearg);
8359 public override void Emit (EmitContext ec)
8361 ec.Emit (OpCodes.Ldtoken, typearg);
8362 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8364 ec.Emit (OpCodes.Call, m);
8367 public override object Accept (StructuralVisitor visitor)
8369 return visitor.Visit (this);
8373 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
8375 public TypeOfMethod (MethodSpec method, Location loc)
8376 : base (method, loc)
8380 protected override Expression DoResolve (ResolveContext ec)
8382 if (member.IsConstructor) {
8383 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
8385 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
8391 return base.DoResolve (ec);
8394 public override void Emit (EmitContext ec)
8396 ec.Emit (OpCodes.Ldtoken, member);
8399 ec.Emit (OpCodes.Castclass, type);
8402 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8404 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
8407 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8409 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
8413 abstract class TypeOfMember<T> : Expression where T : MemberSpec
8415 protected readonly T member;
8417 protected TypeOfMember (T member, Location loc)
8419 this.member = member;
8423 public override bool IsSideEffectFree {
8429 public override bool ContainsEmitWithAwait ()
8434 public override Expression CreateExpressionTree (ResolveContext ec)
8436 Arguments args = new Arguments (2);
8437 args.Add (new Argument (this));
8438 args.Add (new Argument (new TypeOf (type, loc)));
8439 return CreateExpressionFactoryCall (ec, "Constant", args);
8442 protected override Expression DoResolve (ResolveContext ec)
8444 eclass = ExprClass.Value;
8448 public override void Emit (EmitContext ec)
8450 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
8451 PredefinedMember<MethodSpec> p;
8453 p = GetTypeFromHandleGeneric (ec);
8454 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
8456 p = GetTypeFromHandle (ec);
8459 var mi = p.Resolve (loc);
8461 ec.Emit (OpCodes.Call, mi);
8464 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
8465 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
8468 sealed class TypeOfField : TypeOfMember<FieldSpec>
8470 public TypeOfField (FieldSpec field, Location loc)
8475 protected override Expression DoResolve (ResolveContext ec)
8477 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
8481 return base.DoResolve (ec);
8484 public override void Emit (EmitContext ec)
8486 ec.Emit (OpCodes.Ldtoken, member);
8490 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8492 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
8495 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8497 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
8502 /// Implements the sizeof expression
8504 public class SizeOf : Expression {
8505 readonly Expression texpr;
8506 TypeSpec type_queried;
8508 public SizeOf (Expression queried_type, Location l)
8510 this.texpr = queried_type;
8514 public override bool IsSideEffectFree {
8520 public Expression TypeExpression {
8526 public override bool ContainsEmitWithAwait ()
8531 public override Expression CreateExpressionTree (ResolveContext ec)
8533 Error_PointerInsideExpressionTree (ec);
8537 protected override Expression DoResolve (ResolveContext ec)
8539 type_queried = texpr.ResolveAsType (ec);
8540 if (type_queried == null)
8543 if (type_queried.IsEnum)
8544 type_queried = EnumSpec.GetUnderlyingType (type_queried);
8546 int size_of = BuiltinTypeSpec.GetSize (type_queried);
8548 return new IntConstant (ec.BuiltinTypes, size_of, loc);
8551 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
8556 ec.Report.Error (233, loc,
8557 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
8558 type_queried.GetSignatureForError ());
8561 type = ec.BuiltinTypes.Int;
8562 eclass = ExprClass.Value;
8566 public override void Emit (EmitContext ec)
8568 ec.Emit (OpCodes.Sizeof, type_queried);
8571 protected override void CloneTo (CloneContext clonectx, Expression t)
8575 public override object Accept (StructuralVisitor visitor)
8577 return visitor.Visit (this);
8582 /// Implements the qualified-alias-member (::) expression.
8584 public class QualifiedAliasMember : MemberAccess
8586 readonly string alias;
8587 public static readonly string GlobalAlias = "global";
8589 public QualifiedAliasMember (string alias, string identifier, Location l)
8590 : base (null, identifier, l)
8595 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
8596 : base (null, identifier, targs, l)
8601 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
8602 : base (null, identifier, arity, l)
8607 public string Alias {
8613 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
8615 if (alias == GlobalAlias) {
8616 expr = ec.Module.GlobalRootNamespace;
8617 return base.ResolveAsTypeOrNamespace (ec);
8620 int errors = ec.Module.Compiler.Report.Errors;
8621 expr = ec.LookupNamespaceAlias (alias);
8623 if (errors == ec.Module.Compiler.Report.Errors)
8624 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
8628 return base.ResolveAsTypeOrNamespace (ec);
8631 protected override Expression DoResolve (ResolveContext ec)
8633 return ResolveAsTypeOrNamespace (ec);
8636 public override string GetSignatureForError ()
8639 if (targs != null) {
8640 name = Name + "<" + targs.GetSignatureForError () + ">";
8643 return alias + "::" + name;
8646 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8648 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
8649 rc.Module.Compiler.Report.Error (687, loc,
8650 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
8651 GetSignatureForError ());
8656 return DoResolve (rc);
8659 protected override void CloneTo (CloneContext clonectx, Expression t)
8664 public override object Accept (StructuralVisitor visitor)
8666 return visitor.Visit (this);
8671 /// Implements the member access expression
8673 public class MemberAccess : ATypeNameExpression
8675 protected Expression expr;
8677 public MemberAccess (Expression expr, string id)
8678 : base (id, expr.Location)
8683 public MemberAccess (Expression expr, string identifier, Location loc)
8684 : base (identifier, loc)
8689 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
8690 : base (identifier, args, loc)
8695 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
8696 : base (identifier, arity, loc)
8701 public Expression LeftExpression {
8707 public override Location StartLocation {
8709 return expr == null ? loc : expr.StartLocation;
8713 protected override Expression DoResolve (ResolveContext rc)
8715 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
8717 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
8722 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
8724 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
8726 if (e is TypeExpr) {
8727 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8732 e = e.ResolveLValue (rc, rhs);
8737 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8739 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8740 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8742 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8745 public static bool IsValidDotExpression (TypeSpec type)
8747 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8748 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8750 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8753 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8755 var sn = expr as SimpleName;
8756 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8759 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8762 // Resolve expression which does have type set as we need expression type
8763 // with disable flow analysis as we don't know whether left side expression
8764 // is used as variable or type
8766 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8767 expr = expr.Resolve (rc);
8768 } else if (expr is TypeParameterExpr) {
8769 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8773 expr = expr.Resolve (rc, flags);
8779 Namespace ns = expr as Namespace;
8781 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8783 if (retval == null) {
8784 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8788 if (HasTypeArguments)
8789 return new GenericTypeExpr (retval.Type, targs, loc);
8795 TypeSpec expr_type = expr.Type;
8796 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8797 me = expr as MemberExpr;
8799 me.ResolveInstanceExpression (rc, null);
8801 Arguments args = new Arguments (1);
8802 args.Add (new Argument (expr));
8803 return new DynamicMemberBinder (Name, args, loc);
8806 if (!IsValidDotExpression (expr_type)) {
8807 Error_OperatorCannotBeApplied (rc, expr_type);
8811 var lookup_arity = Arity;
8812 bool errorMode = false;
8813 Expression member_lookup;
8815 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8816 if (member_lookup == null) {
8818 // Try to look for extension method when member lookup failed
8820 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8821 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8822 if (methods != null) {
8823 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8824 if (HasTypeArguments) {
8825 if (!targs.Resolve (rc))
8828 emg.SetTypeArguments (rc, targs);
8831 // TODO: it should really skip the checks bellow
8832 return emg.Resolve (rc);
8838 if (member_lookup == null) {
8839 var dep = expr_type.GetMissingDependencies ();
8841 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8842 } else if (expr is TypeExpr) {
8843 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8845 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8851 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8852 // Leave it to overload resolution to report correct error
8853 } else if (!(member_lookup is TypeExpr)) {
8854 // TODO: rc.SymbolRelatedToPreviousError
8855 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8860 if (member_lookup != null)
8864 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8868 TypeExpr texpr = member_lookup as TypeExpr;
8869 if (texpr != null) {
8870 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8871 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8872 Name, texpr.GetSignatureForError ());
8875 if (!texpr.Type.IsAccessible (rc)) {
8876 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8877 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8881 if (HasTypeArguments) {
8882 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8885 return member_lookup;
8888 me = member_lookup as MemberExpr;
8890 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8894 me = me.ResolveMemberAccess (rc, expr, sn);
8897 if (!targs.Resolve (rc))
8900 me.SetTypeArguments (rc, targs);
8906 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8908 FullNamedExpression fexpr = expr as FullNamedExpression;
8909 if (fexpr == null) {
8910 expr.ResolveAsType (rc);
8914 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8916 if (expr_resolved == null)
8919 Namespace ns = expr_resolved as Namespace;
8921 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8923 if (retval == null) {
8924 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8925 } else if (HasTypeArguments) {
8926 retval = new GenericTypeExpr (retval.Type, targs, loc);
8927 if (retval.ResolveAsType (rc) == null)
8934 var tnew_expr = expr_resolved.ResolveAsType (rc);
8935 if (tnew_expr == null)
8938 TypeSpec expr_type = tnew_expr;
8939 if (TypeManager.IsGenericParameter (expr_type)) {
8940 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8941 tnew_expr.GetSignatureForError ());
8945 var qam = this as QualifiedAliasMember;
8947 rc.Module.Compiler.Report.Error (431, loc,
8948 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8953 TypeSpec nested = null;
8954 while (expr_type != null) {
8955 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8956 if (nested == null) {
8957 if (expr_type == tnew_expr) {
8958 Error_IdentifierNotFound (rc, expr_type, Name);
8962 expr_type = tnew_expr;
8963 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8964 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
8968 if (nested.IsAccessible (rc))
8972 // Keep looking after inaccessible candidate but only if
8973 // we are not in same context as the definition itself
8975 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
8978 expr_type = expr_type.BaseType;
8983 if (HasTypeArguments) {
8984 texpr = new GenericTypeExpr (nested, targs, loc);
8986 texpr = new GenericOpenTypeExpr (nested, loc);
8989 texpr = new TypeExpression (nested, loc);
8992 if (texpr.ResolveAsType (rc) == null)
8998 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
9000 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9002 if (nested != null) {
9003 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9007 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9008 if (any_other_member != null) {
9009 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9013 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9014 Name, expr_type.GetSignatureForError ());
9017 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9019 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9022 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9024 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9025 ec.Report.SymbolRelatedToPreviousError (type);
9027 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9029 // a using directive or an assembly reference
9031 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9033 missing = "an assembly reference";
9036 ec.Report.Error (1061, loc,
9037 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9038 type.GetSignatureForError (), name, missing);
9042 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9045 public override string GetSignatureForError ()
9047 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9050 protected override void CloneTo (CloneContext clonectx, Expression t)
9052 MemberAccess target = (MemberAccess) t;
9054 target.expr = expr.Clone (clonectx);
9057 public override object Accept (StructuralVisitor visitor)
9059 return visitor.Visit (this);
9064 /// Implements checked expressions
9066 public class CheckedExpr : Expression {
9068 public Expression Expr;
9070 public CheckedExpr (Expression e, Location l)
9076 public override bool ContainsEmitWithAwait ()
9078 return Expr.ContainsEmitWithAwait ();
9081 public override Expression CreateExpressionTree (ResolveContext ec)
9083 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9084 return Expr.CreateExpressionTree (ec);
9087 protected override Expression DoResolve (ResolveContext ec)
9089 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9090 Expr = Expr.Resolve (ec);
9095 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9098 eclass = Expr.eclass;
9103 public override void Emit (EmitContext ec)
9105 using (ec.With (EmitContext.Options.CheckedScope, true))
9109 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9111 using (ec.With (EmitContext.Options.CheckedScope, true))
9112 Expr.EmitBranchable (ec, target, on_true);
9115 public override void FlowAnalysis (FlowAnalysisContext fc)
9117 Expr.FlowAnalysis (fc);
9120 public override SLE.Expression MakeExpression (BuilderContext ctx)
9122 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9123 return Expr.MakeExpression (ctx);
9127 protected override void CloneTo (CloneContext clonectx, Expression t)
9129 CheckedExpr target = (CheckedExpr) t;
9131 target.Expr = Expr.Clone (clonectx);
9134 public override object Accept (StructuralVisitor visitor)
9136 return visitor.Visit (this);
9141 /// Implements the unchecked expression
9143 public class UnCheckedExpr : Expression {
9145 public Expression Expr;
9147 public UnCheckedExpr (Expression e, Location l)
9153 public override bool ContainsEmitWithAwait ()
9155 return Expr.ContainsEmitWithAwait ();
9158 public override Expression CreateExpressionTree (ResolveContext ec)
9160 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9161 return Expr.CreateExpressionTree (ec);
9164 protected override Expression DoResolve (ResolveContext ec)
9166 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9167 Expr = Expr.Resolve (ec);
9172 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9175 eclass = Expr.eclass;
9180 public override void Emit (EmitContext ec)
9182 using (ec.With (EmitContext.Options.CheckedScope, false))
9186 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9188 using (ec.With (EmitContext.Options.CheckedScope, false))
9189 Expr.EmitBranchable (ec, target, on_true);
9192 public override void FlowAnalysis (FlowAnalysisContext fc)
9194 Expr.FlowAnalysis (fc);
9197 protected override void CloneTo (CloneContext clonectx, Expression t)
9199 UnCheckedExpr target = (UnCheckedExpr) t;
9201 target.Expr = Expr.Clone (clonectx);
9204 public override object Accept (StructuralVisitor visitor)
9206 return visitor.Visit (this);
9211 /// An Element Access expression.
9213 /// During semantic analysis these are transformed into
9214 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
9216 public class ElementAccess : Expression
9218 public Arguments Arguments;
9219 public Expression Expr;
9221 public ElementAccess (Expression e, Arguments args, Location loc)
9225 this.Arguments = args;
9228 public override Location StartLocation {
9230 return Expr.StartLocation;
9234 public override bool ContainsEmitWithAwait ()
9236 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
9240 // We perform some simple tests, and then to "split" the emit and store
9241 // code we create an instance of a different class, and return that.
9243 Expression CreateAccessExpression (ResolveContext ec)
9246 return (new ArrayAccess (this, loc));
9249 return MakePointerAccess (ec, type);
9251 FieldExpr fe = Expr as FieldExpr;
9253 var ff = fe.Spec as FixedFieldSpec;
9255 return MakePointerAccess (ec, ff.ElementType);
9259 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
9260 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9261 return new IndexerExpr (indexers, type, this);
9264 if (type != InternalType.ErrorType) {
9265 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
9266 type.GetSignatureForError ());
9272 public override Expression CreateExpressionTree (ResolveContext ec)
9274 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
9275 Expr.CreateExpressionTree (ec));
9277 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
9280 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
9282 if (Arguments.Count != 1){
9283 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
9287 if (Arguments [0] is NamedArgument)
9288 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
9290 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
9291 return new Indirection (p, loc);
9294 protected override Expression DoResolve (ResolveContext ec)
9296 Expr = Expr.Resolve (ec);
9302 // TODO: Create 1 result for Resolve and ResolveLValue ?
9303 var res = CreateAccessExpression (ec);
9307 return res.Resolve (ec);
9310 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
9312 Expr = Expr.Resolve (ec);
9318 var res = CreateAccessExpression (ec);
9322 return res.ResolveLValue (ec, rhs);
9325 public override void Emit (EmitContext ec)
9327 throw new Exception ("Should never be reached");
9330 public static void Error_NamedArgument (NamedArgument na, Report Report)
9332 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
9335 public override void FlowAnalysis (FlowAnalysisContext fc)
9337 Expr.FlowAnalysis (fc);
9338 Arguments.FlowAnalysis (fc);
9341 public override string GetSignatureForError ()
9343 return Expr.GetSignatureForError ();
9346 protected override void CloneTo (CloneContext clonectx, Expression t)
9348 ElementAccess target = (ElementAccess) t;
9350 target.Expr = Expr.Clone (clonectx);
9351 if (Arguments != null)
9352 target.Arguments = Arguments.Clone (clonectx);
9355 public override object Accept (StructuralVisitor visitor)
9357 return visitor.Visit (this);
9362 /// Implements array access
9364 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
9366 // Points to our "data" repository
9370 LocalTemporary temp;
9372 bool? has_await_args;
9374 public ArrayAccess (ElementAccess ea_data, Location l)
9380 public void AddressOf (EmitContext ec, AddressOp mode)
9382 var ac = (ArrayContainer) ea.Expr.Type;
9384 LoadInstanceAndArguments (ec, false, false);
9386 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
9387 ec.Emit (OpCodes.Readonly);
9389 ec.EmitArrayAddress (ac);
9392 public override Expression CreateExpressionTree (ResolveContext ec)
9394 return ea.CreateExpressionTree (ec);
9397 public override bool ContainsEmitWithAwait ()
9399 return ea.ContainsEmitWithAwait ();
9402 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9404 return DoResolve (ec);
9407 protected override Expression DoResolve (ResolveContext ec)
9409 // dynamic is used per argument in ConvertExpressionToArrayIndex case
9411 ea.Arguments.Resolve (ec, out dynamic);
9413 var ac = ea.Expr.Type as ArrayContainer;
9414 int rank = ea.Arguments.Count;
9415 if (ac.Rank != rank) {
9416 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
9417 rank.ToString (), ac.Rank.ToString ());
9422 if (type.IsPointer && !ec.IsUnsafe) {
9423 UnsafeError (ec, ea.Location);
9426 foreach (Argument a in ea.Arguments) {
9427 if (a is NamedArgument)
9428 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
9430 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
9433 eclass = ExprClass.Variable;
9438 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
9440 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
9443 public override void FlowAnalysis (FlowAnalysisContext fc)
9445 ea.FlowAnalysis (fc);
9449 // Load the array arguments into the stack.
9451 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
9454 ea.Expr = ea.Expr.EmitToField (ec);
9455 } else if (duplicateArguments) {
9457 ec.Emit (OpCodes.Dup);
9459 var copy = new LocalTemporary (ea.Expr.Type);
9466 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
9467 if (dup_args != null)
9468 ea.Arguments = dup_args;
9471 public void Emit (EmitContext ec, bool leave_copy)
9473 var ac = ea.Expr.Type as ArrayContainer;
9476 ec.EmitLoadFromPtr (type);
9478 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
9479 LoadInstanceAndArguments (ec, false, true);
9482 LoadInstanceAndArguments (ec, false, false);
9483 ec.EmitArrayLoad (ac);
9487 ec.Emit (OpCodes.Dup);
9488 temp = new LocalTemporary (this.type);
9493 public override void Emit (EmitContext ec)
9498 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9500 var ac = (ArrayContainer) ea.Expr.Type;
9501 TypeSpec t = source.Type;
9503 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
9506 // When we are dealing with a struct, get the address of it to avoid value copy
9507 // Same cannot be done for reference type because array covariance and the
9508 // check in ldelema requires to specify the type of array element stored at the index
9510 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
9511 LoadInstanceAndArguments (ec, false, has_await_args.Value);
9513 if (has_await_args.Value) {
9514 if (source.ContainsEmitWithAwait ()) {
9515 source = source.EmitToField (ec);
9520 LoadInstanceAndArguments (ec, isCompound, false);
9525 ec.EmitArrayAddress (ac);
9528 ec.Emit (OpCodes.Dup);
9532 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
9534 if (has_await_args.Value) {
9535 if (source.ContainsEmitWithAwait ())
9536 source = source.EmitToField (ec);
9538 LoadInstanceAndArguments (ec, false, false);
9545 var lt = ea.Expr as LocalTemporary;
9551 ec.Emit (OpCodes.Dup);
9552 temp = new LocalTemporary (this.type);
9557 ec.EmitStoreFromPtr (t);
9559 ec.EmitArrayStore (ac);
9568 public override Expression EmitToField (EmitContext ec)
9571 // Have to be specialized for arrays to get access to
9572 // underlying element. Instead of another result copy we
9573 // need direct access to element
9577 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
9579 ea.Expr = ea.Expr.EmitToField (ec);
9583 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9585 #if NET_4_0 || MONODROID
9586 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9588 throw new NotImplementedException ();
9592 public override SLE.Expression MakeExpression (BuilderContext ctx)
9594 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9597 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
9599 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9600 return Arguments.MakeExpression (ea.Arguments, ctx);
9606 // Indexer access expression
9608 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
9610 IList<MemberSpec> indexers;
9611 Arguments arguments;
9612 TypeSpec queried_type;
9614 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
9615 : base (ea.Location)
9617 this.indexers = indexers;
9618 this.queried_type = queriedType;
9619 this.InstanceExpression = ea.Expr;
9620 this.arguments = ea.Arguments;
9625 protected override Arguments Arguments {
9634 protected override TypeSpec DeclaringType {
9636 return best_candidate.DeclaringType;
9640 public override bool IsInstance {
9646 public override bool IsStatic {
9652 public override string KindName {
9653 get { return "indexer"; }
9656 public override string Name {
9664 public override bool ContainsEmitWithAwait ()
9666 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
9669 public override Expression CreateExpressionTree (ResolveContext ec)
9671 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
9672 InstanceExpression.CreateExpressionTree (ec),
9673 new TypeOfMethod (Getter, loc));
9675 return CreateExpressionFactoryCall (ec, "Call", args);
9678 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9680 LocalTemporary await_source_arg = null;
9683 emitting_compound_assignment = true;
9684 if (source is DynamicExpressionStatement) {
9689 emitting_compound_assignment = false;
9691 if (has_await_arguments) {
9692 await_source_arg = new LocalTemporary (Type);
9693 await_source_arg.Store (ec);
9695 arguments.Add (new Argument (await_source_arg));
9698 temp = await_source_arg;
9701 has_await_arguments = false;
9706 ec.Emit (OpCodes.Dup);
9707 temp = new LocalTemporary (Type);
9713 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9714 source = source.EmitToField (ec);
9716 temp = new LocalTemporary (Type);
9723 arguments.Add (new Argument (source));
9726 var call = new CallEmitter ();
9727 call.InstanceExpression = InstanceExpression;
9728 if (arguments == null)
9729 call.InstanceExpressionOnStack = true;
9731 call.Emit (ec, Setter, arguments, loc);
9736 } else if (leave_copy) {
9740 if (await_source_arg != null) {
9741 await_source_arg.Release (ec);
9745 public override void FlowAnalysis (FlowAnalysisContext fc)
9747 // TODO: Check the order
9748 base.FlowAnalysis (fc);
9749 arguments.FlowAnalysis (fc);
9752 public override string GetSignatureForError ()
9754 return best_candidate.GetSignatureForError ();
9757 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9760 throw new NotSupportedException ();
9762 var value = new[] { source.MakeExpression (ctx) };
9763 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9764 #if NET_4_0 || MONODROID
9765 return SLE.Expression.Block (
9766 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9769 return args.First ();
9774 public override SLE.Expression MakeExpression (BuilderContext ctx)
9777 return base.MakeExpression (ctx);
9779 var args = Arguments.MakeExpression (arguments, ctx);
9780 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9784 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9786 if (best_candidate != null)
9789 eclass = ExprClass.IndexerAccess;
9792 arguments.Resolve (rc, out dynamic);
9794 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9797 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9798 res.BaseMembersProvider = this;
9799 res.InstanceQualifier = this;
9801 // TODO: Do I need 2 argument sets?
9802 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9803 if (best_candidate != null)
9804 type = res.BestCandidateReturnType;
9805 else if (!res.BestCandidateIsDynamic)
9810 // It has dynamic arguments
9813 Arguments args = new Arguments (arguments.Count + 1);
9815 rc.Report.Error (1972, loc,
9816 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9818 args.Add (new Argument (InstanceExpression));
9820 args.AddRange (arguments);
9822 best_candidate = null;
9823 return new DynamicIndexBinder (args, loc);
9827 // Try to avoid resolving left expression again
9829 if (right_side != null)
9830 ResolveInstanceExpression (rc, right_side);
9835 protected override void CloneTo (CloneContext clonectx, Expression t)
9837 IndexerExpr target = (IndexerExpr) t;
9839 if (arguments != null)
9840 target.arguments = arguments.Clone (clonectx);
9843 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9845 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9848 #region IBaseMembersProvider Members
9850 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9852 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9855 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9857 if (queried_type == member.DeclaringType)
9860 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9861 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9864 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9873 // A base access expression
9875 public class BaseThis : This
9877 public BaseThis (Location loc)
9882 public BaseThis (TypeSpec type, Location loc)
9886 eclass = ExprClass.Variable;
9891 public override string Name {
9899 public override Expression CreateExpressionTree (ResolveContext ec)
9901 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9902 return base.CreateExpressionTree (ec);
9905 public override void Emit (EmitContext ec)
9909 var context_type = ec.CurrentType;
9910 if (context_type.IsStruct) {
9911 ec.Emit (OpCodes.Ldobj, context_type);
9912 ec.Emit (OpCodes.Box, context_type);
9916 protected override void Error_ThisNotAvailable (ResolveContext ec)
9919 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9921 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9925 public override void ResolveBase (ResolveContext ec)
9927 base.ResolveBase (ec);
9928 type = ec.CurrentType.BaseType;
9931 public override object Accept (StructuralVisitor visitor)
9933 return visitor.Visit (this);
9938 /// This class exists solely to pass the Type around and to be a dummy
9939 /// that can be passed to the conversion functions (this is used by
9940 /// foreach implementation to typecast the object return value from
9941 /// get_Current into the proper type. All code has been generated and
9942 /// we only care about the side effect conversions to be performed
9944 /// This is also now used as a placeholder where a no-action expression
9945 /// is needed (the `New' class).
9947 public class EmptyExpression : Expression
9949 sealed class OutAccessExpression : EmptyExpression
9951 public OutAccessExpression (TypeSpec t)
9956 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9958 rc.Report.Error (206, right_side.Location,
9959 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
9965 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
9966 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
9967 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
9968 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
9969 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
9970 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
9971 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
9972 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
9974 public EmptyExpression (TypeSpec t)
9977 eclass = ExprClass.Value;
9978 loc = Location.Null;
9981 public override bool ContainsEmitWithAwait ()
9986 public override Expression CreateExpressionTree (ResolveContext ec)
9988 throw new NotSupportedException ("ET");
9991 protected override Expression DoResolve (ResolveContext ec)
9996 public override void Emit (EmitContext ec)
9998 // nothing, as we only exist to not do anything.
10001 public override void EmitSideEffect (EmitContext ec)
10005 public override object Accept (StructuralVisitor visitor)
10007 return visitor.Visit (this);
10011 sealed class EmptyAwaitExpression : EmptyExpression
10013 public EmptyAwaitExpression (TypeSpec type)
10018 public override bool ContainsEmitWithAwait ()
10025 // Empty statement expression
10027 public sealed class EmptyExpressionStatement : ExpressionStatement
10029 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
10031 private EmptyExpressionStatement ()
10033 loc = Location.Null;
10036 public override bool ContainsEmitWithAwait ()
10041 public override Expression CreateExpressionTree (ResolveContext ec)
10046 public override void EmitStatement (EmitContext ec)
10051 protected override Expression DoResolve (ResolveContext ec)
10053 eclass = ExprClass.Value;
10054 type = ec.BuiltinTypes.Object;
10058 public override void Emit (EmitContext ec)
10063 public override object Accept (StructuralVisitor visitor)
10065 return visitor.Visit (this);
10069 public class ErrorExpression : EmptyExpression
10071 public static readonly ErrorExpression Instance = new ErrorExpression ();
10073 private ErrorExpression ()
10074 : base (InternalType.ErrorType)
10078 public override Expression CreateExpressionTree (ResolveContext ec)
10083 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10088 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
10092 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
10096 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
10100 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
10104 public override object Accept (StructuralVisitor visitor)
10106 return visitor.Visit (this);
10110 public class UserCast : Expression {
10114 public UserCast (MethodSpec method, Expression source, Location l)
10116 if (source == null)
10117 throw new ArgumentNullException ("source");
10119 this.method = method;
10120 this.source = source;
10121 type = method.ReturnType;
10125 public Expression Source {
10131 public override bool ContainsEmitWithAwait ()
10133 return source.ContainsEmitWithAwait ();
10136 public override Expression CreateExpressionTree (ResolveContext ec)
10138 Arguments args = new Arguments (3);
10139 args.Add (new Argument (source.CreateExpressionTree (ec)));
10140 args.Add (new Argument (new TypeOf (type, loc)));
10141 args.Add (new Argument (new TypeOfMethod (method, loc)));
10142 return CreateExpressionFactoryCall (ec, "Convert", args);
10145 protected override Expression DoResolve (ResolveContext ec)
10147 ObsoleteAttribute oa = method.GetAttributeObsolete ();
10149 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
10151 eclass = ExprClass.Value;
10155 public override void Emit (EmitContext ec)
10158 ec.MarkCallEntry (loc);
10159 ec.Emit (OpCodes.Call, method);
10162 public override void FlowAnalysis (FlowAnalysisContext fc)
10164 source.FlowAnalysis (fc);
10167 public override string GetSignatureForError ()
10169 return TypeManager.CSharpSignature (method);
10172 public override SLE.Expression MakeExpression (BuilderContext ctx)
10175 return base.MakeExpression (ctx);
10177 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
10183 // Holds additional type specifiers like ?, *, []
10185 public class ComposedTypeSpecifier
10187 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
10189 public readonly int Dimension;
10190 public readonly Location Location;
10192 public ComposedTypeSpecifier (int specifier, Location loc)
10194 this.Dimension = specifier;
10195 this.Location = loc;
10199 public bool IsNullable {
10201 return Dimension == -1;
10205 public bool IsPointer {
10207 return Dimension == -2;
10211 public ComposedTypeSpecifier Next { get; set; }
10215 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
10217 return new ComposedTypeSpecifier (dimension, loc);
10220 public static ComposedTypeSpecifier CreateNullable (Location loc)
10222 return new ComposedTypeSpecifier (-1, loc);
10225 public static ComposedTypeSpecifier CreatePointer (Location loc)
10227 return new ComposedTypeSpecifier (-2, loc);
10230 public string GetSignatureForError ()
10235 ArrayContainer.GetPostfixSignature (Dimension);
10237 return Next != null ? s + Next.GetSignatureForError () : s;
10242 // This class is used to "construct" the type during a typecast
10243 // operation. Since the Type.GetType class in .NET can parse
10244 // the type specification, we just use this to construct the type
10245 // one bit at a time.
10247 public class ComposedCast : TypeExpr {
10248 FullNamedExpression left;
10249 ComposedTypeSpecifier spec;
10251 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
10254 throw new ArgumentNullException ("spec");
10258 this.loc = left.Location;
10261 public override TypeSpec ResolveAsType (IMemberContext ec)
10263 type = left.ResolveAsType (ec);
10267 eclass = ExprClass.Type;
10269 var single_spec = spec;
10271 if (single_spec.IsNullable) {
10272 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
10276 single_spec = single_spec.Next;
10277 } else if (single_spec.IsPointer) {
10278 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
10281 if (!ec.IsUnsafe) {
10282 UnsafeError (ec.Module.Compiler.Report, loc);
10286 type = PointerContainer.MakeType (ec.Module, type);
10287 single_spec = single_spec.Next;
10288 } while (single_spec != null && single_spec.IsPointer);
10291 if (single_spec != null && single_spec.Dimension > 0) {
10292 if (type.IsSpecialRuntimeType) {
10293 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
10294 } else if (type.IsStatic) {
10295 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
10296 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
10297 type.GetSignatureForError ());
10299 MakeArray (ec.Module, single_spec);
10306 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
10308 if (spec.Next != null)
10309 MakeArray (module, spec.Next);
10311 type = ArrayContainer.MakeType (module, type, spec.Dimension);
10314 public override string GetSignatureForError ()
10316 return left.GetSignatureForError () + spec.GetSignatureForError ();
10319 public override object Accept (StructuralVisitor visitor)
10321 return visitor.Visit (this);
10325 class FixedBufferPtr : Expression
10327 readonly Expression array;
10329 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
10331 this.type = array_type;
10332 this.array = array;
10336 public override bool ContainsEmitWithAwait ()
10338 throw new NotImplementedException ();
10341 public override Expression CreateExpressionTree (ResolveContext ec)
10343 Error_PointerInsideExpressionTree (ec);
10347 public override void Emit(EmitContext ec)
10352 protected override Expression DoResolve (ResolveContext ec)
10354 type = PointerContainer.MakeType (ec.Module, type);
10355 eclass = ExprClass.Value;
10362 // This class is used to represent the address of an array, used
10363 // only by the Fixed statement, this generates "&a [0]" construct
10364 // for fixed (char *pa = a)
10366 class ArrayPtr : FixedBufferPtr
10368 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
10369 base (array, array_type, l)
10373 public override void Emit (EmitContext ec)
10378 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
10383 // Encapsulates a conversion rules required for array indexes
10385 public class ArrayIndexCast : TypeCast
10387 public ArrayIndexCast (Expression expr, TypeSpec returnType)
10388 : base (expr, returnType)
10390 if (expr.Type == returnType) // int -> int
10391 throw new ArgumentException ("unnecessary array index conversion");
10394 public override Expression CreateExpressionTree (ResolveContext ec)
10396 using (ec.Set (ResolveContext.Options.CheckedScope)) {
10397 return base.CreateExpressionTree (ec);
10401 public override void Emit (EmitContext ec)
10405 switch (child.Type.BuiltinType) {
10406 case BuiltinTypeSpec.Type.UInt:
10407 ec.Emit (OpCodes.Conv_U);
10409 case BuiltinTypeSpec.Type.Long:
10410 ec.Emit (OpCodes.Conv_Ovf_I);
10412 case BuiltinTypeSpec.Type.ULong:
10413 ec.Emit (OpCodes.Conv_Ovf_I_Un);
10416 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
10422 // Implements the `stackalloc' keyword
10424 public class StackAlloc : Expression {
10429 public StackAlloc (Expression type, Expression count, Location l)
10432 this.count = count;
10436 public Expression TypeExpression {
10442 public Expression CountExpression {
10448 public override bool ContainsEmitWithAwait ()
10453 public override Expression CreateExpressionTree (ResolveContext ec)
10455 throw new NotSupportedException ("ET");
10458 protected override Expression DoResolve (ResolveContext ec)
10460 count = count.Resolve (ec);
10464 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
10465 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
10470 Constant c = count as Constant;
10471 if (c != null && c.IsNegative) {
10472 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
10475 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
10476 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
10479 otype = t.ResolveAsType (ec);
10483 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
10486 type = PointerContainer.MakeType (ec.Module, otype);
10487 eclass = ExprClass.Value;
10492 public override void Emit (EmitContext ec)
10494 int size = BuiltinTypeSpec.GetSize (otype);
10499 ec.Emit (OpCodes.Sizeof, otype);
10503 ec.Emit (OpCodes.Mul_Ovf_Un);
10504 ec.Emit (OpCodes.Localloc);
10507 protected override void CloneTo (CloneContext clonectx, Expression t)
10509 StackAlloc target = (StackAlloc) t;
10510 target.count = count.Clone (clonectx);
10511 target.t = t.Clone (clonectx);
10514 public override object Accept (StructuralVisitor visitor)
10516 return visitor.Visit (this);
10521 // An object initializer expression
10523 public class ElementInitializer : Assign
10525 public readonly string Name;
10527 public ElementInitializer (string name, Expression initializer, Location loc)
10528 : base (null, initializer, loc)
10533 protected override void CloneTo (CloneContext clonectx, Expression t)
10535 ElementInitializer target = (ElementInitializer) t;
10536 target.source = source.Clone (clonectx);
10539 public override Expression CreateExpressionTree (ResolveContext ec)
10541 Arguments args = new Arguments (2);
10542 FieldExpr fe = target as FieldExpr;
10544 args.Add (new Argument (fe.CreateTypeOfExpression ()));
10546 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
10549 Expression arg_expr;
10550 var cinit = source as CollectionOrObjectInitializers;
10551 if (cinit == null) {
10553 arg_expr = source.CreateExpressionTree (ec);
10555 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
10556 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
10559 args.Add (new Argument (arg_expr));
10560 return CreateExpressionFactoryCall (ec, mname, args);
10563 protected override Expression DoResolve (ResolveContext ec)
10565 if (source == null)
10566 return EmptyExpressionStatement.Instance;
10568 var t = ec.CurrentInitializerVariable.Type;
10569 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10570 Arguments args = new Arguments (1);
10571 args.Add (new Argument (ec.CurrentInitializerVariable));
10572 target = new DynamicMemberBinder (Name, args, loc);
10575 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10576 if (member == null) {
10577 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10579 if (member != null) {
10580 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
10581 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
10586 if (member == null) {
10587 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
10591 if (!(member is PropertyExpr || member is FieldExpr)) {
10592 ec.Report.Error (1913, loc,
10593 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
10594 member.GetSignatureForError ());
10599 var me = member as MemberExpr;
10601 ec.Report.Error (1914, loc,
10602 "Static field or property `{0}' cannot be assigned in an object initializer",
10603 me.GetSignatureForError ());
10607 me.InstanceExpression = ec.CurrentInitializerVariable;
10610 if (source is CollectionOrObjectInitializers) {
10611 Expression previous = ec.CurrentInitializerVariable;
10612 ec.CurrentInitializerVariable = target;
10613 source = source.Resolve (ec);
10614 ec.CurrentInitializerVariable = previous;
10615 if (source == null)
10618 eclass = source.eclass;
10619 type = source.Type;
10623 return base.DoResolve (ec);
10626 public override void EmitStatement (EmitContext ec)
10628 if (source is CollectionOrObjectInitializers)
10631 base.EmitStatement (ec);
10636 // A collection initializer expression
10638 class CollectionElementInitializer : Invocation
10640 public class ElementInitializerArgument : Argument
10642 public ElementInitializerArgument (Expression e)
10648 sealed class AddMemberAccess : MemberAccess
10650 public AddMemberAccess (Expression expr, Location loc)
10651 : base (expr, "Add", loc)
10655 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10657 if (TypeManager.HasElementType (type))
10660 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10664 public CollectionElementInitializer (Expression argument)
10665 : base (null, new Arguments (1))
10667 base.arguments.Add (new ElementInitializerArgument (argument));
10668 this.loc = argument.Location;
10671 public CollectionElementInitializer (List<Expression> arguments, Location loc)
10672 : base (null, new Arguments (arguments.Count))
10674 foreach (Expression e in arguments)
10675 base.arguments.Add (new ElementInitializerArgument (e));
10680 public CollectionElementInitializer (Location loc)
10681 : base (null, null)
10686 public override Expression CreateExpressionTree (ResolveContext ec)
10688 Arguments args = new Arguments (2);
10689 args.Add (new Argument (mg.CreateExpressionTree (ec)));
10691 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
10692 foreach (Argument a in arguments)
10693 expr_initializers.Add (a.CreateExpressionTree (ec));
10695 args.Add (new Argument (new ArrayCreation (
10696 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
10697 return CreateExpressionFactoryCall (ec, "ElementInit", args);
10700 protected override void CloneTo (CloneContext clonectx, Expression t)
10702 CollectionElementInitializer target = (CollectionElementInitializer) t;
10703 if (arguments != null)
10704 target.arguments = arguments.Clone (clonectx);
10707 protected override Expression DoResolve (ResolveContext ec)
10709 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
10711 return base.DoResolve (ec);
10716 // A block of object or collection initializers
10718 public class CollectionOrObjectInitializers : ExpressionStatement
10720 IList<Expression> initializers;
10721 bool is_collection_initialization;
10723 public CollectionOrObjectInitializers (Location loc)
10724 : this (new Expression[0], loc)
10728 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10730 this.initializers = initializers;
10734 public IList<Expression> Initializers {
10736 return initializers;
10740 public bool IsEmpty {
10742 return initializers.Count == 0;
10746 public bool IsCollectionInitializer {
10748 return is_collection_initialization;
10752 protected override void CloneTo (CloneContext clonectx, Expression target)
10754 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10756 t.initializers = new List<Expression> (initializers.Count);
10757 foreach (var e in initializers)
10758 t.initializers.Add (e.Clone (clonectx));
10761 public override bool ContainsEmitWithAwait ()
10763 foreach (var e in initializers) {
10764 if (e.ContainsEmitWithAwait ())
10771 public override Expression CreateExpressionTree (ResolveContext ec)
10773 return CreateExpressionTree (ec, false);
10776 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10778 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10779 foreach (Expression e in initializers) {
10780 Expression expr = e.CreateExpressionTree (ec);
10782 expr_initializers.Add (expr);
10786 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10788 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10791 protected override Expression DoResolve (ResolveContext ec)
10793 List<string> element_names = null;
10794 for (int i = 0; i < initializers.Count; ++i) {
10795 Expression initializer = initializers [i];
10796 ElementInitializer element_initializer = initializer as ElementInitializer;
10799 if (element_initializer != null) {
10800 element_names = new List<string> (initializers.Count);
10801 element_names.Add (element_initializer.Name);
10802 } else if (initializer is CompletingExpression){
10803 initializer.Resolve (ec);
10804 throw new InternalErrorException ("This line should never be reached");
10806 var t = ec.CurrentInitializerVariable.Type;
10807 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10808 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10809 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10810 "object initializer because type `{1}' does not implement `{2}' interface",
10811 ec.CurrentInitializerVariable.GetSignatureForError (),
10812 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10813 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10816 is_collection_initialization = true;
10819 if (is_collection_initialization != (element_initializer == null)) {
10820 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10821 is_collection_initialization ? "collection initializer" : "object initializer");
10825 if (!is_collection_initialization) {
10826 if (element_names.Contains (element_initializer.Name)) {
10827 ec.Report.Error (1912, element_initializer.Location,
10828 "An object initializer includes more than one member `{0}' initialization",
10829 element_initializer.Name);
10831 element_names.Add (element_initializer.Name);
10836 Expression e = initializer.Resolve (ec);
10837 if (e == EmptyExpressionStatement.Instance)
10838 initializers.RemoveAt (i--);
10840 initializers [i] = e;
10843 type = ec.CurrentInitializerVariable.Type;
10844 if (is_collection_initialization) {
10845 if (TypeManager.HasElementType (type)) {
10846 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10847 type.GetSignatureForError ());
10851 eclass = ExprClass.Variable;
10855 public override void Emit (EmitContext ec)
10857 EmitStatement (ec);
10860 public override void EmitStatement (EmitContext ec)
10862 foreach (ExpressionStatement e in initializers) {
10863 // TODO: need location region
10864 ec.Mark (e.Location);
10865 e.EmitStatement (ec);
10869 public override void FlowAnalysis (FlowAnalysisContext fc)
10871 foreach (var initializer in initializers)
10872 initializer.FlowAnalysis (fc);
10877 // New expression with element/object initializers
10879 public class NewInitialize : New
10882 // This class serves as a proxy for variable initializer target instances.
10883 // A real variable is assigned later when we resolve left side of an
10886 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10888 NewInitialize new_instance;
10890 public InitializerTargetExpression (NewInitialize newInstance)
10892 this.type = newInstance.type;
10893 this.loc = newInstance.loc;
10894 this.eclass = newInstance.eclass;
10895 this.new_instance = newInstance;
10898 public override bool ContainsEmitWithAwait ()
10903 public override Expression CreateExpressionTree (ResolveContext ec)
10905 // Should not be reached
10906 throw new NotSupportedException ("ET");
10909 protected override Expression DoResolve (ResolveContext ec)
10914 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10919 public override void Emit (EmitContext ec)
10921 Expression e = (Expression) new_instance.instance;
10925 public override Expression EmitToField (EmitContext ec)
10927 return (Expression) new_instance.instance;
10930 #region IMemoryLocation Members
10932 public void AddressOf (EmitContext ec, AddressOp mode)
10934 new_instance.instance.AddressOf (ec, mode);
10940 CollectionOrObjectInitializers initializers;
10941 IMemoryLocation instance;
10942 DynamicExpressionStatement dynamic;
10944 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10945 : base (requested_type, arguments, l)
10947 this.initializers = initializers;
10950 public CollectionOrObjectInitializers Initializers {
10952 return initializers;
10956 protected override void CloneTo (CloneContext clonectx, Expression t)
10958 base.CloneTo (clonectx, t);
10960 NewInitialize target = (NewInitialize) t;
10961 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
10964 public override bool ContainsEmitWithAwait ()
10966 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
10969 public override Expression CreateExpressionTree (ResolveContext ec)
10971 Arguments args = new Arguments (2);
10972 args.Add (new Argument (base.CreateExpressionTree (ec)));
10973 if (!initializers.IsEmpty)
10974 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
10976 return CreateExpressionFactoryCall (ec,
10977 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
10981 protected override Expression DoResolve (ResolveContext ec)
10983 Expression e = base.DoResolve (ec);
10987 if (type.IsDelegate) {
10988 ec.Report.Error (1958, Initializers.Location,
10989 "Object and collection initializers cannot be used to instantiate a delegate");
10992 Expression previous = ec.CurrentInitializerVariable;
10993 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
10994 initializers.Resolve (ec);
10995 ec.CurrentInitializerVariable = previous;
10997 dynamic = e as DynamicExpressionStatement;
10998 if (dynamic != null)
11004 public override bool Emit (EmitContext ec, IMemoryLocation target)
11006 bool left_on_stack;
11007 if (dynamic != null) {
11009 left_on_stack = true;
11011 left_on_stack = base.Emit (ec, target);
11014 if (initializers.IsEmpty)
11015 return left_on_stack;
11017 LocalTemporary temp = null;
11019 instance = target as LocalTemporary;
11021 if (instance == null) {
11022 if (!left_on_stack) {
11023 VariableReference vr = target as VariableReference;
11025 // FIXME: This still does not work correctly for pre-set variables
11026 if (vr != null && vr.IsRef)
11027 target.AddressOf (ec, AddressOp.Load);
11029 ((Expression) target).Emit (ec);
11030 left_on_stack = true;
11033 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
11034 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
11036 temp = new LocalTemporary (type);
11041 if (left_on_stack && temp != null)
11044 initializers.Emit (ec);
11046 if (left_on_stack) {
11047 if (temp != null) {
11051 ((Expression) instance).Emit (ec);
11055 return left_on_stack;
11058 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
11060 instance = base.EmitAddressOf (ec, Mode);
11062 if (!initializers.IsEmpty)
11063 initializers.Emit (ec);
11068 public override void FlowAnalysis (FlowAnalysisContext fc)
11070 base.FlowAnalysis (fc);
11071 initializers.FlowAnalysis (fc);
11074 public override object Accept (StructuralVisitor visitor)
11076 return visitor.Visit (this);
11080 public class NewAnonymousType : New
11082 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
11084 List<AnonymousTypeParameter> parameters;
11085 readonly TypeContainer parent;
11086 AnonymousTypeClass anonymous_type;
11088 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
11089 : base (null, null, loc)
11091 this.parameters = parameters;
11092 this.parent = parent;
11095 public List<AnonymousTypeParameter> Parameters {
11097 return this.parameters;
11101 protected override void CloneTo (CloneContext clonectx, Expression target)
11103 if (parameters == null)
11106 NewAnonymousType t = (NewAnonymousType) target;
11107 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
11108 foreach (AnonymousTypeParameter atp in parameters)
11109 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
11112 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
11114 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
11118 type = AnonymousTypeClass.Create (parent, parameters, loc);
11122 int errors = ec.Report.Errors;
11123 type.CreateContainer ();
11124 type.DefineContainer ();
11126 if ((ec.Report.Errors - errors) == 0) {
11127 parent.Module.AddAnonymousType (type);
11133 public override Expression CreateExpressionTree (ResolveContext ec)
11135 if (parameters == null)
11136 return base.CreateExpressionTree (ec);
11138 var init = new ArrayInitializer (parameters.Count, loc);
11139 foreach (var m in anonymous_type.Members) {
11140 var p = m as Property;
11142 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
11145 var ctor_args = new ArrayInitializer (arguments.Count, loc);
11146 foreach (Argument a in arguments)
11147 ctor_args.Add (a.CreateExpressionTree (ec));
11149 Arguments args = new Arguments (3);
11150 args.Add (new Argument (new TypeOfMethod (method, loc)));
11151 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
11152 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
11154 return CreateExpressionFactoryCall (ec, "New", args);
11157 protected override Expression DoResolve (ResolveContext ec)
11159 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
11160 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
11164 if (parameters == null) {
11165 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
11166 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
11167 return base.DoResolve (ec);
11170 bool error = false;
11171 arguments = new Arguments (parameters.Count);
11172 var t_args = new TypeSpec [parameters.Count];
11173 for (int i = 0; i < parameters.Count; ++i) {
11174 Expression e = parameters [i].Resolve (ec);
11180 arguments.Add (new Argument (e));
11181 t_args [i] = e.Type;
11187 anonymous_type = CreateAnonymousType (ec, parameters);
11188 if (anonymous_type == null)
11191 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
11192 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
11193 eclass = ExprClass.Value;
11197 public override object Accept (StructuralVisitor visitor)
11199 return visitor.Visit (this);
11203 public class AnonymousTypeParameter : ShimExpression
11205 public readonly string Name;
11207 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
11208 : base (initializer)
11214 public AnonymousTypeParameter (Parameter parameter)
11215 : base (new SimpleName (parameter.Name, parameter.Location))
11217 this.Name = parameter.Name;
11218 this.loc = parameter.Location;
11221 public override bool Equals (object o)
11223 AnonymousTypeParameter other = o as AnonymousTypeParameter;
11224 return other != null && Name == other.Name;
11227 public override int GetHashCode ()
11229 return Name.GetHashCode ();
11232 protected override Expression DoResolve (ResolveContext ec)
11234 Expression e = expr.Resolve (ec);
11238 if (e.eclass == ExprClass.MethodGroup) {
11239 Error_InvalidInitializer (ec, e.ExprClassName);
11244 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
11245 Error_InvalidInitializer (ec, type.GetSignatureForError ());
11252 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
11254 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
11255 Name, initializer);