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);
86 public override SLE.Expression MakeExpression (BuilderContext ctx)
89 return base.MakeExpression (ctx);
91 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
96 public class ParenthesizedExpression : ShimExpression
98 public ParenthesizedExpression (Expression expr, Location loc)
104 protected override Expression DoResolve (ResolveContext ec)
106 var res = expr.Resolve (ec);
107 var constant = res as Constant;
108 if (constant != null && constant.IsLiteral)
109 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
114 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
116 return expr.DoResolveLValue (ec, right_side);
119 public override object Accept (StructuralVisitor visitor)
121 return visitor.Visit (this);
126 // Unary implements unary expressions.
128 public class Unary : Expression
130 public enum Operator : byte {
131 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
135 public readonly Operator Oper;
136 public Expression Expr;
137 Expression enum_conversion;
139 public Unary (Operator op, Expression expr, Location loc)
147 // This routine will attempt to simplify the unary expression when the
148 // argument is a constant.
150 Constant TryReduceConstant (ResolveContext ec, Constant constant)
154 while (e is EmptyConstantCast)
155 e = ((EmptyConstantCast) e).child;
157 if (e is SideEffectConstant) {
158 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
159 return r == null ? null : new SideEffectConstant (r, e, r.Location);
162 TypeSpec expr_type = e.Type;
165 case Operator.UnaryPlus:
166 // Unary numeric promotions
167 switch (expr_type.BuiltinType) {
168 case BuiltinTypeSpec.Type.Byte:
169 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
170 case BuiltinTypeSpec.Type.SByte:
171 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
172 case BuiltinTypeSpec.Type.Short:
173 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
174 case BuiltinTypeSpec.Type.UShort:
175 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
176 case BuiltinTypeSpec.Type.Char:
177 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
179 // Predefined operators
180 case BuiltinTypeSpec.Type.Int:
181 case BuiltinTypeSpec.Type.UInt:
182 case BuiltinTypeSpec.Type.Long:
183 case BuiltinTypeSpec.Type.ULong:
184 case BuiltinTypeSpec.Type.Float:
185 case BuiltinTypeSpec.Type.Double:
186 case BuiltinTypeSpec.Type.Decimal:
192 case Operator.UnaryNegation:
193 // Unary numeric promotions
194 switch (expr_type.BuiltinType) {
195 case BuiltinTypeSpec.Type.Byte:
196 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
197 case BuiltinTypeSpec.Type.SByte:
198 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
199 case BuiltinTypeSpec.Type.Short:
200 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
201 case BuiltinTypeSpec.Type.UShort:
202 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
203 case BuiltinTypeSpec.Type.Char:
204 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
206 // Predefined operators
207 case BuiltinTypeSpec.Type.Int:
208 int ivalue = ((IntConstant) e).Value;
209 if (ivalue == int.MinValue) {
210 if (ec.ConstantCheckState) {
211 ConstantFold.Error_CompileTimeOverflow (ec, loc);
216 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
218 case BuiltinTypeSpec.Type.Long:
219 long lvalue = ((LongConstant) e).Value;
220 if (lvalue == long.MinValue) {
221 if (ec.ConstantCheckState) {
222 ConstantFold.Error_CompileTimeOverflow (ec, loc);
227 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
229 case BuiltinTypeSpec.Type.UInt:
230 UIntLiteral uil = constant as UIntLiteral;
232 if (uil.Value == int.MaxValue + (uint) 1)
233 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
234 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
236 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
239 case BuiltinTypeSpec.Type.ULong:
240 ULongLiteral ull = constant as ULongLiteral;
241 if (ull != null && ull.Value == 9223372036854775808)
242 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
245 case BuiltinTypeSpec.Type.Float:
246 FloatLiteral fl = constant as FloatLiteral;
247 // For better error reporting
249 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
251 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
253 case BuiltinTypeSpec.Type.Double:
254 DoubleLiteral dl = constant as DoubleLiteral;
255 // For better error reporting
257 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
259 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
261 case BuiltinTypeSpec.Type.Decimal:
262 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
267 case Operator.LogicalNot:
268 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
271 bool b = (bool)e.GetValue ();
272 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
274 case Operator.OnesComplement:
275 // Unary numeric promotions
276 switch (expr_type.BuiltinType) {
277 case BuiltinTypeSpec.Type.Byte:
278 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
279 case BuiltinTypeSpec.Type.SByte:
280 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
281 case BuiltinTypeSpec.Type.Short:
282 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
283 case BuiltinTypeSpec.Type.UShort:
284 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
285 case BuiltinTypeSpec.Type.Char:
286 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
288 // Predefined operators
289 case BuiltinTypeSpec.Type.Int:
290 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
291 case BuiltinTypeSpec.Type.UInt:
292 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
293 case BuiltinTypeSpec.Type.Long:
294 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
295 case BuiltinTypeSpec.Type.ULong:
296 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
298 if (e is EnumConstant) {
299 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
301 e = new EnumConstant (e, expr_type);
306 throw new Exception ("Can not constant fold: " + Oper.ToString());
309 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
311 eclass = ExprClass.Value;
313 TypeSpec expr_type = expr.Type;
314 Expression best_expr;
316 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
319 // Primitive types first
321 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
322 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
323 if (best_expr == null)
326 type = best_expr.Type;
332 // E operator ~(E x);
334 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
335 return ResolveEnumOperator (ec, expr, predefined);
337 return ResolveUserType (ec, expr, predefined);
340 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
342 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
343 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
344 if (best_expr == null)
348 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (best_expr.Type), underlying_type);
350 return EmptyCast.Create (this, type);
353 public override bool ContainsEmitWithAwait ()
355 return Expr.ContainsEmitWithAwait ();
358 public override Expression CreateExpressionTree (ResolveContext ec)
360 return CreateExpressionTree (ec, null);
363 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
367 case Operator.AddressOf:
368 Error_PointerInsideExpressionTree (ec);
370 case Operator.UnaryNegation:
371 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
372 method_name = "NegateChecked";
374 method_name = "Negate";
376 case Operator.OnesComplement:
377 case Operator.LogicalNot:
380 case Operator.UnaryPlus:
381 method_name = "UnaryPlus";
384 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
387 Arguments args = new Arguments (2);
388 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
390 args.Add (new Argument (user_op));
392 return CreateExpressionFactoryCall (ec, method_name, args);
395 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
397 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
400 // 7.6.1 Unary plus operator
402 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
403 types.Int, types.UInt,
404 types.Long, types.ULong,
405 types.Float, types.Double,
410 // 7.6.2 Unary minus operator
412 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
413 types.Int, types.Long,
414 types.Float, types.Double,
419 // 7.6.3 Logical negation operator
421 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
426 // 7.6.4 Bitwise complement operator
428 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
429 types.Int, types.UInt,
430 types.Long, types.ULong
433 return predefined_operators;
437 // Unary numeric promotions
439 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
441 TypeSpec expr_type = expr.Type;
442 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
443 switch (expr_type.BuiltinType) {
444 case BuiltinTypeSpec.Type.Byte:
445 case BuiltinTypeSpec.Type.SByte:
446 case BuiltinTypeSpec.Type.Short:
447 case BuiltinTypeSpec.Type.UShort:
448 case BuiltinTypeSpec.Type.Char:
449 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
453 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
454 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
459 protected override Expression DoResolve (ResolveContext ec)
461 if (Oper == Operator.AddressOf) {
462 return ResolveAddressOf (ec);
465 Expr = Expr.Resolve (ec);
469 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
470 Arguments args = new Arguments (1);
471 args.Add (new Argument (Expr));
472 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
475 if (Expr.Type.IsNullableType)
476 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
479 // Attempt to use a constant folding operation.
481 Constant cexpr = Expr as Constant;
483 cexpr = TryReduceConstant (ec, cexpr);
488 Expression expr = ResolveOperator (ec, Expr);
490 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
493 // Reduce unary operator on predefined types
495 if (expr == this && Oper == Operator.UnaryPlus)
501 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
506 public override void Emit (EmitContext ec)
508 EmitOperator (ec, type);
511 protected void EmitOperator (EmitContext ec, TypeSpec type)
514 case Operator.UnaryPlus:
518 case Operator.UnaryNegation:
519 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
520 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
521 Expr = Expr.EmitToField (ec);
524 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
525 ec.Emit (OpCodes.Conv_U8);
527 ec.Emit (OpCodes.Sub_Ovf);
530 ec.Emit (OpCodes.Neg);
535 case Operator.LogicalNot:
538 ec.Emit (OpCodes.Ceq);
541 case Operator.OnesComplement:
543 ec.Emit (OpCodes.Not);
546 case Operator.AddressOf:
547 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
551 throw new Exception ("This should not happen: Operator = "
556 // Same trick as in Binary expression
558 if (enum_conversion != null)
559 enum_conversion.Emit (ec);
562 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
564 if (Oper == Operator.LogicalNot)
565 Expr.EmitBranchable (ec, target, !on_true);
567 base.EmitBranchable (ec, target, on_true);
570 public override void EmitSideEffect (EmitContext ec)
572 Expr.EmitSideEffect (ec);
576 // Converts operator to System.Linq.Expressions.ExpressionType enum name
578 string GetOperatorExpressionTypeName ()
581 case Operator.OnesComplement:
582 return "OnesComplement";
583 case Operator.LogicalNot:
585 case Operator.UnaryNegation:
587 case Operator.UnaryPlus:
590 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
594 static bool IsFloat (TypeSpec t)
596 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
600 // Returns a stringified representation of the Operator
602 public static string OperName (Operator oper)
605 case Operator.UnaryPlus:
607 case Operator.UnaryNegation:
609 case Operator.LogicalNot:
611 case Operator.OnesComplement:
613 case Operator.AddressOf:
617 throw new NotImplementedException (oper.ToString ());
620 public override SLE.Expression MakeExpression (BuilderContext ctx)
622 var expr = Expr.MakeExpression (ctx);
623 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
626 case Operator.UnaryNegation:
627 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
628 case Operator.LogicalNot:
629 return SLE.Expression.Not (expr);
630 #if NET_4_0 || MONODROID
631 case Operator.OnesComplement:
632 return SLE.Expression.OnesComplement (expr);
635 throw new NotImplementedException (Oper.ToString ());
639 Expression ResolveAddressOf (ResolveContext ec)
642 UnsafeError (ec, loc);
644 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
645 if (Expr == null || Expr.eclass != ExprClass.Variable) {
646 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
650 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
654 IVariableReference vr = Expr as IVariableReference;
657 is_fixed = vr.IsFixed;
658 vr.SetHasAddressTaken ();
661 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
664 IFixedExpression fe = Expr as IFixedExpression;
665 is_fixed = fe != null && fe.IsFixed;
668 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
669 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
672 type = PointerContainer.MakeType (ec.Module, Expr.Type);
673 eclass = ExprClass.Value;
677 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
679 expr = DoNumericPromotion (rc, Oper, expr);
680 TypeSpec expr_type = expr.Type;
681 foreach (TypeSpec t in predefined) {
689 // Perform user-operator overload resolution
691 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
693 CSharp.Operator.OpType op_type;
695 case Operator.LogicalNot:
696 op_type = CSharp.Operator.OpType.LogicalNot; break;
697 case Operator.OnesComplement:
698 op_type = CSharp.Operator.OpType.OnesComplement; break;
699 case Operator.UnaryNegation:
700 op_type = CSharp.Operator.OpType.UnaryNegation; break;
701 case Operator.UnaryPlus:
702 op_type = CSharp.Operator.OpType.UnaryPlus; break;
704 throw new InternalErrorException (Oper.ToString ());
707 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
711 Arguments args = new Arguments (1);
712 args.Add (new Argument (expr));
714 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
715 var oper = res.ResolveOperator (ec, ref args);
720 Expr = args [0].Expr;
721 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
725 // Unary user type overload resolution
727 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
729 Expression best_expr = ResolveUserOperator (ec, expr);
730 if (best_expr != null)
733 foreach (TypeSpec t in predefined) {
734 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
735 if (oper_expr == null)
738 if (oper_expr == ErrorExpression.Instance)
742 // decimal type is predefined but has user-operators
744 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
745 oper_expr = ResolveUserType (ec, oper_expr, predefined);
747 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
749 if (oper_expr == null)
752 if (best_expr == null) {
753 best_expr = oper_expr;
757 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
759 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
760 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
761 OperName (Oper), expr.Type.GetSignatureForError ());
763 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
770 best_expr = oper_expr;
773 if (best_expr == null)
777 // HACK: Decimal user-operator is included in standard operators
779 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
783 type = best_expr.Type;
787 protected override void CloneTo (CloneContext clonectx, Expression t)
789 Unary target = (Unary) t;
791 target.Expr = Expr.Clone (clonectx);
794 public override object Accept (StructuralVisitor visitor)
796 return visitor.Visit (this);
802 // Unary operators are turned into Indirection expressions
803 // after semantic analysis (this is so we can take the address
804 // of an indirection).
806 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
808 LocalTemporary temporary;
811 public Indirection (Expression expr, Location l)
817 public Expression Expr {
823 public bool IsFixed {
827 public override Location StartLocation {
829 return expr.StartLocation;
833 protected override void CloneTo (CloneContext clonectx, Expression t)
835 Indirection target = (Indirection) t;
836 target.expr = expr.Clone (clonectx);
839 public override bool ContainsEmitWithAwait ()
841 throw new NotImplementedException ();
844 public override Expression CreateExpressionTree (ResolveContext ec)
846 Error_PointerInsideExpressionTree (ec);
850 public override void Emit (EmitContext ec)
855 ec.EmitLoadFromPtr (Type);
858 public void Emit (EmitContext ec, bool leave_copy)
862 ec.Emit (OpCodes.Dup);
863 temporary = new LocalTemporary (expr.Type);
864 temporary.Store (ec);
868 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
870 prepared = isCompound;
875 ec.Emit (OpCodes.Dup);
879 ec.Emit (OpCodes.Dup);
880 temporary = new LocalTemporary (source.Type);
881 temporary.Store (ec);
884 ec.EmitStoreFromPtr (type);
886 if (temporary != null) {
888 temporary.Release (ec);
892 public void AddressOf (EmitContext ec, AddressOp Mode)
897 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
899 return DoResolve (ec);
902 protected override Expression DoResolve (ResolveContext ec)
904 expr = expr.Resolve (ec);
909 UnsafeError (ec, loc);
911 var pc = expr.Type as PointerContainer;
914 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
920 if (type.Kind == MemberKind.Void) {
921 Error_VoidPointerOperation (ec);
925 eclass = ExprClass.Variable;
929 public override object Accept (StructuralVisitor visitor)
931 return visitor.Visit (this);
936 /// Unary Mutator expressions (pre and post ++ and --)
940 /// UnaryMutator implements ++ and -- expressions. It derives from
941 /// ExpressionStatement becuase the pre/post increment/decrement
942 /// operators can be used in a statement context.
944 /// FIXME: Idea, we could split this up in two classes, one simpler
945 /// for the common case, and one with the extra fields for more complex
946 /// classes (indexers require temporary access; overloaded require method)
949 public class UnaryMutator : ExpressionStatement
951 class DynamicPostMutator : Expression, IAssignMethod
956 public DynamicPostMutator (Expression expr)
959 this.type = expr.Type;
960 this.loc = expr.Location;
963 public override Expression CreateExpressionTree (ResolveContext ec)
965 throw new NotImplementedException ("ET");
968 protected override Expression DoResolve (ResolveContext rc)
970 eclass = expr.eclass;
974 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
976 expr.DoResolveLValue (ec, right_side);
977 return DoResolve (ec);
980 public override void Emit (EmitContext ec)
985 public void Emit (EmitContext ec, bool leave_copy)
987 throw new NotImplementedException ();
991 // Emits target assignment using unmodified source value
993 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
996 // Allocate temporary variable to keep original value before it's modified
998 temp = new LocalTemporary (type);
1002 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1013 public enum Mode : byte {
1020 PreDecrement = IsDecrement,
1021 PostIncrement = IsPost,
1022 PostDecrement = IsPost | IsDecrement
1026 bool is_expr, recurse;
1028 protected Expression expr;
1030 // Holds the real operation
1031 Expression operation;
1033 public UnaryMutator (Mode m, Expression e, Location loc)
1040 public Mode UnaryMutatorMode {
1046 public Expression Expr {
1052 public override Location StartLocation {
1054 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1058 public override bool ContainsEmitWithAwait ()
1060 return expr.ContainsEmitWithAwait ();
1063 public override Expression CreateExpressionTree (ResolveContext ec)
1065 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1068 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1071 // Predefined ++ and -- operators exist for the following types:
1072 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1074 return new TypeSpec[] {
1090 protected override Expression DoResolve (ResolveContext ec)
1092 expr = expr.Resolve (ec);
1097 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1099 // Handle postfix unary operators using local
1100 // temporary variable
1102 if ((mode & Mode.IsPost) != 0)
1103 expr = new DynamicPostMutator (expr);
1105 Arguments args = new Arguments (1);
1106 args.Add (new Argument (expr));
1107 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1110 if (expr.Type.IsNullableType)
1111 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1113 return DoResolveOperation (ec);
1116 protected Expression DoResolveOperation (ResolveContext ec)
1118 eclass = ExprClass.Value;
1121 if (expr is RuntimeValueExpression) {
1124 // Use itself at the top of the stack
1125 operation = new EmptyExpression (type);
1129 // The operand of the prefix/postfix increment decrement operators
1130 // should be an expression that is classified as a variable,
1131 // a property access or an indexer access
1133 // TODO: Move to parser, expr is ATypeNameExpression
1134 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1135 expr = expr.ResolveLValue (ec, expr);
1137 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1141 // Step 1: Try to find a user operator, it has priority over predefined ones
1143 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1144 var methods = MemberCache.GetUserOperator (type, user_op, false);
1146 if (methods != null) {
1147 Arguments args = new Arguments (1);
1148 args.Add (new Argument (expr));
1150 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1151 var method = res.ResolveOperator (ec, ref args);
1155 args[0].Expr = operation;
1156 operation = new UserOperatorCall (method, args, null, loc);
1157 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1162 // Step 2: Try predefined types
1165 Expression source = null;
1166 bool primitive_type;
1169 // Predefined without user conversion first for speed-up
1171 // Predefined ++ and -- operators exist for the following types:
1172 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1174 switch (type.BuiltinType) {
1175 case BuiltinTypeSpec.Type.Byte:
1176 case BuiltinTypeSpec.Type.SByte:
1177 case BuiltinTypeSpec.Type.Short:
1178 case BuiltinTypeSpec.Type.UShort:
1179 case BuiltinTypeSpec.Type.Int:
1180 case BuiltinTypeSpec.Type.UInt:
1181 case BuiltinTypeSpec.Type.Long:
1182 case BuiltinTypeSpec.Type.ULong:
1183 case BuiltinTypeSpec.Type.Char:
1184 case BuiltinTypeSpec.Type.Float:
1185 case BuiltinTypeSpec.Type.Double:
1186 case BuiltinTypeSpec.Type.Decimal:
1188 primitive_type = true;
1191 primitive_type = false;
1193 // ++/-- on pointer variables of all types except void*
1194 if (type.IsPointer) {
1195 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1196 Error_VoidPointerOperation (ec);
1202 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1203 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1205 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1206 if (source != null) {
1212 // ++/-- on enum types
1213 if (source == null && type.IsEnum)
1216 if (source == null) {
1217 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1224 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1225 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1226 operation = new Binary (op, source, one);
1227 operation = operation.Resolve (ec);
1228 if (operation == null)
1229 throw new NotImplementedException ("should not be reached");
1231 if (operation.Type != type) {
1233 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1235 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1241 void EmitCode (EmitContext ec, bool is_expr)
1244 this.is_expr = is_expr;
1245 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1248 public override void Emit (EmitContext ec)
1251 // We use recurse to allow ourselfs to be the source
1252 // of an assignment. This little hack prevents us from
1253 // having to allocate another expression
1256 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1264 EmitCode (ec, true);
1267 protected virtual void EmitOperation (EmitContext ec)
1269 operation.Emit (ec);
1272 public override void EmitStatement (EmitContext ec)
1274 EmitCode (ec, false);
1278 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1280 string GetOperatorExpressionTypeName ()
1282 return IsDecrement ? "Decrement" : "Increment";
1286 get { return (mode & Mode.IsDecrement) != 0; }
1290 #if NET_4_0 || MONODROID
1291 public override SLE.Expression MakeExpression (BuilderContext ctx)
1293 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1294 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1295 return SLE.Expression.Assign (target, source);
1299 protected override void CloneTo (CloneContext clonectx, Expression t)
1301 UnaryMutator target = (UnaryMutator) t;
1303 target.expr = expr.Clone (clonectx);
1306 public override object Accept (StructuralVisitor visitor)
1308 return visitor.Visit (this);
1314 // Base class for the `is' and `as' operators
1316 public abstract class Probe : Expression
1318 public Expression ProbeType;
1319 protected Expression expr;
1320 protected TypeSpec probe_type_expr;
1322 public Probe (Expression expr, Expression probe_type, Location l)
1324 ProbeType = probe_type;
1329 public Expression Expr {
1335 public override bool ContainsEmitWithAwait ()
1337 return expr.ContainsEmitWithAwait ();
1340 protected override Expression DoResolve (ResolveContext ec)
1342 probe_type_expr = ProbeType.ResolveAsType (ec);
1343 if (probe_type_expr == null)
1346 expr = expr.Resolve (ec);
1350 if (probe_type_expr.IsStatic) {
1351 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1355 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1356 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1361 if (expr.Type == InternalType.AnonymousMethod) {
1362 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1370 protected abstract string OperatorName { get; }
1372 protected override void CloneTo (CloneContext clonectx, Expression t)
1374 Probe target = (Probe) t;
1376 target.expr = expr.Clone (clonectx);
1377 target.ProbeType = ProbeType.Clone (clonectx);
1383 /// Implementation of the `is' operator.
1385 public class Is : Probe
1387 Nullable.Unwrap expr_unwrap;
1389 public Is (Expression expr, Expression probe_type, Location l)
1390 : base (expr, probe_type, l)
1394 protected override string OperatorName {
1395 get { return "is"; }
1398 public override Expression CreateExpressionTree (ResolveContext ec)
1400 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1401 expr.CreateExpressionTree (ec),
1402 new TypeOf (probe_type_expr, loc));
1404 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1407 public override void Emit (EmitContext ec)
1409 if (expr_unwrap != null) {
1410 expr_unwrap.EmitCheck (ec);
1416 // Only to make verifier happy
1417 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1418 ec.Emit (OpCodes.Box, expr.Type);
1420 ec.Emit (OpCodes.Isinst, probe_type_expr);
1422 ec.Emit (OpCodes.Cgt_Un);
1425 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1427 if (expr_unwrap != null) {
1428 expr_unwrap.EmitCheck (ec);
1431 ec.Emit (OpCodes.Isinst, probe_type_expr);
1433 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1436 Expression CreateConstantResult (ResolveContext ec, bool result)
1439 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1440 probe_type_expr.GetSignatureForError ());
1442 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1443 probe_type_expr.GetSignatureForError ());
1445 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, result, loc), this);
1448 protected override Expression DoResolve (ResolveContext ec)
1450 if (base.DoResolve (ec) == null)
1453 TypeSpec d = expr.Type;
1454 bool d_is_nullable = false;
1457 // If E is a method group or the null literal, or if the type of E is a reference
1458 // type or a nullable type and the value of E is null, the result is false
1460 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1461 return CreateConstantResult (ec, false);
1463 if (d.IsNullableType) {
1464 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1465 if (!ut.IsGenericParameter) {
1467 d_is_nullable = true;
1471 type = ec.BuiltinTypes.Bool;
1472 eclass = ExprClass.Value;
1473 TypeSpec t = probe_type_expr;
1474 bool t_is_nullable = false;
1475 if (t.IsNullableType) {
1476 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1477 if (!ut.IsGenericParameter) {
1479 t_is_nullable = true;
1486 // D and T are the same value types but D can be null
1488 if (d_is_nullable && !t_is_nullable) {
1489 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1494 // The result is true if D and T are the same value types
1496 return CreateConstantResult (ec, true);
1499 var tp = d as TypeParameterSpec;
1501 return ResolveGenericParameter (ec, t, tp);
1504 // An unboxing conversion exists
1506 if (Convert.ExplicitReferenceConversionExists (d, t))
1509 if (TypeManager.IsGenericParameter (t))
1510 return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
1512 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1513 ec.Report.Warning (1981, 3, loc,
1514 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1515 OperatorName, t.GetSignatureForError ());
1518 if (TypeManager.IsGenericParameter (d))
1519 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1521 if (TypeSpec.IsValueType (d)) {
1522 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1523 if (d_is_nullable && !t_is_nullable) {
1524 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1528 return CreateConstantResult (ec, true);
1531 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1533 // Do not optimize for imported type
1535 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None)
1539 // Turn is check into simple null check for implicitly convertible reference types
1541 return ReducedExpression.Create (
1542 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1546 if (Convert.ExplicitReferenceConversionExists (d, t)) {
1552 return CreateConstantResult (ec, false);
1555 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1557 if (t.IsReferenceType) {
1559 return CreateConstantResult (ec, false);
1562 if (TypeManager.IsGenericParameter (expr.Type)) {
1563 if (expr.Type == d && TypeSpec.IsValueType (t))
1564 return CreateConstantResult (ec, true);
1566 expr = new BoxedCast (expr, d);
1572 public override object Accept (StructuralVisitor visitor)
1574 return visitor.Visit (this);
1579 /// Implementation of the `as' operator.
1581 public class As : Probe {
1582 Expression resolved_type;
1584 public As (Expression expr, Expression probe_type, Location l)
1585 : base (expr, probe_type, l)
1589 protected override string OperatorName {
1590 get { return "as"; }
1593 public override Expression CreateExpressionTree (ResolveContext ec)
1595 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1596 expr.CreateExpressionTree (ec),
1597 new TypeOf (probe_type_expr, loc));
1599 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1602 public override void Emit (EmitContext ec)
1606 ec.Emit (OpCodes.Isinst, type);
1608 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1609 ec.Emit (OpCodes.Unbox_Any, type);
1612 protected override Expression DoResolve (ResolveContext ec)
1614 if (resolved_type == null) {
1615 resolved_type = base.DoResolve (ec);
1617 if (resolved_type == null)
1621 type = probe_type_expr;
1622 eclass = ExprClass.Value;
1623 TypeSpec etype = expr.Type;
1625 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1626 if (TypeManager.IsGenericParameter (type)) {
1627 ec.Report.Error (413, loc,
1628 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1629 probe_type_expr.GetSignatureForError ());
1631 ec.Report.Error (77, loc,
1632 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1633 type.GetSignatureForError ());
1638 if (expr.IsNull && type.IsNullableType) {
1639 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1642 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1643 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1647 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1649 e = EmptyCast.Create (e, type);
1650 return ReducedExpression.Create (e, this).Resolve (ec);
1653 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1654 if (TypeManager.IsGenericParameter (etype))
1655 expr = new BoxedCast (expr, etype);
1660 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1661 expr = new BoxedCast (expr, etype);
1665 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1666 etype.GetSignatureForError (), type.GetSignatureForError ());
1671 public override object Accept (StructuralVisitor visitor)
1673 return visitor.Visit (this);
1678 // This represents a typecast in the source language.
1680 public class Cast : ShimExpression {
1681 Expression target_type;
1683 public Cast (Expression cast_type, Expression expr, Location loc)
1686 this.target_type = cast_type;
1690 public Expression TargetType {
1691 get { return target_type; }
1694 protected override Expression DoResolve (ResolveContext ec)
1696 expr = expr.Resolve (ec);
1700 type = target_type.ResolveAsType (ec);
1704 if (type.IsStatic) {
1705 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
1709 if (type.IsPointer && !ec.IsUnsafe) {
1710 UnsafeError (ec, loc);
1713 eclass = ExprClass.Value;
1715 Constant c = expr as Constant;
1717 c = c.Reduce (ec, type);
1722 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1724 return EmptyCast.Create (res, type);
1729 protected override void CloneTo (CloneContext clonectx, Expression t)
1731 Cast target = (Cast) t;
1733 target.target_type = target_type.Clone (clonectx);
1734 target.expr = expr.Clone (clonectx);
1737 public override object Accept (StructuralVisitor visitor)
1739 return visitor.Visit (this);
1743 public class ImplicitCast : ShimExpression
1747 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1750 this.loc = expr.Location;
1752 this.arrayAccess = arrayAccess;
1755 protected override Expression DoResolve (ResolveContext ec)
1757 expr = expr.Resolve (ec);
1762 expr = ConvertExpressionToArrayIndex (ec, expr);
1764 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1771 // C# 2.0 Default value expression
1773 public class DefaultValueExpression : Expression
1777 public DefaultValueExpression (Expression expr, Location loc)
1783 public Expression Expr {
1789 public override bool IsSideEffectFree {
1795 public override bool ContainsEmitWithAwait ()
1800 public override Expression CreateExpressionTree (ResolveContext ec)
1802 Arguments args = new Arguments (2);
1803 args.Add (new Argument (this));
1804 args.Add (new Argument (new TypeOf (type, loc)));
1805 return CreateExpressionFactoryCall (ec, "Constant", args);
1808 protected override Expression DoResolve (ResolveContext ec)
1810 type = expr.ResolveAsType (ec);
1814 if (type.IsStatic) {
1815 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1819 return new NullLiteral (Location).ConvertImplicitly (type);
1821 if (TypeSpec.IsReferenceType (type))
1822 return new NullConstant (type, loc);
1824 Constant c = New.Constantify (type, expr.Location);
1828 eclass = ExprClass.Variable;
1832 public override void Emit (EmitContext ec)
1834 LocalTemporary temp_storage = new LocalTemporary(type);
1836 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1837 ec.Emit(OpCodes.Initobj, type);
1838 temp_storage.Emit(ec);
1839 temp_storage.Release (ec);
1842 #if (NET_4_0 || MONODROID) && !STATIC
1843 public override SLE.Expression MakeExpression (BuilderContext ctx)
1845 return SLE.Expression.Default (type.GetMetaInfo ());
1849 protected override void CloneTo (CloneContext clonectx, Expression t)
1851 DefaultValueExpression target = (DefaultValueExpression) t;
1853 target.expr = expr.Clone (clonectx);
1856 public override object Accept (StructuralVisitor visitor)
1858 return visitor.Visit (this);
1863 /// Binary operators
1865 public class Binary : Expression, IDynamicBinder
1867 public class PredefinedOperator
1869 protected readonly TypeSpec left;
1870 protected readonly TypeSpec right;
1871 public readonly Operator OperatorsMask;
1872 public TypeSpec ReturnType;
1874 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1875 : this (ltype, rtype, op_mask, ltype)
1879 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1880 : this (type, type, op_mask, return_type)
1884 public PredefinedOperator (TypeSpec type, Operator op_mask)
1885 : this (type, type, op_mask, type)
1889 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1891 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1892 throw new InternalErrorException ("Only masked values can be used");
1896 this.OperatorsMask = op_mask;
1897 this.ReturnType = return_type;
1900 public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1902 b.type = ReturnType;
1904 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1905 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1908 // A user operators does not support multiple user conversions, but decimal type
1909 // is considered to be predefined type therefore we apply predefined operators rules
1910 // and then look for decimal user-operator implementation
1912 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal)
1913 return b.ResolveUserOperator (ec, b.left, b.right);
1915 var c = b.right as Constant;
1917 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1918 return ReducedExpression.Create (b.left, b).Resolve (ec);
1919 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
1920 return ReducedExpression.Create (b.left, b).Resolve (ec);
1924 c = b.left as Constant;
1926 if (c.IsDefaultValue && (b.oper == Operator.Addition || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1927 return ReducedExpression.Create (b.right, b).Resolve (ec);
1928 if (b.oper == Operator.Multiply && c.IsOneInteger)
1929 return ReducedExpression.Create (b.right, b).Resolve (ec);
1936 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
1939 // We are dealing with primitive types only
1941 return left == ltype && ltype == rtype;
1944 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1947 if (left == lexpr.Type && right == rexpr.Type)
1950 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1951 Convert.ImplicitConversionExists (ec, rexpr, right);
1954 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1957 if (left != null && best_operator.left != null) {
1958 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left, left);
1962 // When second argument is same as the first one, the result is same
1964 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1965 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right, right);
1968 if (result == 0 || result > 2)
1971 return result == 1 ? best_operator : this;
1975 sealed class PredefinedStringOperator : PredefinedOperator
1977 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
1978 : base (type, type, op_mask, retType)
1982 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
1983 : base (ltype, rtype, op_mask, retType)
1987 public override Expression ConvertResult (ResolveContext ec, Binary b)
1990 // Use original expression for nullable arguments
1992 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1994 b.left = unwrap.Original;
1996 unwrap = b.right as Nullable.Unwrap;
1998 b.right = unwrap.Original;
2000 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2001 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2004 // Start a new concat expression using converted expression
2006 return StringConcat.Create (ec, b.left, b.right, b.loc);
2010 sealed class PredefinedShiftOperator : PredefinedOperator
2012 public PredefinedShiftOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2013 : base (ltype, rtype, op_mask)
2017 public override Expression ConvertResult (ResolveContext ec, Binary b)
2019 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2021 Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2023 int right_mask = left.BuiltinType == BuiltinTypeSpec.Type.Int || left.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
2026 // b = b.left >> b.right & (0x1f|0x3f)
2028 b.right = new Binary (Operator.BitwiseAnd,
2029 b.right, new IntConstant (ec.BuiltinTypes, right_mask, b.right.Location)).Resolve (ec);
2032 // Expression tree representation does not use & mask
2034 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
2035 b.type = ReturnType;
2038 // Optimize shift by 0
2040 var c = b.right as Constant;
2041 if (c != null && c.IsDefaultValue)
2042 return ReducedExpression.Create (b.left, b).Resolve (ec);
2048 sealed class PredefinedEqualityOperator : PredefinedOperator
2050 MethodSpec equal_method, inequal_method;
2052 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
2053 : base (arg, arg, Operator.EqualityMask, retType)
2057 public override Expression ConvertResult (ResolveContext ec, Binary b)
2059 b.type = ReturnType;
2061 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2062 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2064 Arguments args = new Arguments (2);
2065 args.Add (new Argument (b.left));
2066 args.Add (new Argument (b.right));
2069 if (b.oper == Operator.Equality) {
2070 if (equal_method == null) {
2071 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2072 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2073 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2074 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2076 throw new NotImplementedException (left.GetSignatureForError ());
2079 method = equal_method;
2081 if (inequal_method == null) {
2082 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2083 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2084 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2085 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2087 throw new NotImplementedException (left.GetSignatureForError ());
2090 method = inequal_method;
2093 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2097 class PredefinedPointerOperator : PredefinedOperator
2099 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2100 : base (ltype, rtype, op_mask)
2104 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2105 : base (ltype, rtype, op_mask, retType)
2109 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2110 : base (type, op_mask, return_type)
2114 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2117 if (!lexpr.Type.IsPointer)
2120 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2124 if (right == null) {
2125 if (!rexpr.Type.IsPointer)
2128 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2135 public override Expression ConvertResult (ResolveContext ec, Binary b)
2138 b.left = EmptyCast.Create (b.left, left);
2139 } else if (right != null) {
2140 b.right = EmptyCast.Create (b.right, right);
2143 TypeSpec r_type = ReturnType;
2144 Expression left_arg, right_arg;
2145 if (r_type == null) {
2148 right_arg = b.right;
2149 r_type = b.left.Type;
2153 r_type = b.right.Type;
2157 right_arg = b.right;
2160 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2165 public enum Operator {
2166 Multiply = 0 | ArithmeticMask,
2167 Division = 1 | ArithmeticMask,
2168 Modulus = 2 | ArithmeticMask,
2169 Addition = 3 | ArithmeticMask | AdditionMask,
2170 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2172 LeftShift = 5 | ShiftMask,
2173 RightShift = 6 | ShiftMask,
2175 LessThan = 7 | ComparisonMask | RelationalMask,
2176 GreaterThan = 8 | ComparisonMask | RelationalMask,
2177 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2178 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2179 Equality = 11 | ComparisonMask | EqualityMask,
2180 Inequality = 12 | ComparisonMask | EqualityMask,
2182 BitwiseAnd = 13 | BitwiseMask,
2183 ExclusiveOr = 14 | BitwiseMask,
2184 BitwiseOr = 15 | BitwiseMask,
2186 LogicalAnd = 16 | LogicalMask,
2187 LogicalOr = 17 | LogicalMask,
2192 ValuesOnlyMask = ArithmeticMask - 1,
2193 ArithmeticMask = 1 << 5,
2195 ComparisonMask = 1 << 7,
2196 EqualityMask = 1 << 8,
2197 BitwiseMask = 1 << 9,
2198 LogicalMask = 1 << 10,
2199 AdditionMask = 1 << 11,
2200 SubtractionMask = 1 << 12,
2201 RelationalMask = 1 << 13
2204 protected enum State
2208 LeftNullLifted = 1 << 2,
2209 RightNullLifted = 1 << 3
2212 readonly Operator oper;
2213 protected Expression left, right;
2214 protected State state;
2215 Expression enum_conversion;
2217 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
2218 : this (oper, left, right)
2221 state |= State.Compound;
2224 public Binary (Operator oper, Expression left, Expression right)
2229 this.loc = left.Location;
2234 public bool IsCompound {
2236 return (state & State.Compound) != 0;
2240 public Operator Oper {
2246 public Expression Left {
2252 public Expression Right {
2258 public override Location StartLocation {
2260 return left.StartLocation;
2267 /// Returns a stringified representation of the Operator
2269 string OperName (Operator oper)
2273 case Operator.Multiply:
2276 case Operator.Division:
2279 case Operator.Modulus:
2282 case Operator.Addition:
2285 case Operator.Subtraction:
2288 case Operator.LeftShift:
2291 case Operator.RightShift:
2294 case Operator.LessThan:
2297 case Operator.GreaterThan:
2300 case Operator.LessThanOrEqual:
2303 case Operator.GreaterThanOrEqual:
2306 case Operator.Equality:
2309 case Operator.Inequality:
2312 case Operator.BitwiseAnd:
2315 case Operator.BitwiseOr:
2318 case Operator.ExclusiveOr:
2321 case Operator.LogicalOr:
2324 case Operator.LogicalAnd:
2328 s = oper.ToString ();
2338 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2340 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2343 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2345 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
2349 l = left.Type.GetSignatureForError ();
2350 r = right.Type.GetSignatureForError ();
2352 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2356 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2358 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2362 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2364 string GetOperatorExpressionTypeName ()
2367 case Operator.Addition:
2368 return IsCompound ? "AddAssign" : "Add";
2369 case Operator.BitwiseAnd:
2370 return IsCompound ? "AndAssign" : "And";
2371 case Operator.BitwiseOr:
2372 return IsCompound ? "OrAssign" : "Or";
2373 case Operator.Division:
2374 return IsCompound ? "DivideAssign" : "Divide";
2375 case Operator.ExclusiveOr:
2376 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2377 case Operator.Equality:
2379 case Operator.GreaterThan:
2380 return "GreaterThan";
2381 case Operator.GreaterThanOrEqual:
2382 return "GreaterThanOrEqual";
2383 case Operator.Inequality:
2385 case Operator.LeftShift:
2386 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2387 case Operator.LessThan:
2389 case Operator.LessThanOrEqual:
2390 return "LessThanOrEqual";
2391 case Operator.LogicalAnd:
2393 case Operator.LogicalOr:
2395 case Operator.Modulus:
2396 return IsCompound ? "ModuloAssign" : "Modulo";
2397 case Operator.Multiply:
2398 return IsCompound ? "MultiplyAssign" : "Multiply";
2399 case Operator.RightShift:
2400 return IsCompound ? "RightShiftAssign" : "RightShift";
2401 case Operator.Subtraction:
2402 return IsCompound ? "SubtractAssign" : "Subtract";
2404 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2408 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2411 case Operator.Addition:
2412 return CSharp.Operator.OpType.Addition;
2413 case Operator.BitwiseAnd:
2414 case Operator.LogicalAnd:
2415 return CSharp.Operator.OpType.BitwiseAnd;
2416 case Operator.BitwiseOr:
2417 case Operator.LogicalOr:
2418 return CSharp.Operator.OpType.BitwiseOr;
2419 case Operator.Division:
2420 return CSharp.Operator.OpType.Division;
2421 case Operator.Equality:
2422 return CSharp.Operator.OpType.Equality;
2423 case Operator.ExclusiveOr:
2424 return CSharp.Operator.OpType.ExclusiveOr;
2425 case Operator.GreaterThan:
2426 return CSharp.Operator.OpType.GreaterThan;
2427 case Operator.GreaterThanOrEqual:
2428 return CSharp.Operator.OpType.GreaterThanOrEqual;
2429 case Operator.Inequality:
2430 return CSharp.Operator.OpType.Inequality;
2431 case Operator.LeftShift:
2432 return CSharp.Operator.OpType.LeftShift;
2433 case Operator.LessThan:
2434 return CSharp.Operator.OpType.LessThan;
2435 case Operator.LessThanOrEqual:
2436 return CSharp.Operator.OpType.LessThanOrEqual;
2437 case Operator.Modulus:
2438 return CSharp.Operator.OpType.Modulus;
2439 case Operator.Multiply:
2440 return CSharp.Operator.OpType.Multiply;
2441 case Operator.RightShift:
2442 return CSharp.Operator.OpType.RightShift;
2443 case Operator.Subtraction:
2444 return CSharp.Operator.OpType.Subtraction;
2446 throw new InternalErrorException (op.ToString ());
2450 public override bool ContainsEmitWithAwait ()
2452 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2455 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l)
2460 case Operator.Multiply:
2461 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2462 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2463 opcode = OpCodes.Mul_Ovf;
2464 else if (!IsFloat (l))
2465 opcode = OpCodes.Mul_Ovf_Un;
2467 opcode = OpCodes.Mul;
2469 opcode = OpCodes.Mul;
2473 case Operator.Division:
2475 opcode = OpCodes.Div_Un;
2477 opcode = OpCodes.Div;
2480 case Operator.Modulus:
2482 opcode = OpCodes.Rem_Un;
2484 opcode = OpCodes.Rem;
2487 case Operator.Addition:
2488 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2489 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2490 opcode = OpCodes.Add_Ovf;
2491 else if (!IsFloat (l))
2492 opcode = OpCodes.Add_Ovf_Un;
2494 opcode = OpCodes.Add;
2496 opcode = OpCodes.Add;
2499 case Operator.Subtraction:
2500 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2501 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2502 opcode = OpCodes.Sub_Ovf;
2503 else if (!IsFloat (l))
2504 opcode = OpCodes.Sub_Ovf_Un;
2506 opcode = OpCodes.Sub;
2508 opcode = OpCodes.Sub;
2511 case Operator.RightShift:
2513 opcode = OpCodes.Shr_Un;
2515 opcode = OpCodes.Shr;
2518 case Operator.LeftShift:
2519 opcode = OpCodes.Shl;
2522 case Operator.Equality:
2523 opcode = OpCodes.Ceq;
2526 case Operator.Inequality:
2527 ec.Emit (OpCodes.Ceq);
2530 opcode = OpCodes.Ceq;
2533 case Operator.LessThan:
2535 opcode = OpCodes.Clt_Un;
2537 opcode = OpCodes.Clt;
2540 case Operator.GreaterThan:
2542 opcode = OpCodes.Cgt_Un;
2544 opcode = OpCodes.Cgt;
2547 case Operator.LessThanOrEqual:
2548 if (IsUnsigned (l) || IsFloat (l))
2549 ec.Emit (OpCodes.Cgt_Un);
2551 ec.Emit (OpCodes.Cgt);
2554 opcode = OpCodes.Ceq;
2557 case Operator.GreaterThanOrEqual:
2558 if (IsUnsigned (l) || IsFloat (l))
2559 ec.Emit (OpCodes.Clt_Un);
2561 ec.Emit (OpCodes.Clt);
2565 opcode = OpCodes.Ceq;
2568 case Operator.BitwiseOr:
2569 opcode = OpCodes.Or;
2572 case Operator.BitwiseAnd:
2573 opcode = OpCodes.And;
2576 case Operator.ExclusiveOr:
2577 opcode = OpCodes.Xor;
2581 throw new InternalErrorException (oper.ToString ());
2587 static bool IsUnsigned (TypeSpec t)
2589 switch (t.BuiltinType) {
2590 case BuiltinTypeSpec.Type.Char:
2591 case BuiltinTypeSpec.Type.UInt:
2592 case BuiltinTypeSpec.Type.ULong:
2593 case BuiltinTypeSpec.Type.UShort:
2594 case BuiltinTypeSpec.Type.Byte:
2601 static bool IsFloat (TypeSpec t)
2603 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2606 Expression ResolveOperator (ResolveContext ec)
2608 TypeSpec l = left.Type;
2609 TypeSpec r = right.Type;
2611 bool primitives_only = false;
2614 // Handles predefined primitive types
2616 if (BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r)) {
2617 if ((oper & Operator.ShiftMask) == 0) {
2618 if (l.BuiltinType != BuiltinTypeSpec.Type.Bool && !DoBinaryOperatorPromotion (ec))
2621 primitives_only = true;
2625 if (l.IsPointer || r.IsPointer)
2626 return ResolveOperatorPointer (ec, l, r);
2629 bool lenum = l.IsEnum;
2630 bool renum = r.IsEnum;
2631 if (lenum || renum) {
2632 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2639 if ((oper == Operator.Addition || oper == Operator.Subtraction) && (l.IsDelegate || r.IsDelegate)) {
2641 expr = ResolveOperatorDelegate (ec, l, r);
2643 // TODO: Can this be ambiguous
2649 expr = ResolveUserOperator (ec, left, right);
2653 // Predefined reference types equality
2654 if ((oper & Operator.EqualityMask) != 0) {
2655 expr = ResolveOperatorEquality (ec, l, r);
2661 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, primitives_only, null);
2664 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2665 // if 'left' is not an enumeration constant, create one from the type of 'right'
2666 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2669 case Operator.BitwiseOr:
2670 case Operator.BitwiseAnd:
2671 case Operator.ExclusiveOr:
2672 case Operator.Equality:
2673 case Operator.Inequality:
2674 case Operator.LessThan:
2675 case Operator.LessThanOrEqual:
2676 case Operator.GreaterThan:
2677 case Operator.GreaterThanOrEqual:
2678 if (left.Type.IsEnum)
2681 if (left.IsZeroInteger)
2682 return left.Reduce (ec, right.Type);
2686 case Operator.Addition:
2687 case Operator.Subtraction:
2690 case Operator.Multiply:
2691 case Operator.Division:
2692 case Operator.Modulus:
2693 case Operator.LeftShift:
2694 case Operator.RightShift:
2695 if (right.Type.IsEnum || left.Type.IsEnum)
2704 // The `|' operator used on types which were extended is dangerous
2706 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2708 OpcodeCast lcast = left as OpcodeCast;
2709 if (lcast != null) {
2710 if (IsUnsigned (lcast.UnderlyingType))
2714 OpcodeCast rcast = right as OpcodeCast;
2715 if (rcast != null) {
2716 if (IsUnsigned (rcast.UnderlyingType))
2720 if (lcast == null && rcast == null)
2723 // FIXME: consider constants
2725 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
2726 ec.Report.Warning (675, 3, loc,
2727 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2728 ltype.GetSignatureForError ());
2731 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
2733 return new PredefinedOperator[] {
2735 // Pointer arithmetic:
2737 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2738 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2739 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2740 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2742 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
2743 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
2744 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
2745 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
2748 // T* operator + (int y, T* x);
2749 // T* operator + (uint y, T *x);
2750 // T* operator + (long y, T *x);
2751 // T* operator + (ulong y, T *x);
2753 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
2754 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
2755 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
2756 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
2759 // long operator - (T* x, T *y)
2761 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
2765 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
2767 TypeSpec bool_type = types.Bool;
2768 return new PredefinedOperator[] {
2769 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask),
2770 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
2771 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
2772 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
2773 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
2774 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
2775 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
2777 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
2778 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
2779 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
2780 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
2781 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
2782 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
2783 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
2785 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
2786 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
2787 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
2789 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
2791 new PredefinedShiftOperator (types.Int, types.Int, Operator.ShiftMask),
2792 new PredefinedShiftOperator (types.UInt, types.Int, Operator.ShiftMask),
2793 new PredefinedShiftOperator (types.Long, types.Int, Operator.ShiftMask),
2794 new PredefinedShiftOperator (types.ULong, types.Int, Operator.ShiftMask)
2798 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
2800 TypeSpec bool_type = types.Bool;
2802 return new PredefinedOperator[] {
2803 new PredefinedEqualityOperator (types.String, bool_type),
2804 new PredefinedEqualityOperator (types.Delegate, bool_type),
2805 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type)
2810 // Rules used during binary numeric promotion
2812 static bool DoNumericPromotion (ResolveContext rc, ref Expression prim_expr, ref Expression second_expr, TypeSpec type)
2816 Constant c = prim_expr as Constant;
2818 temp = c.ConvertImplicitly (type);
2825 if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
2826 switch (prim_expr.Type.BuiltinType) {
2827 case BuiltinTypeSpec.Type.Int:
2828 case BuiltinTypeSpec.Type.Short:
2829 case BuiltinTypeSpec.Type.SByte:
2830 case BuiltinTypeSpec.Type.Long:
2831 type = rc.BuiltinTypes.Long;
2833 if (type != second_expr.Type) {
2834 c = second_expr as Constant;
2836 temp = c.ConvertImplicitly (type);
2838 temp = Convert.ImplicitNumericConversion (second_expr, type);
2845 } else if (type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
2847 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2849 switch (type.BuiltinType) {
2850 case BuiltinTypeSpec.Type.Int:
2851 case BuiltinTypeSpec.Type.Long:
2852 case BuiltinTypeSpec.Type.Short:
2853 case BuiltinTypeSpec.Type.SByte:
2858 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2867 // 7.2.6.2 Binary numeric promotions
2869 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2871 TypeSpec ltype = left.Type;
2872 TypeSpec rtype = right.Type;
2875 foreach (TypeSpec t in ec.BuiltinTypes.BinaryPromotionsTypes) {
2877 return t == rtype || DoNumericPromotion (ec, ref right, ref left, t);
2880 return t == ltype || DoNumericPromotion (ec, ref left, ref right, t);
2883 TypeSpec int32 = ec.BuiltinTypes.Int;
2884 if (ltype != int32) {
2885 Constant c = left as Constant;
2887 temp = c.ConvertImplicitly (int32);
2889 temp = Convert.ImplicitNumericConversion (left, int32);
2896 if (rtype != int32) {
2897 Constant c = right as Constant;
2899 temp = c.ConvertImplicitly (int32);
2901 temp = Convert.ImplicitNumericConversion (right, int32);
2911 protected override Expression DoResolve (ResolveContext ec)
2916 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2917 left = ((ParenthesizedExpression) left).Expr;
2918 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2922 if (left.eclass == ExprClass.Type) {
2923 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2927 left = left.Resolve (ec);
2932 Constant lc = left as Constant;
2934 if (lc != null && lc.Type.BuiltinType == BuiltinTypeSpec.Type.Bool &&
2935 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2936 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2938 // FIXME: resolve right expression as unreachable
2939 // right.Resolve (ec);
2941 ec.Report.Warning (429, 4, right.StartLocation, "Unreachable expression code detected");
2945 right = right.Resolve (ec);
2949 eclass = ExprClass.Value;
2950 Constant rc = right as Constant;
2952 // The conversion rules are ignored in enum context but why
2953 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
2954 lc = EnumLiftUp (ec, lc, rc, loc);
2956 rc = EnumLiftUp (ec, rc, lc, loc);
2959 if (rc != null && lc != null) {
2960 int prev_e = ec.Report.Errors;
2961 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
2962 if (e != null || ec.Report.Errors != prev_e)
2966 // Comparison warnings
2967 if ((oper & Operator.ComparisonMask) != 0) {
2968 if (left.Equals (right)) {
2969 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2971 CheckOutOfRangeComparison (ec, lc, right.Type);
2972 CheckOutOfRangeComparison (ec, rc, left.Type);
2975 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2977 var rt = right.Type;
2978 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
2979 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
2980 Error_OperatorCannotBeApplied (ec, left, right);
2987 // Special handling for logical boolean operators which require rhs not to be
2988 // evaluated based on lhs value
2990 if ((oper & Operator.LogicalMask) != 0) {
2991 Expression cond_left, cond_right, expr;
2993 args = new Arguments (2);
2995 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2996 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, ec.CurrentBlock, loc);
2998 var cond_args = new Arguments (1);
2999 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left).Resolve (ec)));
3002 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
3003 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
3005 left = temp.CreateReferenceExpression (ec, loc);
3006 if (oper == Operator.LogicalAnd) {
3007 expr = DynamicUnaryConversion.CreateIsFalse (ec, cond_args, loc);
3010 expr = DynamicUnaryConversion.CreateIsTrue (ec, cond_args, loc);
3014 args.Add (new Argument (left));
3015 args.Add (new Argument (right));
3016 cond_right = new DynamicExpressionStatement (this, args, loc);
3018 LocalVariable temp = LocalVariable.CreateCompilerGenerated (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
3020 args.Add (new Argument (temp.CreateReferenceExpression (ec, loc).Resolve (ec)));
3021 args.Add (new Argument (right));
3022 right = new DynamicExpressionStatement (this, args, loc);
3025 // bool && dynamic => (temp = left) ? temp && right : temp;
3026 // bool || dynamic => (temp = left) ? temp : temp || right;
3028 if (oper == Operator.LogicalAnd) {
3030 cond_right = temp.CreateReferenceExpression (ec, loc);
3032 cond_left = temp.CreateReferenceExpression (ec, loc);
3036 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left));
3039 return new Conditional (expr, cond_left, cond_right, loc).Resolve (ec);
3042 args = new Arguments (2);
3043 args.Add (new Argument (left));
3044 args.Add (new Argument (right));
3045 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
3048 if (ec.Module.Compiler.Settings.Version >= LanguageVersion.ISO_2 &&
3049 ((left.Type.IsNullableType && (right is NullLiteral || right.Type.IsNullableType || TypeSpec.IsValueType (right.Type))) ||
3050 (TypeSpec.IsValueType (left.Type) && right is NullLiteral) ||
3051 (right.Type.IsNullableType && (left is NullLiteral || left.Type.IsNullableType || TypeSpec.IsValueType (left.Type))) ||
3052 (TypeSpec.IsValueType (right.Type) && left is NullLiteral))) {
3053 var lifted = new Nullable.LiftedBinaryOperator (oper, left, right);
3054 lifted.state = state;
3055 return lifted.Resolve (ec);
3058 return DoResolveCore (ec, left, right);
3061 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3063 Expression expr = ResolveOperator (ec);
3065 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3067 if (left == null || right == null)
3068 throw new InternalErrorException ("Invalid conversion");
3070 if (oper == Operator.BitwiseOr)
3071 CheckBitwiseOrOnSignExtended (ec);
3076 public override SLE.Expression MakeExpression (BuilderContext ctx)
3078 var le = left.MakeExpression (ctx);
3079 var re = right.MakeExpression (ctx);
3080 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3083 case Operator.Addition:
3084 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3085 case Operator.BitwiseAnd:
3086 return SLE.Expression.And (le, re);
3087 case Operator.BitwiseOr:
3088 return SLE.Expression.Or (le, re);
3089 case Operator.Division:
3090 return SLE.Expression.Divide (le, re);
3091 case Operator.Equality:
3092 return SLE.Expression.Equal (le, re);
3093 case Operator.ExclusiveOr:
3094 return SLE.Expression.ExclusiveOr (le, re);
3095 case Operator.GreaterThan:
3096 return SLE.Expression.GreaterThan (le, re);
3097 case Operator.GreaterThanOrEqual:
3098 return SLE.Expression.GreaterThanOrEqual (le, re);
3099 case Operator.Inequality:
3100 return SLE.Expression.NotEqual (le, re);
3101 case Operator.LeftShift:
3102 return SLE.Expression.LeftShift (le, re);
3103 case Operator.LessThan:
3104 return SLE.Expression.LessThan (le, re);
3105 case Operator.LessThanOrEqual:
3106 return SLE.Expression.LessThanOrEqual (le, re);
3107 case Operator.LogicalAnd:
3108 return SLE.Expression.AndAlso (le, re);
3109 case Operator.LogicalOr:
3110 return SLE.Expression.OrElse (le, re);
3111 case Operator.Modulus:
3112 return SLE.Expression.Modulo (le, re);
3113 case Operator.Multiply:
3114 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3115 case Operator.RightShift:
3116 return SLE.Expression.RightShift (le, re);
3117 case Operator.Subtraction:
3118 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3120 throw new NotImplementedException (oper.ToString ());
3125 // D operator + (D x, D y)
3126 // D operator - (D x, D y)
3128 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3130 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3132 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3133 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3138 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3139 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3149 MethodSpec method = null;
3150 Arguments args = new Arguments (2);
3151 args.Add (new Argument (left));
3152 args.Add (new Argument (right));
3154 if (oper == Operator.Addition) {
3155 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3156 } else if (oper == Operator.Subtraction) {
3157 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3161 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3163 MethodGroupExpr mg = MethodGroupExpr.CreatePredefined (method, ec.BuiltinTypes.Delegate, loc);
3164 Expression expr = new UserOperatorCall (mg.BestCandidate, args, CreateExpressionTree, loc);
3165 return new ClassCast (expr, l);
3169 // Enumeration operators
3171 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3174 // bool operator == (E x, E y);
3175 // bool operator != (E x, E y);
3176 // bool operator < (E x, E y);
3177 // bool operator > (E x, E y);
3178 // bool operator <= (E x, E y);
3179 // bool operator >= (E x, E y);
3181 // E operator & (E x, E y);
3182 // E operator | (E x, E y);
3183 // E operator ^ (E x, E y);
3185 // U operator - (E e, E f)
3186 // E operator - (E e, U x)
3187 // E operator - (U x, E e) // LAMESPEC: Not covered by the specification
3189 // E operator + (E e, U x)
3190 // E operator + (U x, E e)
3192 Expression ltemp = left;
3193 Expression rtemp = right;
3194 TypeSpec underlying_type;
3195 TypeSpec underlying_type_result;
3200 // LAMESPEC: There is never ambiguous conversion between enum operators
3201 // the one which contains more enum parameters always wins even if there
3202 // is an implicit conversion involved
3204 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3206 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3207 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
3214 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3215 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
3225 if ((oper & Operator.BitwiseMask) != 0) {
3227 underlying_type_result = underlying_type;
3230 underlying_type_result = null;
3232 } else if (oper == Operator.Subtraction) {
3234 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3235 if (ltype != rtype) {
3236 expr = Convert.ImplicitConversion (ec, left, rtype, left.Location);
3238 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3244 res_type = underlying_type;
3249 res_type = underlying_type;
3252 underlying_type_result = underlying_type;
3254 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3255 expr = Convert.ImplicitConversion (ec, right, ltype, right.Location);
3256 if (expr == null || expr is EnumConstant) {
3257 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3263 res_type = underlying_type;
3267 underlying_type_result = underlying_type;
3271 } else if (oper == Operator.Addition) {
3273 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3276 if (rtype != underlying_type && (state & (State.RightNullLifted | State.LeftNullLifted)) == 0) {
3277 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3284 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3286 if (ltype != underlying_type) {
3287 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3295 underlying_type_result = underlying_type;
3300 // Unwrap the constant correctly, so DoBinaryOperatorPromotion can do the magic
3301 // with constants and expressions
3302 if (left.Type != underlying_type) {
3303 if (left is Constant)
3304 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
3306 left = EmptyCast.Create (left, underlying_type);
3309 if (right.Type != underlying_type) {
3310 if (right is Constant)
3311 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
3313 right = EmptyCast.Create (right, underlying_type);
3317 // C# specification uses explicit cast syntax which means binary promotion
3318 // should happen, however it seems that csc does not do that
3320 if (!DoBinaryOperatorPromotion (ec)) {
3326 if (underlying_type_result != null && left.Type != underlying_type_result) {
3327 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (left.Type), underlying_type_result);
3330 expr = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, true, res_type);
3342 // If the return type of the selected operator is implicitly convertible to the type of x
3344 if (Convert.ImplicitConversionExists (ec, expr, ltype))
3348 // Otherwise, if the selected operator is a predefined operator, if the return type of the
3349 // selected operator is explicitly convertible to the type of x, and if y is implicitly
3350 // convertible to the type of x or the operator is a shift operator, then the operation
3351 // is evaluated as x = (T)(x op y), where T is the type of x
3353 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
3357 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
3364 // 7.9.6 Reference type equality operators
3366 Expression ResolveOperatorEquality (ResolveContext ec, TypeSpec l, TypeSpec r)
3369 type = ec.BuiltinTypes.Bool;
3372 // a, Both operands are reference-type values or the value null
3373 // b, One operand is a value of type T where T is a type-parameter and
3374 // the other operand is the value null. Furthermore T does not have the
3375 // value type constraint
3377 // LAMESPEC: Very confusing details in the specification, basically any
3378 // reference like type-parameter is allowed
3380 var tparam_l = l as TypeParameterSpec;
3381 var tparam_r = r as TypeParameterSpec;
3382 if (tparam_l != null) {
3383 if (right is NullLiteral && !tparam_l.HasSpecialStruct) {
3384 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3388 if (!tparam_l.IsReferenceType)
3391 l = tparam_l.GetEffectiveBase ();
3392 left = new BoxedCast (left, l);
3393 } else if (left is NullLiteral && tparam_r == null) {
3394 if (!TypeSpec.IsReferenceType (r) || r.Kind == MemberKind.InternalCompilerType)
3400 if (tparam_r != null) {
3401 if (left is NullLiteral && !tparam_r.HasSpecialStruct) {
3402 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3406 if (!tparam_r.IsReferenceType)
3409 r = tparam_r.GetEffectiveBase ();
3410 right = new BoxedCast (right, r);
3411 } else if (right is NullLiteral) {
3412 if (!TypeSpec.IsReferenceType (l) || l.Kind == MemberKind.InternalCompilerType)
3418 bool no_arg_conv = false;
3421 // LAMESPEC: method groups can be compared when they convert to other side delegate
3424 if (right.eclass == ExprClass.MethodGroup) {
3425 result = Convert.ImplicitConversion (ec, right, l, loc);
3431 } else if (r.IsDelegate && l != r) {
3434 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3435 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3442 no_arg_conv = l == r && !l.IsStruct;
3446 // bool operator != (string a, string b)
3447 // bool operator == (string a, string b)
3449 // bool operator != (Delegate a, Delegate b)
3450 // bool operator == (Delegate a, Delegate b)
3452 // bool operator != (bool a, bool b)
3453 // bool operator == (bool a, bool b)
3455 // LAMESPEC: Reference equality comparison can apply to value/reference types when
3456 // they implement an implicit conversion to any of types above. This does
3457 // not apply when both operands are of same reference type
3459 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3460 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv, null);
3466 // bool operator != (object a, object b)
3467 // bool operator == (object a, object b)
3469 // An explicit reference conversion exists from the
3470 // type of either operand to the type of the other operand.
3473 // Optimize common path
3475 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3478 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3479 !Convert.ExplicitReferenceConversionExists (r, l))
3482 // Reject allowed explicit conversions like int->object
3483 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
3486 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3487 ec.Report.Warning (253, 2, loc,
3488 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3489 l.GetSignatureForError ());
3491 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3492 ec.Report.Warning (252, 2, loc,
3493 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3494 r.GetSignatureForError ());
3500 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3503 // bool operator == (void* x, void* y);
3504 // bool operator != (void* x, void* y);
3505 // bool operator < (void* x, void* y);
3506 // bool operator > (void* x, void* y);
3507 // bool operator <= (void* x, void* y);
3508 // bool operator >= (void* x, void* y);
3510 if ((oper & Operator.ComparisonMask) != 0) {
3513 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3520 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3526 type = ec.BuiltinTypes.Bool;
3530 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false, null);
3534 // Build-in operators method overloading
3536 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, TypeSpec enum_type)
3538 PredefinedOperator best_operator = null;
3539 TypeSpec l = left.Type;
3540 TypeSpec r = right.Type;
3541 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3543 foreach (PredefinedOperator po in operators) {
3544 if ((po.OperatorsMask & oper_mask) == 0)
3547 if (primitives_only) {
3548 if (!po.IsPrimitiveApplicable (l, r))
3551 if (!po.IsApplicable (ec, left, right))
3555 if (best_operator == null) {
3557 if (primitives_only)
3563 best_operator = po.ResolveBetterOperator (ec, best_operator);
3565 if (best_operator == null) {
3566 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3567 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
3574 if (best_operator == null)
3577 Expression expr = best_operator.ConvertResult (ec, this);
3580 // Optimize &/&& constant expressions with 0 value
3582 if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
3583 Constant rc = right as Constant;
3584 Constant lc = left as Constant;
3585 if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
3587 // The result is a constant with side-effect
3589 Constant side_effect = rc == null ?
3590 new SideEffectConstant (lc, right, loc) :
3591 new SideEffectConstant (rc, left, loc);
3593 return ReducedExpression.Create (side_effect, expr);
3597 if (enum_type == null)
3601 // HACK: required by enum_conversion
3603 expr.Type = enum_type;
3604 return EmptyCast.Create (expr, enum_type);
3608 // Performs user-operator overloading
3610 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression left, Expression right)
3612 var op = ConvertBinaryToUserOperator (oper);
3614 if (l.IsNullableType)
3615 l = Nullable.NullableInfo.GetUnderlyingType (l);
3617 if (r.IsNullableType)
3618 r = Nullable.NullableInfo.GetUnderlyingType (r);
3620 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
3621 IList<MemberSpec> right_operators = null;
3624 right_operators = MemberCache.GetUserOperator (r, op, false);
3625 if (right_operators == null && left_operators == null)
3627 } else if (left_operators == null) {
3631 Arguments args = new Arguments (2);
3632 Argument larg = new Argument (left);
3634 Argument rarg = new Argument (right);
3638 // User-defined operator implementations always take precedence
3639 // over predefined operator implementations
3641 if (left_operators != null && right_operators != null) {
3642 left_operators = CombineUserOperators (left_operators, right_operators);
3643 } else if (right_operators != null) {
3644 left_operators = right_operators;
3647 var res = new OverloadResolver (left_operators, OverloadResolver.Restrictions.ProbingOnly |
3648 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded, loc);
3650 var oper_method = res.ResolveOperator (ec, ref args);
3651 if (oper_method == null)
3654 var llifted = (state & State.LeftNullLifted) != 0;
3655 var rlifted = (state & State.RightNullLifted) != 0;
3656 if ((Oper & Operator.EqualityMask) != 0) {
3657 var parameters = oper_method.Parameters;
3658 // LAMESPEC: No idea why this is not allowed
3659 if ((left is Nullable.Unwrap || right is Nullable.Unwrap) && parameters.Types [0] != parameters.Types [1])
3662 // Binary operation was lifted but we have found a user operator
3663 // which requires value-type argument, we downgrade ourself back to
3665 // LAMESPEC: The user operator is not called (it cannot be we are passing null to struct)
3666 // but compilation succeeds
3667 if ((llifted && !parameters.Types[0].IsStruct) || (rlifted && !parameters.Types[1].IsStruct)) {
3668 state &= ~(State.LeftNullLifted | State.RightNullLifted);
3672 Expression oper_expr;
3674 // TODO: CreateExpressionTree is allocated every time
3675 if ((oper & Operator.LogicalMask) != 0) {
3676 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
3677 oper == Operator.LogicalAnd, loc).Resolve (ec);
3679 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
3683 this.left = larg.Expr;
3686 this.right = rarg.Expr;
3692 // Merge two sets of user operators into one, they are mostly distinguish
3693 // except when they share base type and it contains an operator
3695 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
3697 var combined = new List<MemberSpec> (left.Count + right.Count);
3698 combined.AddRange (left);
3699 foreach (var r in right) {
3701 foreach (var l in left) {
3702 if (l.DeclaringType == r.DeclaringType) {
3715 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
3717 if (c is IntegralConstant || c is CharConstant) {
3719 c.ConvertExplicitly (true, type);
3720 } catch (OverflowException) {
3721 ec.Report.Warning (652, 2, loc,
3722 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
3723 type.GetSignatureForError ());
3729 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3730 /// context of a conditional bool expression. This function will return
3731 /// false if it is was possible to use EmitBranchable, or true if it was.
3733 /// The expression's code is generated, and we will generate a branch to `target'
3734 /// if the resulting expression value is equal to isTrue
3736 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3739 // This is more complicated than it looks, but its just to avoid
3740 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3741 // but on top of that we want for == and != to use a special path
3742 // if we are comparing against null
3744 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
3745 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3748 // put the constant on the rhs, for simplicity
3750 if (left is Constant) {
3751 Expression swap = right;
3757 // brtrue/brfalse works with native int only
3759 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
3760 left.EmitBranchable (ec, target, my_on_true);
3763 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
3764 // right is a boolean, and it's not 'false' => it is 'true'
3765 left.EmitBranchable (ec, target, !my_on_true);
3769 } else if (oper == Operator.LogicalAnd) {
3772 Label tests_end = ec.DefineLabel ();
3774 left.EmitBranchable (ec, tests_end, false);
3775 right.EmitBranchable (ec, target, true);
3776 ec.MarkLabel (tests_end);
3779 // This optimizes code like this
3780 // if (true && i > 4)
3782 if (!(left is Constant))
3783 left.EmitBranchable (ec, target, false);
3785 if (!(right is Constant))
3786 right.EmitBranchable (ec, target, false);
3791 } else if (oper == Operator.LogicalOr){
3793 left.EmitBranchable (ec, target, true);
3794 right.EmitBranchable (ec, target, true);
3797 Label tests_end = ec.DefineLabel ();
3798 left.EmitBranchable (ec, tests_end, true);
3799 right.EmitBranchable (ec, target, false);
3800 ec.MarkLabel (tests_end);
3805 } else if ((oper & Operator.ComparisonMask) == 0) {
3806 base.EmitBranchable (ec, target, on_true);
3813 TypeSpec t = left.Type;
3814 bool is_float = IsFloat (t);
3815 bool is_unsigned = is_float || IsUnsigned (t);
3818 case Operator.Equality:
3820 ec.Emit (OpCodes.Beq, target);
3822 ec.Emit (OpCodes.Bne_Un, target);
3825 case Operator.Inequality:
3827 ec.Emit (OpCodes.Bne_Un, target);
3829 ec.Emit (OpCodes.Beq, target);
3832 case Operator.LessThan:
3834 if (is_unsigned && !is_float)
3835 ec.Emit (OpCodes.Blt_Un, target);
3837 ec.Emit (OpCodes.Blt, target);
3840 ec.Emit (OpCodes.Bge_Un, target);
3842 ec.Emit (OpCodes.Bge, target);
3845 case Operator.GreaterThan:
3847 if (is_unsigned && !is_float)
3848 ec.Emit (OpCodes.Bgt_Un, target);
3850 ec.Emit (OpCodes.Bgt, target);
3853 ec.Emit (OpCodes.Ble_Un, target);
3855 ec.Emit (OpCodes.Ble, target);
3858 case Operator.LessThanOrEqual:
3860 if (is_unsigned && !is_float)
3861 ec.Emit (OpCodes.Ble_Un, target);
3863 ec.Emit (OpCodes.Ble, target);
3866 ec.Emit (OpCodes.Bgt_Un, target);
3868 ec.Emit (OpCodes.Bgt, target);
3872 case Operator.GreaterThanOrEqual:
3874 if (is_unsigned && !is_float)
3875 ec.Emit (OpCodes.Bge_Un, target);
3877 ec.Emit (OpCodes.Bge, target);
3880 ec.Emit (OpCodes.Blt_Un, target);
3882 ec.Emit (OpCodes.Blt, target);
3885 throw new InternalErrorException (oper.ToString ());
3889 public override void Emit (EmitContext ec)
3891 EmitOperator (ec, left.Type);
3894 protected virtual void EmitOperator (EmitContext ec, TypeSpec l)
3896 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
3897 left = left.EmitToField (ec);
3899 if ((oper & Operator.LogicalMask) == 0) {
3900 right = right.EmitToField (ec);
3905 // Handle short-circuit operators differently
3908 if ((oper & Operator.LogicalMask) != 0) {
3909 Label load_result = ec.DefineLabel ();
3910 Label end = ec.DefineLabel ();
3912 bool is_or = oper == Operator.LogicalOr;
3913 left.EmitBranchable (ec, load_result, is_or);
3915 ec.Emit (OpCodes.Br_S, end);
3917 ec.MarkLabel (load_result);
3918 ec.EmitInt (is_or ? 1 : 0);
3924 // Optimize zero-based operations which cannot be optimized at expression level
3926 if (oper == Operator.Subtraction) {
3927 var lc = left as IntegralConstant;
3928 if (lc != null && lc.IsDefaultValue) {
3930 ec.Emit (OpCodes.Neg);
3937 EmitOperatorOpcode (ec, oper, l);
3940 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3941 // expression because that would wrap lifted binary operation
3943 if (enum_conversion != null)
3944 enum_conversion.Emit (ec);
3947 public override void EmitSideEffect (EmitContext ec)
3949 if ((oper & Operator.LogicalMask) != 0 ||
3950 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3951 base.EmitSideEffect (ec);
3953 left.EmitSideEffect (ec);
3954 right.EmitSideEffect (ec);
3958 public override Expression EmitToField (EmitContext ec)
3960 if ((oper & Operator.LogicalMask) == 0) {
3961 var await_expr = left as Await;
3962 if (await_expr != null && right.IsSideEffectFree) {
3963 await_expr.Statement.EmitPrologue (ec);
3964 left = await_expr.Statement.GetResultExpression (ec);
3968 await_expr = right as Await;
3969 if (await_expr != null && left.IsSideEffectFree) {
3970 await_expr.Statement.EmitPrologue (ec);
3971 right = await_expr.Statement.GetResultExpression (ec);
3976 return base.EmitToField (ec);
3979 protected override void CloneTo (CloneContext clonectx, Expression t)
3981 Binary target = (Binary) t;
3983 target.left = left.Clone (clonectx);
3984 target.right = right.Clone (clonectx);
3987 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3989 Arguments binder_args = new Arguments (4);
3991 MemberAccess sle = new MemberAccess (new MemberAccess (
3992 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3994 CSharpBinderFlags flags = 0;
3995 if (ec.HasSet (ResolveContext.Options.CheckedScope))
3996 flags = CSharpBinderFlags.CheckedContext;
3998 if ((oper & Operator.LogicalMask) != 0)
3999 flags |= CSharpBinderFlags.BinaryOperationLogical;
4001 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
4002 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
4003 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
4004 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
4006 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
4009 public override Expression CreateExpressionTree (ResolveContext ec)
4011 return CreateExpressionTree (ec, null);
4014 Expression CreateExpressionTree (ResolveContext ec, Expression method)
4017 bool lift_arg = false;
4020 case Operator.Addition:
4021 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4022 method_name = "AddChecked";
4024 method_name = "Add";
4026 case Operator.BitwiseAnd:
4027 method_name = "And";
4029 case Operator.BitwiseOr:
4032 case Operator.Division:
4033 method_name = "Divide";
4035 case Operator.Equality:
4036 method_name = "Equal";
4039 case Operator.ExclusiveOr:
4040 method_name = "ExclusiveOr";
4042 case Operator.GreaterThan:
4043 method_name = "GreaterThan";
4046 case Operator.GreaterThanOrEqual:
4047 method_name = "GreaterThanOrEqual";
4050 case Operator.Inequality:
4051 method_name = "NotEqual";
4054 case Operator.LeftShift:
4055 method_name = "LeftShift";
4057 case Operator.LessThan:
4058 method_name = "LessThan";
4061 case Operator.LessThanOrEqual:
4062 method_name = "LessThanOrEqual";
4065 case Operator.LogicalAnd:
4066 method_name = "AndAlso";
4068 case Operator.LogicalOr:
4069 method_name = "OrElse";
4071 case Operator.Modulus:
4072 method_name = "Modulo";
4074 case Operator.Multiply:
4075 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4076 method_name = "MultiplyChecked";
4078 method_name = "Multiply";
4080 case Operator.RightShift:
4081 method_name = "RightShift";
4083 case Operator.Subtraction:
4084 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4085 method_name = "SubtractChecked";
4087 method_name = "Subtract";
4091 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4094 Arguments args = new Arguments (2);
4095 args.Add (new Argument (left.CreateExpressionTree (ec)));
4096 args.Add (new Argument (right.CreateExpressionTree (ec)));
4097 if (method != null) {
4099 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4101 args.Add (new Argument (method));
4104 return CreateExpressionFactoryCall (ec, method_name, args);
4107 public override object Accept (StructuralVisitor visitor)
4109 return visitor.Visit (this);
4115 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4116 // b, c, d... may be strings or objects.
4118 public class StringConcat : Expression
4120 Arguments arguments;
4122 StringConcat (Location loc)
4125 arguments = new Arguments (2);
4128 public override bool ContainsEmitWithAwait ()
4130 return arguments.ContainsEmitWithAwait ();
4133 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4135 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4136 throw new ArgumentException ();
4138 var s = new StringConcat (loc);
4139 s.type = rc.BuiltinTypes.String;
4140 s.eclass = ExprClass.Value;
4142 s.Append (rc, left);
4143 s.Append (rc, right);
4147 public override Expression CreateExpressionTree (ResolveContext ec)
4149 Argument arg = arguments [0];
4150 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4154 // Creates nested calls tree from an array of arguments used for IL emit
4156 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4158 Arguments concat_args = new Arguments (2);
4159 Arguments add_args = new Arguments (3);
4161 concat_args.Add (left);
4162 add_args.Add (new Argument (left_etree));
4164 concat_args.Add (arguments [pos]);
4165 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4167 var methods = GetConcatMethodCandidates ();
4168 if (methods == null)
4171 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4172 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4176 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4178 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4179 if (++pos == arguments.Count)
4182 left = new Argument (new EmptyExpression (method.ReturnType));
4183 return CreateExpressionAddCall (ec, left, expr, pos);
4186 protected override Expression DoResolve (ResolveContext ec)
4191 void Append (ResolveContext rc, Expression operand)
4196 StringConstant sc = operand as StringConstant;
4198 if (arguments.Count != 0) {
4199 Argument last_argument = arguments [arguments.Count - 1];
4200 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4201 if (last_expr_constant != null) {
4202 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4208 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4210 StringConcat concat_oper = operand as StringConcat;
4211 if (concat_oper != null) {
4212 arguments.AddRange (concat_oper.arguments);
4217 arguments.Add (new Argument (operand));
4220 IList<MemberSpec> GetConcatMethodCandidates ()
4222 return MemberCache.FindMembers (type, "Concat", true);
4225 public override void Emit (EmitContext ec)
4227 // Optimize by removing any extra null arguments, they are no-op
4228 for (int i = 0; i < arguments.Count; ++i) {
4229 if (arguments[i].Expr is NullConstant)
4230 arguments.RemoveAt (i--);
4233 var members = GetConcatMethodCandidates ();
4234 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4235 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4236 if (method != null) {
4237 var call = new CallEmitter ();
4238 call.EmitPredefined (ec, method, arguments);
4242 public override SLE.Expression MakeExpression (BuilderContext ctx)
4244 if (arguments.Count != 2)
4245 throw new NotImplementedException ("arguments.Count != 2");
4247 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4248 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4253 // User-defined conditional logical operator
4255 public class ConditionalLogicalOperator : UserOperatorCall
4257 readonly bool is_and;
4258 Expression oper_expr;
4260 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4261 : base (oper, arguments, expr_tree, loc)
4263 this.is_and = is_and;
4264 eclass = ExprClass.Unresolved;
4267 protected override Expression DoResolve (ResolveContext ec)
4269 AParametersCollection pd = oper.Parameters;
4270 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4271 ec.Report.Error (217, loc,
4272 "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",
4273 oper.GetSignatureForError ());
4277 Expression left_dup = new EmptyExpression (type);
4278 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4279 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4280 if (op_true == null || op_false == null) {
4281 ec.Report.Error (218, loc,
4282 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4283 type.GetSignatureForError (), oper.GetSignatureForError ());
4287 oper_expr = is_and ? op_false : op_true;
4288 eclass = ExprClass.Value;
4292 public override void Emit (EmitContext ec)
4294 Label end_target = ec.DefineLabel ();
4297 // Emit and duplicate left argument
4299 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
4300 if (right_contains_await) {
4301 arguments[0] = arguments[0].EmitToField (ec, false);
4302 arguments[0].Expr.Emit (ec);
4304 arguments[0].Expr.Emit (ec);
4305 ec.Emit (OpCodes.Dup);
4306 arguments.RemoveAt (0);
4309 oper_expr.EmitBranchable (ec, end_target, true);
4313 if (right_contains_await) {
4315 // Special handling when right expression contains await and left argument
4316 // could not be left on stack before logical branch
4318 Label skip_left_load = ec.DefineLabel ();
4319 ec.Emit (OpCodes.Br_S, skip_left_load);
4320 ec.MarkLabel (end_target);
4321 arguments[0].Expr.Emit (ec);
4322 ec.MarkLabel (skip_left_load);
4324 ec.MarkLabel (end_target);
4329 public class PointerArithmetic : Expression {
4330 Expression left, right;
4334 // We assume that `l' is always a pointer
4336 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4345 public override bool ContainsEmitWithAwait ()
4347 throw new NotImplementedException ();
4350 public override Expression CreateExpressionTree (ResolveContext ec)
4352 Error_PointerInsideExpressionTree (ec);
4356 protected override Expression DoResolve (ResolveContext ec)
4358 eclass = ExprClass.Variable;
4360 var pc = left.Type as PointerContainer;
4361 if (pc != null && pc.Element.Kind == MemberKind.Void) {
4362 Error_VoidPointerOperation (ec);
4369 public override void Emit (EmitContext ec)
4371 TypeSpec op_type = left.Type;
4373 // It must be either array or fixed buffer
4375 if (TypeManager.HasElementType (op_type)) {
4376 element = TypeManager.GetElementType (op_type);
4378 FieldExpr fe = left as FieldExpr;
4380 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
4385 int size = BuiltinTypeSpec.GetSize(element);
4386 TypeSpec rtype = right.Type;
4388 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4390 // handle (pointer - pointer)
4394 ec.Emit (OpCodes.Sub);
4398 ec.Emit (OpCodes.Sizeof, element);
4401 ec.Emit (OpCodes.Div);
4403 ec.Emit (OpCodes.Conv_I8);
4406 // handle + and - on (pointer op int)
4408 Constant left_const = left as Constant;
4409 if (left_const != null) {
4411 // Optimize ((T*)null) pointer operations
4413 if (left_const.IsDefaultValue) {
4414 left = EmptyExpression.Null;
4422 var right_const = right as Constant;
4423 if (right_const != null) {
4425 // Optimize 0-based arithmetic
4427 if (right_const.IsDefaultValue)
4431 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
4433 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
4435 // TODO: Should be the checks resolve context sensitive?
4436 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
4437 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
4443 switch (rtype.BuiltinType) {
4444 case BuiltinTypeSpec.Type.SByte:
4445 case BuiltinTypeSpec.Type.Byte:
4446 case BuiltinTypeSpec.Type.Short:
4447 case BuiltinTypeSpec.Type.UShort:
4448 ec.Emit (OpCodes.Conv_I);
4450 case BuiltinTypeSpec.Type.UInt:
4451 ec.Emit (OpCodes.Conv_U);
4455 if (right_const == null && size != 1){
4457 ec.Emit (OpCodes.Sizeof, element);
4460 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4461 ec.Emit (OpCodes.Conv_I8);
4463 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4466 if (left_const == null) {
4467 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
4468 ec.Emit (OpCodes.Conv_I);
4469 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4470 ec.Emit (OpCodes.Conv_U);
4472 Binary.EmitOperatorOpcode (ec, op, op_type);
4479 // A boolean-expression is an expression that yields a result
4482 public class BooleanExpression : ShimExpression
4484 public BooleanExpression (Expression expr)
4487 this.loc = expr.Location;
4490 public override Expression CreateExpressionTree (ResolveContext ec)
4492 // TODO: We should emit IsTrue (v4) instead of direct user operator
4493 // call but that would break csc compatibility
4494 return base.CreateExpressionTree (ec);
4497 protected override Expression DoResolve (ResolveContext ec)
4499 // A boolean-expression is required to be of a type
4500 // that can be implicitly converted to bool or of
4501 // a type that implements operator true
4503 expr = expr.Resolve (ec);
4507 Assign ass = expr as Assign;
4508 if (ass != null && ass.Source is Constant) {
4509 ec.Report.Warning (665, 3, loc,
4510 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4513 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
4516 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4517 Arguments args = new Arguments (1);
4518 args.Add (new Argument (expr));
4519 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
4522 type = ec.BuiltinTypes.Bool;
4523 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4524 if (converted != null)
4528 // If no implicit conversion to bool exists, try using `operator true'
4530 converted = GetOperatorTrue (ec, expr, loc);
4531 if (converted == null) {
4532 expr.Error_ValueCannotBeConverted (ec, type, false);
4539 public override object Accept (StructuralVisitor visitor)
4541 return visitor.Visit (this);
4545 public class BooleanExpressionFalse : Unary
4547 public BooleanExpressionFalse (Expression expr)
4548 : base (Operator.LogicalNot, expr, expr.Location)
4552 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
4554 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
4559 /// Implements the ternary conditional operator (?:)
4561 public class Conditional : Expression {
4562 Expression expr, true_expr, false_expr;
4564 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
4567 this.true_expr = true_expr;
4568 this.false_expr = false_expr;
4574 public Expression Expr {
4580 public Expression TrueExpr {
4586 public Expression FalseExpr {
4594 public override bool ContainsEmitWithAwait ()
4596 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
4599 public override Expression CreateExpressionTree (ResolveContext ec)
4601 Arguments args = new Arguments (3);
4602 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4603 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4604 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4605 return CreateExpressionFactoryCall (ec, "Condition", args);
4608 protected override Expression DoResolve (ResolveContext ec)
4610 expr = expr.Resolve (ec);
4613 // Unreachable code needs different resolve path. For instance for await
4614 // expression to not generate unreachable resumable statement
4616 Constant c = expr as Constant;
4617 if (c != null && ec.CurrentBranching != null) {
4618 bool unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
4620 if (c.IsDefaultValue) {
4621 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
4622 true_expr = true_expr.Resolve (ec);
4623 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
4625 false_expr = false_expr.Resolve (ec);
4627 true_expr = true_expr.Resolve (ec);
4629 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
4630 false_expr = false_expr.Resolve (ec);
4631 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
4634 true_expr = true_expr.Resolve (ec);
4635 false_expr = false_expr.Resolve (ec);
4638 if (true_expr == null || false_expr == null || expr == null)
4641 eclass = ExprClass.Value;
4642 TypeSpec true_type = true_expr.Type;
4643 TypeSpec false_type = false_expr.Type;
4647 // First, if an implicit conversion exists from true_expr
4648 // to false_expr, then the result type is of type false_expr.Type
4650 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
4651 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4652 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
4654 // Check if both can convert implicitly to each other's type
4658 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
4659 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
4661 // LAMESPEC: There seems to be hardcoded promotition to int type when
4662 // both sides are numeric constants and one side is int constant and
4663 // other side is numeric constant convertible to int.
4665 // var res = condition ? (short)1 : 1;
4667 // Type of res is int even if according to the spec the conversion is
4668 // ambiguous because 1 literal can be converted to short.
4670 if (conv_false_expr != null) {
4671 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
4673 conv_false_expr = null;
4674 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
4675 conv_false_expr = null;
4679 if (conv_false_expr != null) {
4680 ec.Report.Error (172, true_expr.Location,
4681 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
4682 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
4687 if (true_expr.Type != type)
4688 true_expr = EmptyCast.Create (true_expr, type);
4689 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4692 ec.Report.Error (173, true_expr.Location,
4693 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4694 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
4700 bool is_false = c.IsDefaultValue;
4703 // Don't issue the warning for constant expressions
4705 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
4706 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location,
4707 "Unreachable expression code detected");
4710 return ReducedExpression.Create (
4711 is_false ? false_expr : true_expr, this,
4712 false_expr is Constant && true_expr is Constant).Resolve (ec);
4718 public override void Emit (EmitContext ec)
4720 Label false_target = ec.DefineLabel ();
4721 Label end_target = ec.DefineLabel ();
4723 expr.EmitBranchable (ec, false_target, false);
4724 true_expr.Emit (ec);
4727 // Verifier doesn't support interface merging. When there are two types on
4728 // the stack without common type hint and the common type is an interface.
4729 // Use temporary local to give verifier hint on what type to unify the stack
4731 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
4732 var temp = ec.GetTemporaryLocal (type);
4733 ec.Emit (OpCodes.Stloc, temp);
4734 ec.Emit (OpCodes.Ldloc, temp);
4735 ec.FreeTemporaryLocal (temp, type);
4738 ec.Emit (OpCodes.Br, end_target);
4739 ec.MarkLabel (false_target);
4740 false_expr.Emit (ec);
4741 ec.MarkLabel (end_target);
4744 protected override void CloneTo (CloneContext clonectx, Expression t)
4746 Conditional target = (Conditional) t;
4748 target.expr = expr.Clone (clonectx);
4749 target.true_expr = true_expr.Clone (clonectx);
4750 target.false_expr = false_expr.Clone (clonectx);
4754 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
4756 LocalTemporary temp;
4759 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4760 public abstract void SetHasAddressTaken ();
4761 public abstract void VerifyAssigned (ResolveContext rc);
4763 public abstract bool IsLockedByStatement { get; set; }
4765 public abstract bool IsFixed { get; }
4766 public abstract bool IsRef { get; }
4767 public abstract string Name { get; }
4770 // Variable IL data, it has to be protected to encapsulate hoisted variables
4772 protected abstract ILocalVariable Variable { get; }
4775 // Variable flow-analysis data
4777 public abstract VariableInfo VariableInfo { get; }
4780 public virtual void AddressOf (EmitContext ec, AddressOp mode)
4782 HoistedVariable hv = GetHoistedVariable (ec);
4784 hv.AddressOf (ec, mode);
4788 Variable.EmitAddressOf (ec);
4791 public override bool ContainsEmitWithAwait ()
4796 public override Expression CreateExpressionTree (ResolveContext ec)
4798 HoistedVariable hv = GetHoistedVariable (ec);
4800 return hv.CreateExpressionTree ();
4802 Arguments arg = new Arguments (1);
4803 arg.Add (new Argument (this));
4804 return CreateExpressionFactoryCall (ec, "Constant", arg);
4807 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
4809 if (IsLockedByStatement) {
4810 rc.Report.Warning (728, 2, loc,
4811 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
4818 public override void Emit (EmitContext ec)
4823 public override void EmitSideEffect (EmitContext ec)
4829 // This method is used by parameters that are references, that are
4830 // being passed as references: we only want to pass the pointer (that
4831 // is already stored in the parameter, not the address of the pointer,
4832 // and not the value of the variable).
4834 public void EmitLoad (EmitContext ec)
4839 public void Emit (EmitContext ec, bool leave_copy)
4841 HoistedVariable hv = GetHoistedVariable (ec);
4843 hv.Emit (ec, leave_copy);
4851 // If we are a reference, we loaded on the stack a pointer
4852 // Now lets load the real value
4854 ec.EmitLoadFromPtr (type);
4858 ec.Emit (OpCodes.Dup);
4861 temp = new LocalTemporary (Type);
4867 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4868 bool prepare_for_load)
4870 HoistedVariable hv = GetHoistedVariable (ec);
4872 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4876 New n_source = source as New;
4877 if (n_source != null) {
4878 if (!n_source.Emit (ec, this)) {
4882 ec.EmitLoadFromPtr (type);
4894 ec.Emit (OpCodes.Dup);
4896 temp = new LocalTemporary (Type);
4902 ec.EmitStoreFromPtr (type);
4904 Variable.EmitAssign (ec);
4912 public override Expression EmitToField (EmitContext ec)
4914 HoistedVariable hv = GetHoistedVariable (ec);
4916 return hv.EmitToField (ec);
4919 return base.EmitToField (ec);
4922 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4924 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4927 public HoistedVariable GetHoistedVariable (EmitContext ec)
4929 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4932 public override string GetSignatureForError ()
4937 public bool IsHoisted {
4938 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4943 // Resolved reference to a local variable
4945 public class LocalVariableReference : VariableReference
4947 public LocalVariable local_info;
4949 public LocalVariableReference (LocalVariable li, Location l)
4951 this.local_info = li;
4955 public override VariableInfo VariableInfo {
4956 get { return local_info.VariableInfo; }
4959 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4961 return local_info.HoistedVariant;
4967 // A local variable is always fixed
4969 public override bool IsFixed {
4975 public override bool IsLockedByStatement {
4977 return local_info.IsLocked;
4980 local_info.IsLocked = value;
4984 public override bool IsRef {
4985 get { return false; }
4988 public override string Name {
4989 get { return local_info.Name; }
4994 public override void VerifyAssigned (ResolveContext rc)
4996 VariableInfo variable_info = local_info.VariableInfo;
4997 if (variable_info == null)
5000 if (variable_info.IsAssigned (rc))
5003 rc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
5004 variable_info.SetAssigned (rc);
5007 public override void SetHasAddressTaken ()
5009 local_info.SetHasAddressTaken ();
5012 void DoResolveBase (ResolveContext ec)
5015 // If we are referencing a variable from the external block
5016 // flag it for capturing
5018 if (ec.MustCaptureVariable (local_info)) {
5019 if (local_info.AddressTaken) {
5020 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5021 } else if (local_info.IsFixed) {
5022 ec.Report.Error (1764, loc,
5023 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
5024 GetSignatureForError ());
5027 if (ec.IsVariableCapturingRequired) {
5028 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
5029 storey.CaptureLocalVariable (ec, local_info);
5033 eclass = ExprClass.Variable;
5034 type = local_info.Type;
5037 protected override Expression DoResolve (ResolveContext ec)
5039 local_info.SetIsUsed ();
5041 VerifyAssigned (ec);
5047 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5050 // Don't be too pedantic when variable is used as out param or for some broken code
5051 // which uses property/indexer access to run some initialization
5053 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5054 local_info.SetIsUsed ();
5056 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5059 if (rhs == EmptyExpression.OutAccess) {
5060 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5061 } else if (rhs == EmptyExpression.LValueMemberAccess) {
5062 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
5063 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5064 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5065 } else if (rhs == EmptyExpression.UnaryAddress) {
5066 code = 459; msg = "Cannot take the address of {1} `{0}'";
5068 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5070 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5071 } else if (VariableInfo != null) {
5072 VariableInfo.SetAssigned (ec);
5075 if (eclass == ExprClass.Unresolved)
5078 return base.DoResolveLValue (ec, rhs);
5081 public override int GetHashCode ()
5083 return local_info.GetHashCode ();
5086 public override bool Equals (object obj)
5088 LocalVariableReference lvr = obj as LocalVariableReference;
5092 return local_info == lvr.local_info;
5095 protected override ILocalVariable Variable {
5096 get { return local_info; }
5099 public override string ToString ()
5101 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5104 protected override void CloneTo (CloneContext clonectx, Expression t)
5111 /// This represents a reference to a parameter in the intermediate
5114 public class ParameterReference : VariableReference
5116 protected ParametersBlock.ParameterInfo pi;
5118 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5126 public override bool IsLockedByStatement {
5131 pi.IsLocked = value;
5135 public override bool IsRef {
5136 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5139 bool HasOutModifier {
5140 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5143 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5145 return pi.Parameter.HoistedVariant;
5149 // A ref or out parameter is classified as a moveable variable, even
5150 // if the argument given for the parameter is a fixed variable
5152 public override bool IsFixed {
5153 get { return !IsRef; }
5156 public override string Name {
5157 get { return Parameter.Name; }
5160 public Parameter Parameter {
5161 get { return pi.Parameter; }
5164 public override VariableInfo VariableInfo {
5165 get { return pi.VariableInfo; }
5168 protected override ILocalVariable Variable {
5169 get { return Parameter; }
5174 public override void AddressOf (EmitContext ec, AddressOp mode)
5177 // ParameterReferences might already be a reference
5184 base.AddressOf (ec, mode);
5187 public override void SetHasAddressTaken ()
5189 Parameter.HasAddressTaken = true;
5192 void SetAssigned (ResolveContext ec)
5194 if (Parameter.HoistedVariant != null)
5195 Parameter.HoistedVariant.IsAssigned = true;
5197 if (HasOutModifier && ec.DoFlowAnalysis)
5198 ec.CurrentBranching.SetAssigned (VariableInfo);
5201 bool DoResolveBase (ResolveContext ec)
5203 if (eclass != ExprClass.Unresolved)
5206 type = pi.ParameterType;
5207 eclass = ExprClass.Variable;
5210 // If we are referencing a parameter from the external block
5211 // flag it for capturing
5213 if (ec.MustCaptureVariable (pi)) {
5214 if (Parameter.HasAddressTaken)
5215 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5218 ec.Report.Error (1628, loc,
5219 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5220 Name, ec.CurrentAnonymousMethod.ContainerType);
5223 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5224 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5225 storey.CaptureParameter (ec, pi, this);
5232 public override int GetHashCode ()
5234 return Name.GetHashCode ();
5237 public override bool Equals (object obj)
5239 ParameterReference pr = obj as ParameterReference;
5243 return Name == pr.Name;
5246 protected override void CloneTo (CloneContext clonectx, Expression target)
5252 public override Expression CreateExpressionTree (ResolveContext ec)
5254 HoistedVariable hv = GetHoistedVariable (ec);
5256 return hv.CreateExpressionTree ();
5258 return Parameter.ExpressionTreeVariableReference ();
5262 // Notice that for ref/out parameters, the type exposed is not the
5263 // same type exposed externally.
5266 // externally we expose "int&"
5267 // here we expose "int".
5269 // We record this in "is_ref". This means that the type system can treat
5270 // the type as it is expected, but when we generate the code, we generate
5271 // the alternate kind of code.
5273 protected override Expression DoResolve (ResolveContext ec)
5275 if (!DoResolveBase (ec))
5278 VerifyAssigned (ec);
5282 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5284 if (!DoResolveBase (ec))
5288 return base.DoResolveLValue (ec, right_side);
5291 public override void VerifyAssigned (ResolveContext rc)
5293 // HACK: Variables are not captured in probing mode
5294 if (rc.IsInProbingMode)
5297 if (HasOutModifier && !VariableInfo.IsAssigned (rc)) {
5298 rc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
5304 /// Invocation of methods or delegates.
5306 public class Invocation : ExpressionStatement
5308 protected Arguments arguments;
5309 protected Expression expr;
5310 protected MethodGroupExpr mg;
5312 public Invocation (Expression expr, Arguments arguments)
5315 this.arguments = arguments;
5317 loc = expr.Location;
5322 public Arguments Arguments {
5328 public Expression Exp {
5334 public MethodGroupExpr MethodGroup {
5340 public override Location StartLocation {
5342 return expr.StartLocation;
5348 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
5350 if (MethodGroup == null)
5353 var candidate = MethodGroup.BestCandidate;
5354 if (candidate == null || !(candidate.IsStatic || Exp is This))
5357 var args_count = arguments == null ? 0 : arguments.Count;
5358 if (args_count != body.Parameters.Count)
5361 var lambda_parameters = body.Block.Parameters.FixedParameters;
5362 for (int i = 0; i < args_count; ++i) {
5363 var pr = arguments[i].Expr as ParameterReference;
5367 if (lambda_parameters[i] != pr.Parameter)
5370 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
5374 var emg = MethodGroup as ExtensionMethodGroupExpr;
5376 return MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
5382 protected override void CloneTo (CloneContext clonectx, Expression t)
5384 Invocation target = (Invocation) t;
5386 if (arguments != null)
5387 target.arguments = arguments.Clone (clonectx);
5389 target.expr = expr.Clone (clonectx);
5392 public override bool ContainsEmitWithAwait ()
5394 if (arguments != null && arguments.ContainsEmitWithAwait ())
5397 return mg.ContainsEmitWithAwait ();
5400 public override Expression CreateExpressionTree (ResolveContext ec)
5402 Expression instance = mg.IsInstance ?
5403 mg.InstanceExpression.CreateExpressionTree (ec) :
5404 new NullLiteral (loc);
5406 var args = Arguments.CreateForExpressionTree (ec, arguments,
5408 mg.CreateExpressionTree (ec));
5410 return CreateExpressionFactoryCall (ec, "Call", args);
5413 protected override Expression DoResolve (ResolveContext ec)
5415 Expression member_expr;
5416 var atn = expr as ATypeNameExpression;
5418 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
5419 if (member_expr != null)
5420 member_expr = member_expr.Resolve (ec);
5422 member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5425 if (member_expr == null)
5429 // Next, evaluate all the expressions in the argument list
5431 bool dynamic_arg = false;
5432 if (arguments != null)
5433 arguments.Resolve (ec, out dynamic_arg);
5435 TypeSpec expr_type = member_expr.Type;
5436 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5437 return DoResolveDynamic (ec, member_expr);
5439 mg = member_expr as MethodGroupExpr;
5440 Expression invoke = null;
5443 if (expr_type != null && expr_type.IsDelegate) {
5444 invoke = new DelegateInvocation (member_expr, arguments, loc);
5445 invoke = invoke.Resolve (ec);
5446 if (invoke == null || !dynamic_arg)
5449 if (member_expr is RuntimeValueExpression) {
5450 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
5451 member_expr.Type.GetSignatureForError ()); ;
5455 MemberExpr me = member_expr as MemberExpr;
5457 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5461 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
5462 member_expr.GetSignatureForError ());
5467 if (invoke == null) {
5468 mg = DoResolveOverload (ec);
5474 return DoResolveDynamic (ec, member_expr);
5476 var method = mg.BestCandidate;
5477 type = mg.BestCandidateReturnType;
5479 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
5481 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5483 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5487 IsSpecialMethodInvocation (ec, method, loc);
5489 eclass = ExprClass.Value;
5493 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
5496 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
5498 args = dmb.Arguments;
5499 if (arguments != null)
5500 args.AddRange (arguments);
5501 } else if (mg == null) {
5502 if (arguments == null)
5503 args = new Arguments (1);
5507 args.Insert (0, new Argument (memberExpr));
5511 ec.Report.Error (1971, loc,
5512 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
5517 if (arguments == null)
5518 args = new Arguments (1);
5522 MemberAccess ma = expr as MemberAccess;
5524 var left_type = ma.LeftExpression as TypeExpr;
5525 if (left_type != null) {
5526 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5529 // Any value type has to be pass as by-ref to get back the same
5530 // instance on which the member was called
5532 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
5533 Argument.AType.Ref : Argument.AType.None;
5534 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
5536 } else { // is SimpleName
5538 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5540 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5545 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5548 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5550 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
5553 public override string GetSignatureForError ()
5555 return mg.GetSignatureForError ();
5559 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
5560 // or the type dynamic, then the member is invocable
5562 public static bool IsMemberInvocable (MemberSpec member)
5564 switch (member.Kind) {
5565 case MemberKind.Event:
5567 case MemberKind.Field:
5568 case MemberKind.Property:
5569 var m = member as IInterfaceMemberSpec;
5570 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
5576 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
5578 if (!method.IsReservedMethod)
5581 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
5584 ec.Report.SymbolRelatedToPreviousError (method);
5585 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5586 method.GetSignatureForError ());
5591 public override void Emit (EmitContext ec)
5593 mg.EmitCall (ec, arguments);
5596 public override void EmitStatement (EmitContext ec)
5601 // Pop the return value if there is one
5603 if (type.Kind != MemberKind.Void)
5604 ec.Emit (OpCodes.Pop);
5607 public override SLE.Expression MakeExpression (BuilderContext ctx)
5609 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
5612 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
5615 throw new NotSupportedException ();
5617 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5618 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
5622 public override object Accept (StructuralVisitor visitor)
5624 return visitor.Visit (this);
5629 // Implements simple new expression
5631 public class New : ExpressionStatement, IMemoryLocation
5633 protected Arguments arguments;
5636 // During bootstrap, it contains the RequestedType,
5637 // but if `type' is not null, it *might* contain a NewDelegate
5638 // (because of field multi-initialization)
5640 protected Expression RequestedType;
5642 protected MethodSpec method;
5644 public New (Expression requested_type, Arguments arguments, Location l)
5646 RequestedType = requested_type;
5647 this.arguments = arguments;
5652 public Arguments Arguments {
5659 // Returns true for resolved `new S()'
5661 public bool IsDefaultStruct {
5663 return arguments == null && type.IsStruct && GetType () == typeof (New);
5667 public Expression TypeExpression {
5669 return RequestedType;
5676 /// Converts complex core type syntax like 'new int ()' to simple constant
5678 public static Constant Constantify (TypeSpec t, Location loc)
5680 switch (t.BuiltinType) {
5681 case BuiltinTypeSpec.Type.Int:
5682 return new IntConstant (t, 0, loc);
5683 case BuiltinTypeSpec.Type.UInt:
5684 return new UIntConstant (t, 0, loc);
5685 case BuiltinTypeSpec.Type.Long:
5686 return new LongConstant (t, 0, loc);
5687 case BuiltinTypeSpec.Type.ULong:
5688 return new ULongConstant (t, 0, loc);
5689 case BuiltinTypeSpec.Type.Float:
5690 return new FloatConstant (t, 0, loc);
5691 case BuiltinTypeSpec.Type.Double:
5692 return new DoubleConstant (t, 0, loc);
5693 case BuiltinTypeSpec.Type.Short:
5694 return new ShortConstant (t, 0, loc);
5695 case BuiltinTypeSpec.Type.UShort:
5696 return new UShortConstant (t, 0, loc);
5697 case BuiltinTypeSpec.Type.SByte:
5698 return new SByteConstant (t, 0, loc);
5699 case BuiltinTypeSpec.Type.Byte:
5700 return new ByteConstant (t, 0, loc);
5701 case BuiltinTypeSpec.Type.Char:
5702 return new CharConstant (t, '\0', loc);
5703 case BuiltinTypeSpec.Type.Bool:
5704 return new BoolConstant (t, false, loc);
5705 case BuiltinTypeSpec.Type.Decimal:
5706 return new DecimalConstant (t, 0, loc);
5710 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
5712 if (t.IsNullableType)
5713 return Nullable.LiftedNull.Create (t, loc);
5718 public override bool ContainsEmitWithAwait ()
5720 return arguments != null && arguments.ContainsEmitWithAwait ();
5724 // Checks whether the type is an interface that has the
5725 // [ComImport, CoClass] attributes and must be treated
5728 public Expression CheckComImport (ResolveContext ec)
5730 if (!type.IsInterface)
5734 // Turn the call into:
5735 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5737 var real_class = type.MemberDefinition.GetAttributeCoClass ();
5738 if (real_class == null)
5741 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
5742 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5743 return cast.Resolve (ec);
5746 public override Expression CreateExpressionTree (ResolveContext ec)
5749 if (method == null) {
5750 args = new Arguments (1);
5751 args.Add (new Argument (new TypeOf (type, loc)));
5753 args = Arguments.CreateForExpressionTree (ec,
5754 arguments, new TypeOfMethod (method, loc));
5757 return CreateExpressionFactoryCall (ec, "New", args);
5760 protected override Expression DoResolve (ResolveContext ec)
5762 type = RequestedType.ResolveAsType (ec);
5766 eclass = ExprClass.Value;
5768 if (type.IsPointer) {
5769 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5770 type.GetSignatureForError ());
5774 if (arguments == null) {
5775 Constant c = Constantify (type, RequestedType.Location);
5777 return ReducedExpression.Create (c, this);
5780 if (type.IsDelegate) {
5781 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
5784 var tparam = type as TypeParameterSpec;
5785 if (tparam != null) {
5787 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
5788 // where type parameter constraint is inflated to struct
5790 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
5791 ec.Report.Error (304, loc,
5792 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
5793 type.GetSignatureForError ());
5796 if ((arguments != null) && (arguments.Count != 0)) {
5797 ec.Report.Error (417, loc,
5798 "`{0}': cannot provide arguments when creating an instance of a variable type",
5799 type.GetSignatureForError ());
5805 if (type.IsStatic) {
5806 ec.Report.SymbolRelatedToPreviousError (type);
5807 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
5811 if (type.IsInterface || type.IsAbstract){
5812 if (!TypeManager.IsGenericType (type)) {
5813 RequestedType = CheckComImport (ec);
5814 if (RequestedType != null)
5815 return RequestedType;
5818 ec.Report.SymbolRelatedToPreviousError (type);
5819 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
5824 // Any struct always defines parameterless constructor
5826 if (type.IsStruct && arguments == null)
5830 if (arguments != null) {
5831 arguments.Resolve (ec, out dynamic);
5836 method = ConstructorLookup (ec, type, ref arguments, loc);
5839 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5840 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
5846 bool DoEmitTypeParameter (EmitContext ec)
5848 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
5852 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
5853 var tparam = (TypeParameterSpec) type;
5855 if (tparam.IsReferenceType) {
5856 ec.Emit (OpCodes.Call, ctor_factory);
5860 // Allow DoEmit() to be called multiple times.
5861 // We need to create a new LocalTemporary each time since
5862 // you can't share LocalBuilders among ILGeneators.
5863 LocalTemporary temp = new LocalTemporary (type);
5865 Label label_activator = ec.DefineLabel ();
5866 Label label_end = ec.DefineLabel ();
5868 temp.AddressOf (ec, AddressOp.Store);
5869 ec.Emit (OpCodes.Initobj, type);
5872 ec.Emit (OpCodes.Box, type);
5873 ec.Emit (OpCodes.Brfalse, label_activator);
5875 temp.AddressOf (ec, AddressOp.Store);
5876 ec.Emit (OpCodes.Initobj, type);
5879 ec.Emit (OpCodes.Br_S, label_end);
5881 ec.MarkLabel (label_activator);
5883 ec.Emit (OpCodes.Call, ctor_factory);
5884 ec.MarkLabel (label_end);
5889 // This Emit can be invoked in two contexts:
5890 // * As a mechanism that will leave a value on the stack (new object)
5891 // * As one that wont (init struct)
5893 // If we are dealing with a ValueType, we have a few
5894 // situations to deal with:
5896 // * The target is a ValueType, and we have been provided
5897 // the instance (this is easy, we are being assigned).
5899 // * The target of New is being passed as an argument,
5900 // to a boxing operation or a function that takes a
5903 // In this case, we need to create a temporary variable
5904 // that is the argument of New.
5906 // Returns whether a value is left on the stack
5908 // *** Implementation note ***
5910 // To benefit from this optimization, each assignable expression
5911 // has to manually cast to New and call this Emit.
5913 // TODO: It's worth to implement it for arrays and fields
5915 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5917 bool is_value_type = TypeSpec.IsValueType (type);
5918 VariableReference vr = target as VariableReference;
5920 if (target != null && is_value_type && (vr != null || method == null)) {
5921 target.AddressOf (ec, AddressOp.Store);
5922 } else if (vr != null && vr.IsRef) {
5926 if (arguments != null) {
5927 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
5928 arguments = arguments.Emit (ec, false, true);
5930 arguments.Emit (ec);
5933 if (is_value_type) {
5934 if (method == null) {
5935 ec.Emit (OpCodes.Initobj, type);
5940 ec.Emit (OpCodes.Call, method);
5945 if (type is TypeParameterSpec)
5946 return DoEmitTypeParameter (ec);
5948 ec.Emit (OpCodes.Newobj, method);
5952 public override void Emit (EmitContext ec)
5954 LocalTemporary v = null;
5955 if (method == null && TypeSpec.IsValueType (type)) {
5956 // TODO: Use temporary variable from pool
5957 v = new LocalTemporary (type);
5964 public override void EmitStatement (EmitContext ec)
5966 LocalTemporary v = null;
5967 if (method == null && TypeSpec.IsValueType (type)) {
5968 // TODO: Use temporary variable from pool
5969 v = new LocalTemporary (type);
5973 ec.Emit (OpCodes.Pop);
5976 public void AddressOf (EmitContext ec, AddressOp mode)
5978 EmitAddressOf (ec, mode);
5981 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5983 LocalTemporary value_target = new LocalTemporary (type);
5985 if (type is TypeParameterSpec) {
5986 DoEmitTypeParameter (ec);
5987 value_target.Store (ec);
5988 value_target.AddressOf (ec, mode);
5989 return value_target;
5992 value_target.AddressOf (ec, AddressOp.Store);
5994 if (method == null) {
5995 ec.Emit (OpCodes.Initobj, type);
5997 if (arguments != null)
5998 arguments.Emit (ec);
6000 ec.Emit (OpCodes.Call, method);
6003 value_target.AddressOf (ec, mode);
6004 return value_target;
6007 protected override void CloneTo (CloneContext clonectx, Expression t)
6009 New target = (New) t;
6011 target.RequestedType = RequestedType.Clone (clonectx);
6012 if (arguments != null){
6013 target.arguments = arguments.Clone (clonectx);
6017 public override SLE.Expression MakeExpression (BuilderContext ctx)
6020 return base.MakeExpression (ctx);
6022 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
6026 public override object Accept (StructuralVisitor visitor)
6028 return visitor.Visit (this);
6033 // Array initializer expression, the expression is allowed in
6034 // variable or field initialization only which makes it tricky as
6035 // the type has to be infered based on the context either from field
6036 // type or variable type (think of multiple declarators)
6038 public class ArrayInitializer : Expression
6040 List<Expression> elements;
6041 BlockVariable variable;
6043 public ArrayInitializer (List<Expression> init, Location loc)
6049 public ArrayInitializer (int count, Location loc)
6050 : this (new List<Expression> (count), loc)
6054 public ArrayInitializer (Location loc)
6062 get { return elements.Count; }
6065 public List<Expression> Elements {
6071 public Expression this [int index] {
6073 return elements [index];
6077 public BlockVariable VariableDeclaration {
6088 public void Add (Expression expr)
6090 elements.Add (expr);
6093 public override bool ContainsEmitWithAwait ()
6095 throw new NotSupportedException ();
6098 public override Expression CreateExpressionTree (ResolveContext ec)
6100 throw new NotSupportedException ("ET");
6103 protected override void CloneTo (CloneContext clonectx, Expression t)
6105 var target = (ArrayInitializer) t;
6107 target.elements = new List<Expression> (elements.Count);
6108 foreach (var element in elements)
6109 target.elements.Add (element.Clone (clonectx));
6112 protected override Expression DoResolve (ResolveContext rc)
6114 var current_field = rc.CurrentMemberDefinition as FieldBase;
6115 TypeExpression type;
6116 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6117 type = new TypeExpression (current_field.MemberType, current_field.Location);
6118 } else if (variable != null) {
6119 if (variable.TypeExpression is VarExpr) {
6120 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6121 return EmptyExpression.Null;
6124 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6126 throw new NotImplementedException ("Unexpected array initializer context");
6129 return new ArrayCreation (type, this).Resolve (rc);
6132 public override void Emit (EmitContext ec)
6134 throw new InternalErrorException ("Missing Resolve call");
6137 public override object Accept (StructuralVisitor visitor)
6139 return visitor.Visit (this);
6144 /// 14.5.10.2: Represents an array creation expression.
6148 /// There are two possible scenarios here: one is an array creation
6149 /// expression that specifies the dimensions and optionally the
6150 /// initialization data and the other which does not need dimensions
6151 /// specified but where initialization data is mandatory.
6153 public class ArrayCreation : Expression
6155 FullNamedExpression requested_base_type;
6156 ArrayInitializer initializers;
6159 // The list of Argument types.
6160 // This is used to construct the `newarray' or constructor signature
6162 protected List<Expression> arguments;
6164 protected TypeSpec array_element_type;
6165 int num_arguments = 0;
6166 protected int dimensions;
6167 protected readonly ComposedTypeSpecifier rank;
6168 Expression first_emit;
6169 LocalTemporary first_emit_temp;
6171 protected List<Expression> array_data;
6173 Dictionary<int, int> bounds;
6176 // The number of constants in array initializers
6177 int const_initializers_count;
6178 bool only_constant_initializers;
6180 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6181 : this (requested_base_type, rank, initializers, l)
6183 arguments = new List<Expression> (exprs);
6184 num_arguments = arguments.Count;
6188 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6190 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6192 this.requested_base_type = requested_base_type;
6194 this.initializers = initializers;
6198 num_arguments = rank.Dimension;
6202 // For compiler generated single dimensional arrays only
6204 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6205 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6210 // For expressions like int[] foo = { 1, 2, 3 };
6212 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6213 : this (requested_base_type, null, initializers, initializers.Location)
6217 public ComposedTypeSpecifier Rank {
6223 public FullNamedExpression TypeExpression {
6225 return this.requested_base_type;
6229 public ArrayInitializer Initializers {
6231 return this.initializers;
6235 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6237 if (initializers != null && bounds == null) {
6239 // We use this to store all the data values in the order in which we
6240 // will need to store them in the byte blob later
6242 array_data = new List<Expression> (probe.Count);
6243 bounds = new Dictionary<int, int> ();
6246 if (specified_dims) {
6247 Expression a = arguments [idx];
6252 a = ConvertExpressionToArrayIndex (ec, a);
6258 if (initializers != null) {
6259 Constant c = a as Constant;
6260 if (c == null && a is ArrayIndexCast)
6261 c = ((ArrayIndexCast) a).Child as Constant;
6264 ec.Report.Error (150, a.Location, "A constant value is expected");
6270 value = System.Convert.ToInt32 (c.GetValue ());
6272 ec.Report.Error (150, a.Location, "A constant value is expected");
6276 // TODO: probe.Count does not fit ulong in
6277 if (value != probe.Count) {
6278 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6282 bounds[idx] = value;
6286 if (initializers == null)
6289 for (int i = 0; i < probe.Count; ++i) {
6291 if (o is ArrayInitializer) {
6292 var sub_probe = o as ArrayInitializer;
6293 if (idx + 1 >= dimensions){
6294 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6298 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
6299 if (!bounds.ContainsKey(idx + 1))
6300 bounds[idx + 1] = sub_probe.Count;
6302 if (bounds[idx + 1] != sub_probe.Count) {
6303 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
6307 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6310 } else if (child_bounds > 1) {
6311 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6313 Expression element = ResolveArrayElement (ec, o);
6314 if (element == null)
6317 // Initializers with the default values can be ignored
6318 Constant c = element as Constant;
6320 if (!c.IsDefaultInitializer (array_element_type)) {
6321 ++const_initializers_count;
6324 only_constant_initializers = false;
6327 array_data.Add (element);
6334 public override bool ContainsEmitWithAwait ()
6336 foreach (var arg in arguments) {
6337 if (arg.ContainsEmitWithAwait ())
6341 return InitializersContainAwait ();
6344 public override Expression CreateExpressionTree (ResolveContext ec)
6348 if (array_data == null) {
6349 args = new Arguments (arguments.Count + 1);
6350 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6351 foreach (Expression a in arguments)
6352 args.Add (new Argument (a.CreateExpressionTree (ec)));
6354 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6357 if (dimensions > 1) {
6358 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6362 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6363 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6364 if (array_data != null) {
6365 for (int i = 0; i < array_data.Count; ++i) {
6366 Expression e = array_data [i];
6367 args.Add (new Argument (e.CreateExpressionTree (ec)));
6371 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6374 void UpdateIndices (ResolveContext rc)
6377 for (var probe = initializers; probe != null;) {
6378 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
6380 bounds[i++] = probe.Count;
6382 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
6383 probe = (ArrayInitializer) probe[0];
6384 } else if (dimensions > i) {
6392 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
6394 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
6397 bool InitializersContainAwait ()
6399 if (array_data == null)
6402 foreach (var expr in array_data) {
6403 if (expr.ContainsEmitWithAwait ())
6410 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
6412 element = element.Resolve (ec);
6413 if (element == null)
6416 if (element is CompoundAssign.TargetExpression) {
6417 if (first_emit != null)
6418 throw new InternalErrorException ("Can only handle one mutator at a time");
6419 first_emit = element;
6420 element = first_emit_temp = new LocalTemporary (element.Type);
6423 return Convert.ImplicitConversionRequired (
6424 ec, element, array_element_type, loc);
6427 protected bool ResolveInitializers (ResolveContext ec)
6430 only_constant_initializers = true;
6433 if (arguments != null) {
6435 for (int i = 0; i < arguments.Count; ++i) {
6436 res &= CheckIndices (ec, initializers, i, true, dimensions);
6437 if (initializers != null)
6444 arguments = new List<Expression> ();
6446 if (!CheckIndices (ec, initializers, 0, false, dimensions))
6455 // Resolved the type of the array
6457 bool ResolveArrayType (ResolveContext ec)
6462 FullNamedExpression array_type_expr;
6463 if (num_arguments > 0) {
6464 array_type_expr = new ComposedCast (requested_base_type, rank);
6466 array_type_expr = requested_base_type;
6469 type = array_type_expr.ResolveAsType (ec);
6470 if (array_type_expr == null)
6473 var ac = type as ArrayContainer;
6475 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6479 array_element_type = ac.Element;
6480 dimensions = ac.Rank;
6485 protected override Expression DoResolve (ResolveContext ec)
6490 if (!ResolveArrayType (ec))
6494 // validate the initializers and fill in any missing bits
6496 if (!ResolveInitializers (ec))
6499 eclass = ExprClass.Value;
6503 byte [] MakeByteBlob ()
6508 int count = array_data.Count;
6510 TypeSpec element_type = array_element_type;
6511 if (element_type.IsEnum)
6512 element_type = EnumSpec.GetUnderlyingType (element_type);
6514 factor = BuiltinTypeSpec.GetSize (element_type);
6516 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6518 data = new byte [(count * factor + 3) & ~3];
6521 for (int i = 0; i < count; ++i) {
6522 var c = array_data[i] as Constant;
6528 object v = c.GetValue ();
6530 switch (element_type.BuiltinType) {
6531 case BuiltinTypeSpec.Type.Long:
6532 long lval = (long) v;
6534 for (int j = 0; j < factor; ++j) {
6535 data[idx + j] = (byte) (lval & 0xFF);
6539 case BuiltinTypeSpec.Type.ULong:
6540 ulong ulval = (ulong) v;
6542 for (int j = 0; j < factor; ++j) {
6543 data[idx + j] = (byte) (ulval & 0xFF);
6544 ulval = (ulval >> 8);
6547 case BuiltinTypeSpec.Type.Float:
6548 var fval = SingleConverter.SingleToInt32Bits((float) v);
6550 data[idx] = (byte) (fval & 0xff);
6551 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
6552 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
6553 data[idx + 3] = (byte) (fval >> 24);
6555 case BuiltinTypeSpec.Type.Double:
6556 element = BitConverter.GetBytes ((double) v);
6558 for (int j = 0; j < factor; ++j)
6559 data[idx + j] = element[j];
6561 // FIXME: Handle the ARM float format.
6562 if (!BitConverter.IsLittleEndian)
6563 System.Array.Reverse (data, idx, 8);
6565 case BuiltinTypeSpec.Type.Char:
6566 int chval = (int) ((char) v);
6568 data[idx] = (byte) (chval & 0xff);
6569 data[idx + 1] = (byte) (chval >> 8);
6571 case BuiltinTypeSpec.Type.Short:
6572 int sval = (int) ((short) v);
6574 data[idx] = (byte) (sval & 0xff);
6575 data[idx + 1] = (byte) (sval >> 8);
6577 case BuiltinTypeSpec.Type.UShort:
6578 int usval = (int) ((ushort) v);
6580 data[idx] = (byte) (usval & 0xff);
6581 data[idx + 1] = (byte) (usval >> 8);
6583 case BuiltinTypeSpec.Type.Int:
6586 data[idx] = (byte) (val & 0xff);
6587 data[idx + 1] = (byte) ((val >> 8) & 0xff);
6588 data[idx + 2] = (byte) ((val >> 16) & 0xff);
6589 data[idx + 3] = (byte) (val >> 24);
6591 case BuiltinTypeSpec.Type.UInt:
6592 uint uval = (uint) v;
6594 data[idx] = (byte) (uval & 0xff);
6595 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
6596 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
6597 data[idx + 3] = (byte) (uval >> 24);
6599 case BuiltinTypeSpec.Type.SByte:
6600 data[idx] = (byte) (sbyte) v;
6602 case BuiltinTypeSpec.Type.Byte:
6603 data[idx] = (byte) v;
6605 case BuiltinTypeSpec.Type.Bool:
6606 data[idx] = (byte) ((bool) v ? 1 : 0);
6608 case BuiltinTypeSpec.Type.Decimal:
6609 int[] bits = Decimal.GetBits ((decimal) v);
6612 // FIXME: For some reason, this doesn't work on the MS runtime.
6613 int[] nbits = new int[4];
6619 for (int j = 0; j < 4; j++) {
6620 data[p++] = (byte) (nbits[j] & 0xff);
6621 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
6622 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
6623 data[p++] = (byte) (nbits[j] >> 24);
6627 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6636 #if NET_4_0 || MONODROID
6637 public override SLE.Expression MakeExpression (BuilderContext ctx)
6640 return base.MakeExpression (ctx);
6642 var initializers = new SLE.Expression [array_data.Count];
6643 for (var i = 0; i < initializers.Length; i++) {
6644 if (array_data [i] == null)
6645 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
6647 initializers [i] = array_data [i].MakeExpression (ctx);
6650 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
6656 // Emits the initializers for the array
6658 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
6660 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
6665 // First, the static data
6667 byte [] data = MakeByteBlob ();
6668 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
6670 if (stackArray == null) {
6671 ec.Emit (OpCodes.Dup);
6673 stackArray.Emit (ec);
6676 ec.Emit (OpCodes.Ldtoken, fb);
6677 ec.Emit (OpCodes.Call, m);
6682 // Emits pieces of the array that can not be computed at compile
6683 // time (variables and string locations).
6685 // This always expect the top value on the stack to be the array
6687 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
6689 int dims = bounds.Count;
6690 var current_pos = new int [dims];
6692 for (int i = 0; i < array_data.Count; i++){
6694 Expression e = array_data [i];
6695 var c = e as Constant;
6697 // Constant can be initialized via StaticInitializer
6698 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
6702 if (stackArray != null) {
6703 if (e.ContainsEmitWithAwait ()) {
6704 e = e.EmitToField (ec);
6707 stackArray.Emit (ec);
6709 ec.Emit (OpCodes.Dup);
6712 for (int idx = 0; idx < dims; idx++)
6713 ec.EmitInt (current_pos [idx]);
6716 // If we are dealing with a struct, get the
6717 // address of it, so we can store it.
6719 if (dims == 1 && etype.IsStruct) {
6720 switch (etype.BuiltinType) {
6721 case BuiltinTypeSpec.Type.Byte:
6722 case BuiltinTypeSpec.Type.SByte:
6723 case BuiltinTypeSpec.Type.Bool:
6724 case BuiltinTypeSpec.Type.Short:
6725 case BuiltinTypeSpec.Type.UShort:
6726 case BuiltinTypeSpec.Type.Char:
6727 case BuiltinTypeSpec.Type.Int:
6728 case BuiltinTypeSpec.Type.UInt:
6729 case BuiltinTypeSpec.Type.Long:
6730 case BuiltinTypeSpec.Type.ULong:
6731 case BuiltinTypeSpec.Type.Float:
6732 case BuiltinTypeSpec.Type.Double:
6735 ec.Emit (OpCodes.Ldelema, etype);
6742 ec.EmitArrayStore ((ArrayContainer) type);
6748 for (int j = dims - 1; j >= 0; j--){
6750 if (current_pos [j] < bounds [j])
6752 current_pos [j] = 0;
6757 public override void Emit (EmitContext ec)
6759 EmitToFieldSource (ec);
6762 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
6764 if (first_emit != null) {
6765 first_emit.Emit (ec);
6766 first_emit_temp.Store (ec);
6769 FieldExpr await_stack_field;
6770 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
6771 await_stack_field = ec.GetTemporaryField (type);
6774 await_stack_field = null;
6777 EmitExpressionsList (ec, arguments);
6779 ec.EmitArrayNew ((ArrayContainer) type);
6781 if (initializers == null)
6782 return await_stack_field;
6784 if (await_stack_field != null)
6785 await_stack_field.EmitAssignFromStack (ec);
6789 // Emit static initializer for arrays which contain more than 2 items and
6790 // the static initializer will initialize at least 25% of array values or there
6791 // is more than 10 items to be initialized
6793 // NOTE: const_initializers_count does not contain default constant values.
6795 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
6796 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
6797 EmitStaticInitializers (ec, await_stack_field);
6799 if (!only_constant_initializers)
6800 EmitDynamicInitializers (ec, false, await_stack_field);
6804 EmitDynamicInitializers (ec, true, await_stack_field);
6807 if (first_emit_temp != null)
6808 first_emit_temp.Release (ec);
6810 return await_stack_field;
6813 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
6815 // no multi dimensional or jagged arrays
6816 if (arguments.Count != 1 || array_element_type.IsArray) {
6817 base.EncodeAttributeValue (rc, enc, targetType);
6821 // No array covariance, except for array -> object
6822 if (type != targetType) {
6823 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
6824 base.EncodeAttributeValue (rc, enc, targetType);
6828 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
6829 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
6834 // Single dimensional array of 0 size
6835 if (array_data == null) {
6836 IntConstant ic = arguments[0] as IntConstant;
6837 if (ic == null || !ic.IsDefaultValue) {
6838 base.EncodeAttributeValue (rc, enc, targetType);
6846 enc.Encode (array_data.Count);
6847 foreach (var element in array_data) {
6848 element.EncodeAttributeValue (rc, enc, array_element_type);
6852 protected override void CloneTo (CloneContext clonectx, Expression t)
6854 ArrayCreation target = (ArrayCreation) t;
6856 if (requested_base_type != null)
6857 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6859 if (arguments != null){
6860 target.arguments = new List<Expression> (arguments.Count);
6861 foreach (Expression e in arguments)
6862 target.arguments.Add (e.Clone (clonectx));
6865 if (initializers != null)
6866 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
6869 public override object Accept (StructuralVisitor visitor)
6871 return visitor.Visit (this);
6876 // Represents an implicitly typed array epxression
6878 class ImplicitlyTypedArrayCreation : ArrayCreation
6880 TypeInferenceContext best_type_inference;
6882 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6883 : base (null, rank, initializers, loc)
6887 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
6888 : base (null, initializers, loc)
6892 protected override Expression DoResolve (ResolveContext ec)
6897 dimensions = rank.Dimension;
6899 best_type_inference = new TypeInferenceContext ();
6901 if (!ResolveInitializers (ec))
6904 best_type_inference.FixAllTypes (ec);
6905 array_element_type = best_type_inference.InferredTypeArguments[0];
6906 best_type_inference = null;
6908 if (array_element_type == null ||
6909 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
6910 arguments.Count != rank.Dimension) {
6911 ec.Report.Error (826, loc,
6912 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6917 // At this point we found common base type for all initializer elements
6918 // but we have to be sure that all static initializer elements are of
6921 UnifyInitializerElement (ec);
6923 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
6924 eclass = ExprClass.Value;
6929 // Converts static initializer only
6931 void UnifyInitializerElement (ResolveContext ec)
6933 for (int i = 0; i < array_data.Count; ++i) {
6934 Expression e = array_data[i];
6936 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6940 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6942 element = element.Resolve (ec);
6943 if (element != null)
6944 best_type_inference.AddCommonTypeBound (element.Type);
6950 sealed class CompilerGeneratedThis : This
6952 public CompilerGeneratedThis (TypeSpec type, Location loc)
6956 eclass = ExprClass.Variable;
6959 protected override Expression DoResolve (ResolveContext ec)
6964 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6971 /// Represents the `this' construct
6974 public class This : VariableReference
6976 sealed class ThisVariable : ILocalVariable
6978 public static readonly ILocalVariable Instance = new ThisVariable ();
6980 public void Emit (EmitContext ec)
6985 public void EmitAssign (EmitContext ec)
6987 throw new InvalidOperationException ();
6990 public void EmitAddressOf (EmitContext ec)
6996 VariableInfo variable_info;
6998 public This (Location loc)
7005 public override string Name {
7006 get { return "this"; }
7009 public override bool IsLockedByStatement {
7017 public override bool IsRef {
7018 get { return type.IsStruct; }
7021 public override bool IsSideEffectFree {
7027 protected override ILocalVariable Variable {
7028 get { return ThisVariable.Instance; }
7031 public override VariableInfo VariableInfo {
7032 get { return variable_info; }
7035 public override bool IsFixed {
7036 get { return false; }
7041 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
7044 // It's null for all cases when we don't need to check `this'
7045 // definitive assignment
7047 if (variable_info == null)
7050 if (rc.OmitStructFlowAnalysis)
7053 if (!variable_info.IsAssigned (rc)) {
7054 rc.Report.Error (188, loc,
7055 "The `this' object cannot be used before all of its fields are assigned to");
7059 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7061 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7062 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7063 } else if (ec.CurrentAnonymousMethod != null) {
7064 ec.Report.Error (1673, loc,
7065 "Anonymous methods inside structs cannot access instance members of `this'. " +
7066 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7068 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7072 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7077 AnonymousMethodStorey storey = ae.Storey;
7078 return storey != null ? storey.HoistedThis : null;
7081 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7083 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7086 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7089 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7095 public virtual void ResolveBase (ResolveContext ec)
7097 eclass = ExprClass.Variable;
7098 type = ec.CurrentType;
7100 if (!IsThisAvailable (ec, false)) {
7101 Error_ThisNotAvailable (ec);
7105 var block = ec.CurrentBlock;
7106 if (block != null) {
7107 var top = block.ParametersBlock.TopBlock;
7108 if (top.ThisVariable != null)
7109 variable_info = top.ThisVariable.VariableInfo;
7111 AnonymousExpression am = ec.CurrentAnonymousMethod;
7112 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7114 // Hoisted this is almost like hoisted variable but not exactly. When
7115 // there is no variable hoisted we can simply emit an instance method
7116 // without lifting this into a storey. Unfotunatelly this complicates
7117 // things in other cases because we don't know where this will be hoisted
7118 // until top-level block is fully resolved
7120 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7121 am.SetHasThisAccess ();
7126 protected override Expression DoResolve (ResolveContext ec)
7130 CheckStructThisDefiniteAssignment (ec);
7135 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7137 if (eclass == ExprClass.Unresolved)
7140 if (variable_info != null)
7141 variable_info.SetAssigned (ec);
7144 if (right_side == EmptyExpression.UnaryAddress)
7145 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7146 else if (right_side == EmptyExpression.OutAccess)
7147 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7149 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7155 public override int GetHashCode()
7157 throw new NotImplementedException ();
7160 public override bool Equals (object obj)
7162 This t = obj as This;
7169 protected override void CloneTo (CloneContext clonectx, Expression t)
7174 public override void SetHasAddressTaken ()
7179 public override void VerifyAssigned (ResolveContext rc)
7183 public override object Accept (StructuralVisitor visitor)
7185 return visitor.Visit (this);
7190 /// Represents the `__arglist' construct
7192 public class ArglistAccess : Expression
7194 public ArglistAccess (Location loc)
7199 protected override void CloneTo (CloneContext clonectx, Expression target)
7204 public override bool ContainsEmitWithAwait ()
7209 public override Expression CreateExpressionTree (ResolveContext ec)
7211 throw new NotSupportedException ("ET");
7214 protected override Expression DoResolve (ResolveContext ec)
7216 eclass = ExprClass.Variable;
7217 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
7219 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7220 ec.Report.Error (190, loc,
7221 "The __arglist construct is valid only within a variable argument method");
7227 public override void Emit (EmitContext ec)
7229 ec.Emit (OpCodes.Arglist);
7232 public override object Accept (StructuralVisitor visitor)
7234 return visitor.Visit (this);
7239 /// Represents the `__arglist (....)' construct
7241 public class Arglist : Expression
7243 Arguments arguments;
7245 public Arglist (Location loc)
7250 public Arglist (Arguments args, Location l)
7256 public Arguments Arguments {
7262 public MetaType[] ArgumentTypes {
7264 if (arguments == null)
7265 return MetaType.EmptyTypes;
7267 var retval = new MetaType[arguments.Count];
7268 for (int i = 0; i < retval.Length; i++)
7269 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
7275 public override bool ContainsEmitWithAwait ()
7277 throw new NotImplementedException ();
7280 public override Expression CreateExpressionTree (ResolveContext ec)
7282 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7286 protected override Expression DoResolve (ResolveContext ec)
7288 eclass = ExprClass.Variable;
7289 type = InternalType.Arglist;
7290 if (arguments != null) {
7291 bool dynamic; // Can be ignored as there is always only 1 overload
7292 arguments.Resolve (ec, out dynamic);
7298 public override void Emit (EmitContext ec)
7300 if (arguments != null)
7301 arguments.Emit (ec);
7304 protected override void CloneTo (CloneContext clonectx, Expression t)
7306 Arglist target = (Arglist) t;
7308 if (arguments != null)
7309 target.arguments = arguments.Clone (clonectx);
7312 public override object Accept (StructuralVisitor visitor)
7314 return visitor.Visit (this);
7318 public class RefValueExpr : ShimExpression, IAssignMethod
7320 FullNamedExpression texpr;
7322 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7329 public FullNamedExpression TypeExpression {
7335 public override bool ContainsEmitWithAwait ()
7340 protected override Expression DoResolve (ResolveContext rc)
7342 expr = expr.Resolve (rc);
7343 type = texpr.ResolveAsType (rc);
7344 if (expr == null || type == null)
7347 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7348 eclass = ExprClass.Value;
7352 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7354 return DoResolve (rc);
7357 public override void Emit (EmitContext ec)
7360 ec.Emit (OpCodes.Refanyval, type);
7361 ec.EmitLoadFromPtr (type);
7364 public void Emit (EmitContext ec, bool leave_copy)
7366 throw new NotImplementedException ();
7369 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7372 ec.Emit (OpCodes.Refanyval, type);
7375 LocalTemporary temporary = null;
7377 ec.Emit (OpCodes.Dup);
7378 temporary = new LocalTemporary (source.Type);
7379 temporary.Store (ec);
7382 ec.EmitStoreFromPtr (type);
7384 if (temporary != null) {
7385 temporary.Emit (ec);
7386 temporary.Release (ec);
7390 public override object Accept (StructuralVisitor visitor)
7392 return visitor.Visit (this);
7396 public class RefTypeExpr : ShimExpression
7398 public RefTypeExpr (Expression expr, Location loc)
7404 protected override Expression DoResolve (ResolveContext rc)
7406 expr = expr.Resolve (rc);
7410 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7414 type = rc.BuiltinTypes.Type;
7415 eclass = ExprClass.Value;
7419 public override void Emit (EmitContext ec)
7422 ec.Emit (OpCodes.Refanytype);
7423 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7425 ec.Emit (OpCodes.Call, m);
7428 public override object Accept (StructuralVisitor visitor)
7430 return visitor.Visit (this);
7434 public class MakeRefExpr : ShimExpression
7436 public MakeRefExpr (Expression expr, Location loc)
7442 public override bool ContainsEmitWithAwait ()
7444 throw new NotImplementedException ();
7447 protected override Expression DoResolve (ResolveContext rc)
7449 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
7450 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
7451 eclass = ExprClass.Value;
7455 public override void Emit (EmitContext ec)
7457 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
7458 ec.Emit (OpCodes.Mkrefany, expr.Type);
7461 public override object Accept (StructuralVisitor visitor)
7463 return visitor.Visit (this);
7468 /// Implements the typeof operator
7470 public class TypeOf : Expression {
7471 FullNamedExpression QueriedType;
7474 public TypeOf (FullNamedExpression queried_type, Location l)
7476 QueriedType = queried_type;
7481 // Use this constructor for any compiler generated typeof expression
7483 public TypeOf (TypeSpec type, Location loc)
7485 this.typearg = type;
7491 public override bool IsSideEffectFree {
7497 public TypeSpec TypeArgument {
7503 public FullNamedExpression TypeExpression {
7512 protected override void CloneTo (CloneContext clonectx, Expression t)
7514 TypeOf target = (TypeOf) t;
7515 if (QueriedType != null)
7516 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
7519 public override bool ContainsEmitWithAwait ()
7524 public override Expression CreateExpressionTree (ResolveContext ec)
7526 Arguments args = new Arguments (2);
7527 args.Add (new Argument (this));
7528 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7529 return CreateExpressionFactoryCall (ec, "Constant", args);
7532 protected override Expression DoResolve (ResolveContext ec)
7534 if (eclass != ExprClass.Unresolved)
7537 if (typearg == null) {
7539 // Pointer types are allowed without explicit unsafe, they are just tokens
7541 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
7542 typearg = QueriedType.ResolveAsType (ec);
7545 if (typearg == null)
7548 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7549 ec.Report.Error (1962, QueriedType.Location,
7550 "The typeof operator cannot be used on the dynamic type");
7554 type = ec.BuiltinTypes.Type;
7556 // Even though what is returned is a type object, it's treated as a value by the compiler.
7557 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7558 eclass = ExprClass.Value;
7562 static bool ContainsDynamicType (TypeSpec type)
7564 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7567 var element_container = type as ElementTypeSpec;
7568 if (element_container != null)
7569 return ContainsDynamicType (element_container.Element);
7571 foreach (var t in type.TypeArguments) {
7572 if (ContainsDynamicType (t)) {
7580 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7582 // Target type is not System.Type therefore must be object
7583 // and we need to use different encoding sequence
7584 if (targetType != type)
7587 if (typearg is InflatedTypeSpec) {
7590 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
7591 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7592 typearg.GetSignatureForError ());
7596 gt = gt.DeclaringType;
7597 } while (gt != null);
7600 if (ContainsDynamicType (typearg)) {
7601 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7605 enc.EncodeTypeName (typearg);
7608 public override void Emit (EmitContext ec)
7610 ec.Emit (OpCodes.Ldtoken, typearg);
7611 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7613 ec.Emit (OpCodes.Call, m);
7616 public override object Accept (StructuralVisitor visitor)
7618 return visitor.Visit (this);
7622 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
7624 public TypeOfMethod (MethodSpec method, Location loc)
7625 : base (method, loc)
7629 protected override Expression DoResolve (ResolveContext ec)
7631 if (member.IsConstructor) {
7632 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
7634 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
7640 return base.DoResolve (ec);
7643 public override void Emit (EmitContext ec)
7645 ec.Emit (OpCodes.Ldtoken, member);
7648 ec.Emit (OpCodes.Castclass, type);
7651 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7653 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
7656 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7658 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
7662 abstract class TypeOfMember<T> : Expression where T : MemberSpec
7664 protected readonly T member;
7666 protected TypeOfMember (T member, Location loc)
7668 this.member = member;
7672 public override bool IsSideEffectFree {
7678 public override bool ContainsEmitWithAwait ()
7683 public override Expression CreateExpressionTree (ResolveContext ec)
7685 Arguments args = new Arguments (2);
7686 args.Add (new Argument (this));
7687 args.Add (new Argument (new TypeOf (type, loc)));
7688 return CreateExpressionFactoryCall (ec, "Constant", args);
7691 protected override Expression DoResolve (ResolveContext ec)
7693 eclass = ExprClass.Value;
7697 public override void Emit (EmitContext ec)
7699 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
7700 PredefinedMember<MethodSpec> p;
7702 p = GetTypeFromHandleGeneric (ec);
7703 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
7705 p = GetTypeFromHandle (ec);
7708 var mi = p.Resolve (loc);
7710 ec.Emit (OpCodes.Call, mi);
7713 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
7714 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
7717 sealed class TypeOfField : TypeOfMember<FieldSpec>
7719 public TypeOfField (FieldSpec field, Location loc)
7724 protected override Expression DoResolve (ResolveContext ec)
7726 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
7730 return base.DoResolve (ec);
7733 public override void Emit (EmitContext ec)
7735 ec.Emit (OpCodes.Ldtoken, member);
7739 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7741 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
7744 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7746 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
7751 /// Implements the sizeof expression
7753 public class SizeOf : Expression {
7754 readonly Expression texpr;
7755 TypeSpec type_queried;
7757 public SizeOf (Expression queried_type, Location l)
7759 this.texpr = queried_type;
7763 public override bool IsSideEffectFree {
7769 public Expression TypeExpression {
7775 public override bool ContainsEmitWithAwait ()
7780 public override Expression CreateExpressionTree (ResolveContext ec)
7782 Error_PointerInsideExpressionTree (ec);
7786 protected override Expression DoResolve (ResolveContext ec)
7788 type_queried = texpr.ResolveAsType (ec);
7789 if (type_queried == null)
7792 if (type_queried.IsEnum)
7793 type_queried = EnumSpec.GetUnderlyingType (type_queried);
7795 int size_of = BuiltinTypeSpec.GetSize (type_queried);
7797 return new IntConstant (ec.BuiltinTypes, size_of, loc);
7800 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
7805 ec.Report.Error (233, loc,
7806 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7807 type_queried.GetSignatureForError ());
7810 type = ec.BuiltinTypes.Int;
7811 eclass = ExprClass.Value;
7815 public override void Emit (EmitContext ec)
7817 ec.Emit (OpCodes.Sizeof, type_queried);
7820 protected override void CloneTo (CloneContext clonectx, Expression t)
7824 public override object Accept (StructuralVisitor visitor)
7826 return visitor.Visit (this);
7831 /// Implements the qualified-alias-member (::) expression.
7833 public class QualifiedAliasMember : MemberAccess
7835 readonly string alias;
7836 public static readonly string GlobalAlias = "global";
7838 public QualifiedAliasMember (string alias, string identifier, Location l)
7839 : base (null, identifier, l)
7844 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7845 : base (null, identifier, targs, l)
7850 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
7851 : base (null, identifier, arity, l)
7856 public string Alias {
7862 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
7864 if (alias == GlobalAlias) {
7865 expr = ec.Module.GlobalRootNamespace;
7866 return base.ResolveAsTypeOrNamespace (ec);
7869 int errors = ec.Module.Compiler.Report.Errors;
7870 expr = ec.LookupNamespaceAlias (alias);
7872 if (errors == ec.Module.Compiler.Report.Errors)
7873 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7877 return base.ResolveAsTypeOrNamespace (ec);
7880 protected override Expression DoResolve (ResolveContext ec)
7882 return ResolveAsTypeOrNamespace (ec);
7885 public override string GetSignatureForError ()
7888 if (targs != null) {
7889 name = Name + "<" + targs.GetSignatureForError () + ">";
7892 return alias + "::" + name;
7895 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7897 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
7898 rc.Module.Compiler.Report.Error (687, loc,
7899 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
7900 GetSignatureForError ());
7905 return DoResolve (rc);
7908 protected override void CloneTo (CloneContext clonectx, Expression t)
7913 public override object Accept (StructuralVisitor visitor)
7915 return visitor.Visit (this);
7920 /// Implements the member access expression
7922 public class MemberAccess : ATypeNameExpression
7924 protected Expression expr;
7926 public MemberAccess (Expression expr, string id)
7927 : base (id, expr.Location)
7932 public MemberAccess (Expression expr, string identifier, Location loc)
7933 : base (identifier, loc)
7938 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7939 : base (identifier, args, loc)
7944 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
7945 : base (identifier, arity, loc)
7950 public Expression LeftExpression {
7956 public override Location StartLocation {
7958 return expr == null ? loc : expr.StartLocation;
7962 protected override Expression DoResolve (ResolveContext rc)
7964 var e = DoResolveName (rc, null);
7966 if (!rc.OmitStructFlowAnalysis) {
7967 var fe = e as FieldExpr;
7969 fe.VerifyAssignedStructField (rc, null);
7976 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
7978 var e = DoResolveName (rc, rhs);
7980 if (!rc.OmitStructFlowAnalysis) {
7981 var fe = e as FieldExpr;
7982 if (fe != null && fe.InstanceExpression is FieldExpr) {
7983 fe = (FieldExpr) fe.InstanceExpression;
7984 fe.VerifyAssignedStructField (rc, rhs);
7991 Expression DoResolveName (ResolveContext rc, Expression right_side)
7993 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
7997 if (right_side != null) {
7998 if (e is TypeExpr) {
7999 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8003 e = e.ResolveLValue (rc, right_side);
8005 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
8011 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8013 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8014 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8016 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8019 public static bool IsValidDotExpression (TypeSpec type)
8021 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8022 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8024 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8027 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8029 var sn = expr as SimpleName;
8030 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8033 // Resolve the expression with flow analysis turned off, we'll do the definite
8034 // assignment checks later. This is because we don't know yet what the expression
8035 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
8036 // definite assignment check on the actual field and not on the whole struct.
8038 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
8040 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8043 // Resolve expression which does have type set as we need expression type
8044 // with disable flow analysis as we don't know whether left side expression
8045 // is used as variable or type
8047 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8048 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
8049 expr = expr.Resolve (rc);
8051 } else if (expr is TypeParameterExpr) {
8052 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8056 expr = expr.Resolve (rc, flags);
8063 Namespace ns = expr as Namespace;
8065 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8067 if (retval == null) {
8068 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8072 if (HasTypeArguments)
8073 return new GenericTypeExpr (retval.Type, targs, loc);
8079 TypeSpec expr_type = expr.Type;
8080 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8081 me = expr as MemberExpr;
8083 me.ResolveInstanceExpression (rc, null);
8086 // Run defined assigned checks on expressions resolved with
8087 // disabled flow-analysis
8090 var vr = expr as VariableReference;
8092 vr.VerifyAssigned (rc);
8095 Arguments args = new Arguments (1);
8096 args.Add (new Argument (expr));
8097 return new DynamicMemberBinder (Name, args, loc);
8100 if (!IsValidDotExpression (expr_type)) {
8101 Error_OperatorCannotBeApplied (rc, expr_type);
8105 var lookup_arity = Arity;
8106 bool errorMode = false;
8107 Expression member_lookup;
8109 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8110 if (member_lookup == null) {
8112 // Try to look for extension method when member lookup failed
8114 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8115 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8116 if (methods != null) {
8117 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8118 if (HasTypeArguments) {
8119 if (!targs.Resolve (rc))
8122 emg.SetTypeArguments (rc, targs);
8126 // Run defined assigned checks on expressions resolved with
8127 // disabled flow-analysis
8129 if (sn != null && !errorMode) {
8130 var vr = expr as VariableReference;
8132 vr.VerifyAssigned (rc);
8135 // TODO: it should really skip the checks bellow
8136 return emg.Resolve (rc);
8142 if (member_lookup == null) {
8143 var dep = expr_type.GetMissingDependencies ();
8145 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8146 } else if (expr is TypeExpr) {
8147 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8149 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8155 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8156 // Leave it to overload resolution to report correct error
8157 } else if (!(member_lookup is TypeExpr)) {
8158 // TODO: rc.SymbolRelatedToPreviousError
8159 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8164 if (member_lookup != null)
8168 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8172 TypeExpr texpr = member_lookup as TypeExpr;
8173 if (texpr != null) {
8174 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8175 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8176 Name, texpr.GetSignatureForError ());
8179 if (!texpr.Type.IsAccessible (rc)) {
8180 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8181 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8185 if (HasTypeArguments) {
8186 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8189 return member_lookup;
8192 me = member_lookup as MemberExpr;
8194 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8198 me = me.ResolveMemberAccess (rc, expr, sn);
8201 if (!targs.Resolve (rc))
8204 me.SetTypeArguments (rc, targs);
8208 // Run defined assigned checks on expressions resolved with
8209 // disabled flow-analysis
8211 if (sn != null && !(me is FieldExpr && TypeSpec.IsValueType (expr_type))) {
8212 var vr = expr as VariableReference;
8214 vr.VerifyAssigned (rc);
8220 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8222 FullNamedExpression fexpr = expr as FullNamedExpression;
8223 if (fexpr == null) {
8224 expr.ResolveAsType (rc);
8228 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8230 if (expr_resolved == null)
8233 Namespace ns = expr_resolved as Namespace;
8235 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8237 if (retval == null) {
8238 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8239 } else if (HasTypeArguments) {
8240 retval = new GenericTypeExpr (retval.Type, targs, loc);
8241 if (retval.ResolveAsType (rc) == null)
8248 var tnew_expr = expr_resolved.ResolveAsType (rc);
8249 if (tnew_expr == null)
8252 TypeSpec expr_type = tnew_expr;
8253 if (TypeManager.IsGenericParameter (expr_type)) {
8254 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8255 tnew_expr.GetSignatureForError ());
8259 var qam = this as QualifiedAliasMember;
8261 rc.Module.Compiler.Report.Error (431, loc,
8262 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8267 TypeSpec nested = null;
8268 while (expr_type != null) {
8269 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8270 if (nested == null) {
8271 if (expr_type == tnew_expr) {
8272 Error_IdentifierNotFound (rc, expr_type, Name);
8276 expr_type = tnew_expr;
8277 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8278 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
8282 if (nested.IsAccessible (rc))
8286 // Keep looking after inaccessible candidate but only if
8287 // we are not in same context as the definition itself
8289 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
8292 expr_type = expr_type.BaseType;
8297 if (HasTypeArguments) {
8298 texpr = new GenericTypeExpr (nested, targs, loc);
8300 texpr = new GenericOpenTypeExpr (nested, loc);
8303 texpr = new TypeExpression (nested, loc);
8306 if (texpr.ResolveAsType (rc) == null)
8312 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
8314 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
8316 if (nested != null) {
8317 Error_TypeArgumentsCannotBeUsed (rc, nested, Arity, expr.Location);
8321 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
8322 if (any_other_member != null) {
8323 any_other_member.Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
8327 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
8328 Name, expr_type.GetSignatureForError ());
8331 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
8333 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
8336 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
8338 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8339 ec.Report.SymbolRelatedToPreviousError (type);
8341 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, type, name, Arity);
8343 // a using directive or an assembly reference
8345 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
8347 missing = "an assembly reference";
8350 ec.Report.Error (1061, loc,
8351 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
8352 type.GetSignatureForError (), name, missing);
8356 base.Error_TypeDoesNotContainDefinition (ec, type, name);
8359 public override string GetSignatureForError ()
8361 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
8364 protected override void CloneTo (CloneContext clonectx, Expression t)
8366 MemberAccess target = (MemberAccess) t;
8368 target.expr = expr.Clone (clonectx);
8371 public override object Accept (StructuralVisitor visitor)
8373 return visitor.Visit (this);
8378 /// Implements checked expressions
8380 public class CheckedExpr : Expression {
8382 public Expression Expr;
8384 public CheckedExpr (Expression e, Location l)
8390 public override bool ContainsEmitWithAwait ()
8392 return Expr.ContainsEmitWithAwait ();
8395 public override Expression CreateExpressionTree (ResolveContext ec)
8397 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
8398 return Expr.CreateExpressionTree (ec);
8401 protected override Expression DoResolve (ResolveContext ec)
8403 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
8404 Expr = Expr.Resolve (ec);
8409 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8412 eclass = Expr.eclass;
8417 public override void Emit (EmitContext ec)
8419 using (ec.With (EmitContext.Options.CheckedScope, true))
8423 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8425 using (ec.With (EmitContext.Options.CheckedScope, true))
8426 Expr.EmitBranchable (ec, target, on_true);
8429 public override SLE.Expression MakeExpression (BuilderContext ctx)
8431 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
8432 return Expr.MakeExpression (ctx);
8436 protected override void CloneTo (CloneContext clonectx, Expression t)
8438 CheckedExpr target = (CheckedExpr) t;
8440 target.Expr = Expr.Clone (clonectx);
8443 public override object Accept (StructuralVisitor visitor)
8445 return visitor.Visit (this);
8450 /// Implements the unchecked expression
8452 public class UnCheckedExpr : Expression {
8454 public Expression Expr;
8456 public UnCheckedExpr (Expression e, Location l)
8462 public override bool ContainsEmitWithAwait ()
8464 return Expr.ContainsEmitWithAwait ();
8467 public override Expression CreateExpressionTree (ResolveContext ec)
8469 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8470 return Expr.CreateExpressionTree (ec);
8473 protected override Expression DoResolve (ResolveContext ec)
8475 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8476 Expr = Expr.Resolve (ec);
8481 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8484 eclass = Expr.eclass;
8489 public override void Emit (EmitContext ec)
8491 using (ec.With (EmitContext.Options.CheckedScope, false))
8495 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8497 using (ec.With (EmitContext.Options.CheckedScope, false))
8498 Expr.EmitBranchable (ec, target, on_true);
8501 protected override void CloneTo (CloneContext clonectx, Expression t)
8503 UnCheckedExpr target = (UnCheckedExpr) t;
8505 target.Expr = Expr.Clone (clonectx);
8508 public override object Accept (StructuralVisitor visitor)
8510 return visitor.Visit (this);
8515 /// An Element Access expression.
8517 /// During semantic analysis these are transformed into
8518 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
8520 public class ElementAccess : Expression
8522 public Arguments Arguments;
8523 public Expression Expr;
8525 public ElementAccess (Expression e, Arguments args, Location loc)
8529 this.Arguments = args;
8532 public override Location StartLocation {
8534 return Expr.StartLocation;
8538 public override bool ContainsEmitWithAwait ()
8540 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
8544 // We perform some simple tests, and then to "split" the emit and store
8545 // code we create an instance of a different class, and return that.
8547 Expression CreateAccessExpression (ResolveContext ec)
8550 return (new ArrayAccess (this, loc));
8553 return MakePointerAccess (ec, type);
8555 FieldExpr fe = Expr as FieldExpr;
8557 var ff = fe.Spec as FixedFieldSpec;
8559 return MakePointerAccess (ec, ff.ElementType);
8563 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
8564 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8565 return new IndexerExpr (indexers, type, this);
8568 if (type != InternalType.ErrorType) {
8569 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8570 type.GetSignatureForError ());
8576 public override Expression CreateExpressionTree (ResolveContext ec)
8578 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
8579 Expr.CreateExpressionTree (ec));
8581 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
8584 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
8586 if (Arguments.Count != 1){
8587 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
8591 if (Arguments [0] is NamedArgument)
8592 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
8594 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
8595 return new Indirection (p, loc);
8598 protected override Expression DoResolve (ResolveContext ec)
8600 Expr = Expr.Resolve (ec);
8606 // TODO: Create 1 result for Resolve and ResolveLValue ?
8607 var res = CreateAccessExpression (ec);
8611 return res.Resolve (ec);
8614 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
8616 Expr = Expr.Resolve (ec);
8622 var res = CreateAccessExpression (ec);
8626 return res.ResolveLValue (ec, rhs);
8629 public override void Emit (EmitContext ec)
8631 throw new Exception ("Should never be reached");
8634 public static void Error_NamedArgument (NamedArgument na, Report Report)
8636 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
8639 public override string GetSignatureForError ()
8641 return Expr.GetSignatureForError ();
8644 protected override void CloneTo (CloneContext clonectx, Expression t)
8646 ElementAccess target = (ElementAccess) t;
8648 target.Expr = Expr.Clone (clonectx);
8649 if (Arguments != null)
8650 target.Arguments = Arguments.Clone (clonectx);
8653 public override object Accept (StructuralVisitor visitor)
8655 return visitor.Visit (this);
8660 /// Implements array access
8662 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
8664 // Points to our "data" repository
8668 LocalTemporary temp;
8670 bool? has_await_args;
8672 public ArrayAccess (ElementAccess ea_data, Location l)
8678 public void AddressOf (EmitContext ec, AddressOp mode)
8680 var ac = (ArrayContainer) ea.Expr.Type;
8682 LoadInstanceAndArguments (ec, false, false);
8684 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
8685 ec.Emit (OpCodes.Readonly);
8687 ec.EmitArrayAddress (ac);
8690 public override Expression CreateExpressionTree (ResolveContext ec)
8692 return ea.CreateExpressionTree (ec);
8695 public override bool ContainsEmitWithAwait ()
8697 return ea.ContainsEmitWithAwait ();
8700 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8702 return DoResolve (ec);
8705 protected override Expression DoResolve (ResolveContext ec)
8707 // dynamic is used per argument in ConvertExpressionToArrayIndex case
8709 ea.Arguments.Resolve (ec, out dynamic);
8711 var ac = ea.Expr.Type as ArrayContainer;
8712 int rank = ea.Arguments.Count;
8713 if (ac.Rank != rank) {
8714 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8715 rank.ToString (), ac.Rank.ToString ());
8720 if (type.IsPointer && !ec.IsUnsafe) {
8721 UnsafeError (ec, ea.Location);
8724 foreach (Argument a in ea.Arguments) {
8725 if (a is NamedArgument)
8726 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
8728 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
8731 eclass = ExprClass.Variable;
8736 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8738 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8742 // Load the array arguments into the stack.
8744 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
8747 ea.Expr = ea.Expr.EmitToField (ec);
8748 } else if (duplicateArguments) {
8750 ec.Emit (OpCodes.Dup);
8752 var copy = new LocalTemporary (ea.Expr.Type);
8759 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
8760 if (dup_args != null)
8761 ea.Arguments = dup_args;
8764 public void Emit (EmitContext ec, bool leave_copy)
8766 var ac = ea.Expr.Type as ArrayContainer;
8769 ec.EmitLoadFromPtr (type);
8771 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
8772 LoadInstanceAndArguments (ec, false, true);
8775 LoadInstanceAndArguments (ec, false, false);
8776 ec.EmitArrayLoad (ac);
8780 ec.Emit (OpCodes.Dup);
8781 temp = new LocalTemporary (this.type);
8786 public override void Emit (EmitContext ec)
8791 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8793 var ac = (ArrayContainer) ea.Expr.Type;
8794 TypeSpec t = source.Type;
8796 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
8799 // When we are dealing with a struct, get the address of it to avoid value copy
8800 // Same cannot be done for reference type because array covariance and the
8801 // check in ldelema requires to specify the type of array element stored at the index
8803 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
8804 LoadInstanceAndArguments (ec, false, has_await_args.Value);
8806 if (has_await_args.Value) {
8807 if (source.ContainsEmitWithAwait ()) {
8808 source = source.EmitToField (ec);
8813 LoadInstanceAndArguments (ec, isCompound, false);
8818 ec.EmitArrayAddress (ac);
8821 ec.Emit (OpCodes.Dup);
8825 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
8827 if (has_await_args.Value) {
8828 if (source.ContainsEmitWithAwait ())
8829 source = source.EmitToField (ec);
8831 LoadInstanceAndArguments (ec, false, false);
8838 var lt = ea.Expr as LocalTemporary;
8844 ec.Emit (OpCodes.Dup);
8845 temp = new LocalTemporary (this.type);
8850 ec.EmitStoreFromPtr (t);
8852 ec.EmitArrayStore (ac);
8861 public override Expression EmitToField (EmitContext ec)
8864 // Have to be specialized for arrays to get access to
8865 // underlying element. Instead of another result copy we
8866 // need direct access to element
8870 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
8872 ea.Expr = ea.Expr.EmitToField (ec);
8876 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8878 #if NET_4_0 || MONODROID
8879 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8881 throw new NotImplementedException ();
8885 public override SLE.Expression MakeExpression (BuilderContext ctx)
8887 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8890 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
8892 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
8893 return Arguments.MakeExpression (ea.Arguments, ctx);
8899 // Indexer access expression
8901 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
8903 IList<MemberSpec> indexers;
8904 Arguments arguments;
8905 TypeSpec queried_type;
8907 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
8908 : base (ea.Location)
8910 this.indexers = indexers;
8911 this.queried_type = queriedType;
8912 this.InstanceExpression = ea.Expr;
8913 this.arguments = ea.Arguments;
8918 protected override Arguments Arguments {
8927 protected override TypeSpec DeclaringType {
8929 return best_candidate.DeclaringType;
8933 public override bool IsInstance {
8939 public override bool IsStatic {
8945 public override string KindName {
8946 get { return "indexer"; }
8949 public override string Name {
8957 public override bool ContainsEmitWithAwait ()
8959 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
8962 public override Expression CreateExpressionTree (ResolveContext ec)
8964 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8965 InstanceExpression.CreateExpressionTree (ec),
8966 new TypeOfMethod (Getter, loc));
8968 return CreateExpressionFactoryCall (ec, "Call", args);
8971 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8973 LocalTemporary await_source_arg = null;
8976 emitting_compound_assignment = true;
8977 if (source is DynamicExpressionStatement) {
8982 emitting_compound_assignment = false;
8984 if (has_await_arguments) {
8985 await_source_arg = new LocalTemporary (Type);
8986 await_source_arg.Store (ec);
8988 arguments.Add (new Argument (await_source_arg));
8991 temp = await_source_arg;
8994 has_await_arguments = false;
8999 ec.Emit (OpCodes.Dup);
9000 temp = new LocalTemporary (Type);
9006 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9007 source = source.EmitToField (ec);
9009 temp = new LocalTemporary (Type);
9016 arguments.Add (new Argument (source));
9019 var call = new CallEmitter ();
9020 call.InstanceExpression = InstanceExpression;
9021 if (arguments == null)
9022 call.InstanceExpressionOnStack = true;
9024 call.Emit (ec, Setter, arguments, loc);
9029 } else if (leave_copy) {
9033 if (await_source_arg != null) {
9034 await_source_arg.Release (ec);
9038 public override string GetSignatureForError ()
9040 return best_candidate.GetSignatureForError ();
9043 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9046 throw new NotSupportedException ();
9048 var value = new[] { source.MakeExpression (ctx) };
9049 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9050 #if NET_4_0 || MONODROID
9051 return SLE.Expression.Block (
9052 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9055 return args.First ();
9060 public override SLE.Expression MakeExpression (BuilderContext ctx)
9063 return base.MakeExpression (ctx);
9065 var args = Arguments.MakeExpression (arguments, ctx);
9066 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9070 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9072 if (best_candidate != null)
9075 eclass = ExprClass.IndexerAccess;
9078 arguments.Resolve (rc, out dynamic);
9080 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9083 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9084 res.BaseMembersProvider = this;
9085 res.InstanceQualifier = this;
9087 // TODO: Do I need 2 argument sets?
9088 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9089 if (best_candidate != null)
9090 type = res.BestCandidateReturnType;
9091 else if (!res.BestCandidateIsDynamic)
9096 // It has dynamic arguments
9099 Arguments args = new Arguments (arguments.Count + 1);
9101 rc.Report.Error (1972, loc,
9102 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9104 args.Add (new Argument (InstanceExpression));
9106 args.AddRange (arguments);
9108 best_candidate = null;
9109 return new DynamicIndexBinder (args, loc);
9113 // Try to avoid resolving left expression again
9115 if (right_side != null)
9116 ResolveInstanceExpression (rc, right_side);
9121 protected override void CloneTo (CloneContext clonectx, Expression t)
9123 IndexerExpr target = (IndexerExpr) t;
9125 if (arguments != null)
9126 target.arguments = arguments.Clone (clonectx);
9129 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9131 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9134 #region IBaseMembersProvider Members
9136 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9138 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9141 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9143 if (queried_type == member.DeclaringType)
9146 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9147 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9150 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9159 // A base access expression
9161 public class BaseThis : This
9163 public BaseThis (Location loc)
9168 public BaseThis (TypeSpec type, Location loc)
9172 eclass = ExprClass.Variable;
9177 public override string Name {
9185 public override Expression CreateExpressionTree (ResolveContext ec)
9187 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9188 return base.CreateExpressionTree (ec);
9191 public override void Emit (EmitContext ec)
9195 var context_type = ec.CurrentType;
9196 if (context_type.IsStruct) {
9197 ec.Emit (OpCodes.Ldobj, context_type);
9198 ec.Emit (OpCodes.Box, context_type);
9202 protected override void Error_ThisNotAvailable (ResolveContext ec)
9205 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9207 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9211 public override void ResolveBase (ResolveContext ec)
9213 base.ResolveBase (ec);
9214 type = ec.CurrentType.BaseType;
9217 public override object Accept (StructuralVisitor visitor)
9219 return visitor.Visit (this);
9224 /// This class exists solely to pass the Type around and to be a dummy
9225 /// that can be passed to the conversion functions (this is used by
9226 /// foreach implementation to typecast the object return value from
9227 /// get_Current into the proper type. All code has been generated and
9228 /// we only care about the side effect conversions to be performed
9230 /// This is also now used as a placeholder where a no-action expression
9231 /// is needed (the `New' class).
9233 public class EmptyExpression : Expression
9235 sealed class OutAccessExpression : EmptyExpression
9237 public OutAccessExpression (TypeSpec t)
9242 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9244 rc.Report.Error (206, right_side.Location,
9245 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
9251 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
9252 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
9253 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
9254 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
9255 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
9256 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
9257 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
9258 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
9260 public EmptyExpression (TypeSpec t)
9263 eclass = ExprClass.Value;
9264 loc = Location.Null;
9267 public override bool ContainsEmitWithAwait ()
9272 public override Expression CreateExpressionTree (ResolveContext ec)
9274 throw new NotSupportedException ("ET");
9277 protected override Expression DoResolve (ResolveContext ec)
9282 public override void Emit (EmitContext ec)
9284 // nothing, as we only exist to not do anything.
9287 public override void EmitSideEffect (EmitContext ec)
9291 public override object Accept (StructuralVisitor visitor)
9293 return visitor.Visit (this);
9297 sealed class EmptyAwaitExpression : EmptyExpression
9299 public EmptyAwaitExpression (TypeSpec type)
9304 public override bool ContainsEmitWithAwait ()
9311 // Empty statement expression
9313 public sealed class EmptyExpressionStatement : ExpressionStatement
9315 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
9317 private EmptyExpressionStatement ()
9319 loc = Location.Null;
9322 public override bool ContainsEmitWithAwait ()
9327 public override Expression CreateExpressionTree (ResolveContext ec)
9332 public override void EmitStatement (EmitContext ec)
9337 protected override Expression DoResolve (ResolveContext ec)
9339 eclass = ExprClass.Value;
9340 type = ec.BuiltinTypes.Object;
9344 public override void Emit (EmitContext ec)
9349 public override object Accept (StructuralVisitor visitor)
9351 return visitor.Visit (this);
9355 public class ErrorExpression : EmptyExpression
9357 public static readonly ErrorExpression Instance = new ErrorExpression ();
9359 private ErrorExpression ()
9360 : base (InternalType.ErrorType)
9364 public override Expression CreateExpressionTree (ResolveContext ec)
9369 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9374 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
9378 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
9382 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
9386 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
9390 public override object Accept (StructuralVisitor visitor)
9392 return visitor.Visit (this);
9396 public class UserCast : Expression {
9400 public UserCast (MethodSpec method, Expression source, Location l)
9403 throw new ArgumentNullException ("source");
9405 this.method = method;
9406 this.source = source;
9407 type = method.ReturnType;
9411 public Expression Source {
9417 public override bool ContainsEmitWithAwait ()
9419 return source.ContainsEmitWithAwait ();
9422 public override Expression CreateExpressionTree (ResolveContext ec)
9424 Arguments args = new Arguments (3);
9425 args.Add (new Argument (source.CreateExpressionTree (ec)));
9426 args.Add (new Argument (new TypeOf (type, loc)));
9427 args.Add (new Argument (new TypeOfMethod (method, loc)));
9428 return CreateExpressionFactoryCall (ec, "Convert", args);
9431 protected override Expression DoResolve (ResolveContext ec)
9433 ObsoleteAttribute oa = method.GetAttributeObsolete ();
9435 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
9437 eclass = ExprClass.Value;
9441 public override void Emit (EmitContext ec)
9444 ec.Emit (OpCodes.Call, method);
9447 public override string GetSignatureForError ()
9449 return TypeManager.CSharpSignature (method);
9452 public override SLE.Expression MakeExpression (BuilderContext ctx)
9455 return base.MakeExpression (ctx);
9457 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
9463 // Holds additional type specifiers like ?, *, []
9465 public class ComposedTypeSpecifier
9467 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
9469 public readonly int Dimension;
9470 public readonly Location Location;
9472 public ComposedTypeSpecifier (int specifier, Location loc)
9474 this.Dimension = specifier;
9475 this.Location = loc;
9479 public bool IsNullable {
9481 return Dimension == -1;
9485 public bool IsPointer {
9487 return Dimension == -2;
9491 public ComposedTypeSpecifier Next { get; set; }
9495 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
9497 return new ComposedTypeSpecifier (dimension, loc);
9500 public static ComposedTypeSpecifier CreateNullable (Location loc)
9502 return new ComposedTypeSpecifier (-1, loc);
9505 public static ComposedTypeSpecifier CreatePointer (Location loc)
9507 return new ComposedTypeSpecifier (-2, loc);
9510 public string GetSignatureForError ()
9515 ArrayContainer.GetPostfixSignature (Dimension);
9517 return Next != null ? s + Next.GetSignatureForError () : s;
9522 // This class is used to "construct" the type during a typecast
9523 // operation. Since the Type.GetType class in .NET can parse
9524 // the type specification, we just use this to construct the type
9525 // one bit at a time.
9527 public class ComposedCast : TypeExpr {
9528 FullNamedExpression left;
9529 ComposedTypeSpecifier spec;
9531 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
9534 throw new ArgumentNullException ("spec");
9538 this.loc = left.Location;
9541 public override TypeSpec ResolveAsType (IMemberContext ec)
9543 type = left.ResolveAsType (ec);
9547 eclass = ExprClass.Type;
9549 var single_spec = spec;
9551 if (single_spec.IsNullable) {
9552 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
9556 single_spec = single_spec.Next;
9557 } else if (single_spec.IsPointer) {
9558 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
9562 UnsafeError (ec.Module.Compiler.Report, loc);
9566 type = PointerContainer.MakeType (ec.Module, type);
9567 single_spec = single_spec.Next;
9568 } while (single_spec != null && single_spec.IsPointer);
9571 if (single_spec != null && single_spec.Dimension > 0) {
9572 if (type.IsSpecialRuntimeType) {
9573 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
9574 } else if (type.IsStatic) {
9575 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
9576 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9577 type.GetSignatureForError ());
9579 MakeArray (ec.Module, single_spec);
9586 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
9588 if (spec.Next != null)
9589 MakeArray (module, spec.Next);
9591 type = ArrayContainer.MakeType (module, type, spec.Dimension);
9594 public override string GetSignatureForError ()
9596 return left.GetSignatureForError () + spec.GetSignatureForError ();
9599 public override object Accept (StructuralVisitor visitor)
9601 return visitor.Visit (this);
9605 class FixedBufferPtr : Expression
9607 readonly Expression array;
9609 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
9611 this.type = array_type;
9616 public override bool ContainsEmitWithAwait ()
9618 throw new NotImplementedException ();
9621 public override Expression CreateExpressionTree (ResolveContext ec)
9623 Error_PointerInsideExpressionTree (ec);
9627 public override void Emit(EmitContext ec)
9632 protected override Expression DoResolve (ResolveContext ec)
9634 type = PointerContainer.MakeType (ec.Module, type);
9635 eclass = ExprClass.Value;
9642 // This class is used to represent the address of an array, used
9643 // only by the Fixed statement, this generates "&a [0]" construct
9644 // for fixed (char *pa = a)
9646 class ArrayPtr : FixedBufferPtr
9648 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
9649 base (array, array_type, l)
9653 public override void Emit (EmitContext ec)
9658 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
9663 // Encapsulates a conversion rules required for array indexes
9665 public class ArrayIndexCast : TypeCast
9667 public ArrayIndexCast (Expression expr, TypeSpec returnType)
9668 : base (expr, returnType)
9670 if (expr.Type == returnType) // int -> int
9671 throw new ArgumentException ("unnecessary array index conversion");
9674 public override Expression CreateExpressionTree (ResolveContext ec)
9676 using (ec.Set (ResolveContext.Options.CheckedScope)) {
9677 return base.CreateExpressionTree (ec);
9681 public override void Emit (EmitContext ec)
9685 switch (child.Type.BuiltinType) {
9686 case BuiltinTypeSpec.Type.UInt:
9687 ec.Emit (OpCodes.Conv_U);
9689 case BuiltinTypeSpec.Type.Long:
9690 ec.Emit (OpCodes.Conv_Ovf_I);
9692 case BuiltinTypeSpec.Type.ULong:
9693 ec.Emit (OpCodes.Conv_Ovf_I_Un);
9696 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9702 // Implements the `stackalloc' keyword
9704 public class StackAlloc : Expression {
9709 public StackAlloc (Expression type, Expression count, Location l)
9716 public Expression TypeExpression {
9722 public Expression CountExpression {
9728 public override bool ContainsEmitWithAwait ()
9733 public override Expression CreateExpressionTree (ResolveContext ec)
9735 throw new NotSupportedException ("ET");
9738 protected override Expression DoResolve (ResolveContext ec)
9740 count = count.Resolve (ec);
9744 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
9745 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
9750 Constant c = count as Constant;
9751 if (c != null && c.IsNegative) {
9752 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9755 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9756 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9759 otype = t.ResolveAsType (ec);
9763 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
9766 type = PointerContainer.MakeType (ec.Module, otype);
9767 eclass = ExprClass.Value;
9772 public override void Emit (EmitContext ec)
9774 int size = BuiltinTypeSpec.GetSize (otype);
9779 ec.Emit (OpCodes.Sizeof, otype);
9783 ec.Emit (OpCodes.Mul_Ovf_Un);
9784 ec.Emit (OpCodes.Localloc);
9787 protected override void CloneTo (CloneContext clonectx, Expression t)
9789 StackAlloc target = (StackAlloc) t;
9790 target.count = count.Clone (clonectx);
9791 target.t = t.Clone (clonectx);
9794 public override object Accept (StructuralVisitor visitor)
9796 return visitor.Visit (this);
9801 // An object initializer expression
9803 public class ElementInitializer : Assign
9805 public readonly string Name;
9807 public ElementInitializer (string name, Expression initializer, Location loc)
9808 : base (null, initializer, loc)
9813 protected override void CloneTo (CloneContext clonectx, Expression t)
9815 ElementInitializer target = (ElementInitializer) t;
9816 target.source = source.Clone (clonectx);
9819 public override Expression CreateExpressionTree (ResolveContext ec)
9821 Arguments args = new Arguments (2);
9822 FieldExpr fe = target as FieldExpr;
9824 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9826 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
9829 Expression arg_expr;
9830 var cinit = source as CollectionOrObjectInitializers;
9831 if (cinit == null) {
9833 arg_expr = source.CreateExpressionTree (ec);
9835 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
9836 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
9839 args.Add (new Argument (arg_expr));
9840 return CreateExpressionFactoryCall (ec, mname, args);
9843 protected override Expression DoResolve (ResolveContext ec)
9846 return EmptyExpressionStatement.Instance;
9848 var t = ec.CurrentInitializerVariable.Type;
9849 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9850 Arguments args = new Arguments (1);
9851 args.Add (new Argument (ec.CurrentInitializerVariable));
9852 target = new DynamicMemberBinder (Name, args, loc);
9855 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9856 if (member == null) {
9857 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9859 if (member != null) {
9860 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
9861 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
9866 if (member == null) {
9867 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
9871 if (!(member is PropertyExpr || member is FieldExpr)) {
9872 ec.Report.Error (1913, loc,
9873 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
9874 member.GetSignatureForError ());
9879 var me = member as MemberExpr;
9881 ec.Report.Error (1914, loc,
9882 "Static field or property `{0}' cannot be assigned in an object initializer",
9883 me.GetSignatureForError ());
9887 me.InstanceExpression = ec.CurrentInitializerVariable;
9890 if (source is CollectionOrObjectInitializers) {
9891 Expression previous = ec.CurrentInitializerVariable;
9892 ec.CurrentInitializerVariable = target;
9893 source = source.Resolve (ec);
9894 ec.CurrentInitializerVariable = previous;
9898 eclass = source.eclass;
9903 return base.DoResolve (ec);
9906 public override void EmitStatement (EmitContext ec)
9908 if (source is CollectionOrObjectInitializers)
9911 base.EmitStatement (ec);
9916 // A collection initializer expression
9918 class CollectionElementInitializer : Invocation
9920 public class ElementInitializerArgument : Argument
9922 public ElementInitializerArgument (Expression e)
9928 sealed class AddMemberAccess : MemberAccess
9930 public AddMemberAccess (Expression expr, Location loc)
9931 : base (expr, "Add", loc)
9935 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9937 if (TypeManager.HasElementType (type))
9940 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9944 public CollectionElementInitializer (Expression argument)
9945 : base (null, new Arguments (1))
9947 base.arguments.Add (new ElementInitializerArgument (argument));
9948 this.loc = argument.Location;
9951 public CollectionElementInitializer (List<Expression> arguments, Location loc)
9952 : base (null, new Arguments (arguments.Count))
9954 foreach (Expression e in arguments)
9955 base.arguments.Add (new ElementInitializerArgument (e));
9960 public override Expression CreateExpressionTree (ResolveContext ec)
9962 Arguments args = new Arguments (2);
9963 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9965 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
9966 foreach (Argument a in arguments)
9967 expr_initializers.Add (a.CreateExpressionTree (ec));
9969 args.Add (new Argument (new ArrayCreation (
9970 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
9971 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9974 protected override void CloneTo (CloneContext clonectx, Expression t)
9976 CollectionElementInitializer target = (CollectionElementInitializer) t;
9977 if (arguments != null)
9978 target.arguments = arguments.Clone (clonectx);
9981 protected override Expression DoResolve (ResolveContext ec)
9983 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9985 return base.DoResolve (ec);
9990 // A block of object or collection initializers
9992 public class CollectionOrObjectInitializers : ExpressionStatement
9994 IList<Expression> initializers;
9995 bool is_collection_initialization;
9997 public CollectionOrObjectInitializers (Location loc)
9998 : this (new Expression[0], loc)
10002 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10004 this.initializers = initializers;
10008 public IList<Expression> Initializers {
10010 return initializers;
10014 public bool IsEmpty {
10016 return initializers.Count == 0;
10020 public bool IsCollectionInitializer {
10022 return is_collection_initialization;
10026 protected override void CloneTo (CloneContext clonectx, Expression target)
10028 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10030 t.initializers = new List<Expression> (initializers.Count);
10031 foreach (var e in initializers)
10032 t.initializers.Add (e.Clone (clonectx));
10035 public override bool ContainsEmitWithAwait ()
10037 foreach (var e in initializers) {
10038 if (e.ContainsEmitWithAwait ())
10045 public override Expression CreateExpressionTree (ResolveContext ec)
10047 return CreateExpressionTree (ec, false);
10050 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10052 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10053 foreach (Expression e in initializers) {
10054 Expression expr = e.CreateExpressionTree (ec);
10056 expr_initializers.Add (expr);
10060 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10062 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10065 protected override Expression DoResolve (ResolveContext ec)
10067 List<string> element_names = null;
10068 for (int i = 0; i < initializers.Count; ++i) {
10069 Expression initializer = initializers [i];
10070 ElementInitializer element_initializer = initializer as ElementInitializer;
10073 if (element_initializer != null) {
10074 element_names = new List<string> (initializers.Count);
10075 element_names.Add (element_initializer.Name);
10076 } else if (initializer is CompletingExpression){
10077 initializer.Resolve (ec);
10078 throw new InternalErrorException ("This line should never be reached");
10080 var t = ec.CurrentInitializerVariable.Type;
10081 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10082 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10083 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10084 "object initializer because type `{1}' does not implement `{2}' interface",
10085 ec.CurrentInitializerVariable.GetSignatureForError (),
10086 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10087 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10090 is_collection_initialization = true;
10093 if (is_collection_initialization != (element_initializer == null)) {
10094 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10095 is_collection_initialization ? "collection initializer" : "object initializer");
10099 if (!is_collection_initialization) {
10100 if (element_names.Contains (element_initializer.Name)) {
10101 ec.Report.Error (1912, element_initializer.Location,
10102 "An object initializer includes more than one member `{0}' initialization",
10103 element_initializer.Name);
10105 element_names.Add (element_initializer.Name);
10110 Expression e = initializer.Resolve (ec);
10111 if (e == EmptyExpressionStatement.Instance)
10112 initializers.RemoveAt (i--);
10114 initializers [i] = e;
10117 type = ec.CurrentInitializerVariable.Type;
10118 if (is_collection_initialization) {
10119 if (TypeManager.HasElementType (type)) {
10120 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10121 type.GetSignatureForError ());
10125 eclass = ExprClass.Variable;
10129 public override void Emit (EmitContext ec)
10131 EmitStatement (ec);
10134 public override void EmitStatement (EmitContext ec)
10136 foreach (ExpressionStatement e in initializers) {
10137 // TODO: need location region
10138 ec.Mark (e.Location);
10139 e.EmitStatement (ec);
10145 // New expression with element/object initializers
10147 public class NewInitialize : New
10150 // This class serves as a proxy for variable initializer target instances.
10151 // A real variable is assigned later when we resolve left side of an
10154 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10156 NewInitialize new_instance;
10158 public InitializerTargetExpression (NewInitialize newInstance)
10160 this.type = newInstance.type;
10161 this.loc = newInstance.loc;
10162 this.eclass = newInstance.eclass;
10163 this.new_instance = newInstance;
10166 public override bool ContainsEmitWithAwait ()
10171 public override Expression CreateExpressionTree (ResolveContext ec)
10173 // Should not be reached
10174 throw new NotSupportedException ("ET");
10177 protected override Expression DoResolve (ResolveContext ec)
10182 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10187 public override void Emit (EmitContext ec)
10189 Expression e = (Expression) new_instance.instance;
10193 public override Expression EmitToField (EmitContext ec)
10195 return (Expression) new_instance.instance;
10198 #region IMemoryLocation Members
10200 public void AddressOf (EmitContext ec, AddressOp mode)
10202 new_instance.instance.AddressOf (ec, mode);
10208 CollectionOrObjectInitializers initializers;
10209 IMemoryLocation instance;
10210 DynamicExpressionStatement dynamic;
10212 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10213 : base (requested_type, arguments, l)
10215 this.initializers = initializers;
10218 public CollectionOrObjectInitializers Initializers {
10220 return initializers;
10224 protected override void CloneTo (CloneContext clonectx, Expression t)
10226 base.CloneTo (clonectx, t);
10228 NewInitialize target = (NewInitialize) t;
10229 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
10232 public override bool ContainsEmitWithAwait ()
10234 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
10237 public override Expression CreateExpressionTree (ResolveContext ec)
10239 Arguments args = new Arguments (2);
10240 args.Add (new Argument (base.CreateExpressionTree (ec)));
10241 if (!initializers.IsEmpty)
10242 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
10244 return CreateExpressionFactoryCall (ec,
10245 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
10249 protected override Expression DoResolve (ResolveContext ec)
10251 Expression e = base.DoResolve (ec);
10255 if (type.IsDelegate) {
10256 ec.Report.Error (1958, Initializers.Location,
10257 "Object and collection initializers cannot be used to instantiate a delegate");
10260 Expression previous = ec.CurrentInitializerVariable;
10261 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
10262 initializers.Resolve (ec);
10263 ec.CurrentInitializerVariable = previous;
10265 dynamic = e as DynamicExpressionStatement;
10266 if (dynamic != null)
10272 public override bool Emit (EmitContext ec, IMemoryLocation target)
10274 bool left_on_stack;
10275 if (dynamic != null) {
10277 left_on_stack = true;
10279 left_on_stack = base.Emit (ec, target);
10282 if (initializers.IsEmpty)
10283 return left_on_stack;
10285 LocalTemporary temp = null;
10287 instance = target as LocalTemporary;
10289 if (instance == null) {
10290 if (!left_on_stack) {
10291 VariableReference vr = target as VariableReference;
10293 // FIXME: This still does not work correctly for pre-set variables
10294 if (vr != null && vr.IsRef)
10295 target.AddressOf (ec, AddressOp.Load);
10297 ((Expression) target).Emit (ec);
10298 left_on_stack = true;
10301 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
10302 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
10304 temp = new LocalTemporary (type);
10309 if (left_on_stack && temp != null)
10312 initializers.Emit (ec);
10314 if (left_on_stack) {
10315 if (temp != null) {
10319 ((Expression) instance).Emit (ec);
10323 return left_on_stack;
10326 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
10328 instance = base.EmitAddressOf (ec, Mode);
10330 if (!initializers.IsEmpty)
10331 initializers.Emit (ec);
10336 public override object Accept (StructuralVisitor visitor)
10338 return visitor.Visit (this);
10342 public class NewAnonymousType : New
10344 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
10346 List<AnonymousTypeParameter> parameters;
10347 readonly TypeContainer parent;
10348 AnonymousTypeClass anonymous_type;
10350 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
10351 : base (null, null, loc)
10353 this.parameters = parameters;
10354 this.parent = parent;
10357 public List<AnonymousTypeParameter> Parameters {
10359 return this.parameters;
10363 protected override void CloneTo (CloneContext clonectx, Expression target)
10365 if (parameters == null)
10368 NewAnonymousType t = (NewAnonymousType) target;
10369 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
10370 foreach (AnonymousTypeParameter atp in parameters)
10371 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
10374 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
10376 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
10380 type = AnonymousTypeClass.Create (parent, parameters, loc);
10384 int errors = ec.Report.Errors;
10385 type.CreateContainer ();
10386 type.DefineContainer ();
10388 if ((ec.Report.Errors - errors) == 0) {
10389 parent.Module.AddAnonymousType (type);
10395 public override Expression CreateExpressionTree (ResolveContext ec)
10397 if (parameters == null)
10398 return base.CreateExpressionTree (ec);
10400 var init = new ArrayInitializer (parameters.Count, loc);
10401 foreach (var m in anonymous_type.Members) {
10402 var p = m as Property;
10404 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
10407 var ctor_args = new ArrayInitializer (arguments.Count, loc);
10408 foreach (Argument a in arguments)
10409 ctor_args.Add (a.CreateExpressionTree (ec));
10411 Arguments args = new Arguments (3);
10412 args.Add (new Argument (new TypeOfMethod (method, loc)));
10413 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
10414 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
10416 return CreateExpressionFactoryCall (ec, "New", args);
10419 protected override Expression DoResolve (ResolveContext ec)
10421 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
10422 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
10426 if (parameters == null) {
10427 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
10428 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
10429 return base.DoResolve (ec);
10432 bool error = false;
10433 arguments = new Arguments (parameters.Count);
10434 var t_args = new TypeSpec [parameters.Count];
10435 for (int i = 0; i < parameters.Count; ++i) {
10436 Expression e = parameters [i].Resolve (ec);
10442 arguments.Add (new Argument (e));
10443 t_args [i] = e.Type;
10449 anonymous_type = CreateAnonymousType (ec, parameters);
10450 if (anonymous_type == null)
10453 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
10454 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
10455 eclass = ExprClass.Value;
10459 public override void EmitStatement (EmitContext ec)
10461 base.EmitStatement (ec);
10464 public override object Accept (StructuralVisitor visitor)
10466 return visitor.Visit (this);
10470 public class AnonymousTypeParameter : ShimExpression
10472 public readonly string Name;
10474 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
10475 : base (initializer)
10481 public AnonymousTypeParameter (Parameter parameter)
10482 : base (new SimpleName (parameter.Name, parameter.Location))
10484 this.Name = parameter.Name;
10485 this.loc = parameter.Location;
10488 public override bool Equals (object o)
10490 AnonymousTypeParameter other = o as AnonymousTypeParameter;
10491 return other != null && Name == other.Name;
10494 public override int GetHashCode ()
10496 return Name.GetHashCode ();
10499 protected override Expression DoResolve (ResolveContext ec)
10501 Expression e = expr.Resolve (ec);
10505 if (e.eclass == ExprClass.MethodGroup) {
10506 Error_InvalidInitializer (ec, e.ExprClassName);
10511 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
10512 Error_InvalidInitializer (ec, type.GetSignatureForError ());
10519 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
10521 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
10522 Name, initializer);