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 expr.Location;
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 TypeManager.CSharpName (probe_type_expr));
1442 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1443 TypeManager.CSharpName (probe_type_expr));
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 TypeManager.CSharpName (type));
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 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
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}'", TypeManager.CSharpName (type));
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 {
2261 /// Returns a stringified representation of the Operator
2263 string OperName (Operator oper)
2267 case Operator.Multiply:
2270 case Operator.Division:
2273 case Operator.Modulus:
2276 case Operator.Addition:
2279 case Operator.Subtraction:
2282 case Operator.LeftShift:
2285 case Operator.RightShift:
2288 case Operator.LessThan:
2291 case Operator.GreaterThan:
2294 case Operator.LessThanOrEqual:
2297 case Operator.GreaterThanOrEqual:
2300 case Operator.Equality:
2303 case Operator.Inequality:
2306 case Operator.BitwiseAnd:
2309 case Operator.BitwiseOr:
2312 case Operator.ExclusiveOr:
2315 case Operator.LogicalOr:
2318 case Operator.LogicalAnd:
2322 s = oper.ToString ();
2332 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2334 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2337 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2339 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
2343 l = TypeManager.CSharpName (left.Type);
2344 r = TypeManager.CSharpName (right.Type);
2346 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2350 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2352 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2356 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2358 string GetOperatorExpressionTypeName ()
2361 case Operator.Addition:
2362 return IsCompound ? "AddAssign" : "Add";
2363 case Operator.BitwiseAnd:
2364 return IsCompound ? "AndAssign" : "And";
2365 case Operator.BitwiseOr:
2366 return IsCompound ? "OrAssign" : "Or";
2367 case Operator.Division:
2368 return IsCompound ? "DivideAssign" : "Divide";
2369 case Operator.ExclusiveOr:
2370 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2371 case Operator.Equality:
2373 case Operator.GreaterThan:
2374 return "GreaterThan";
2375 case Operator.GreaterThanOrEqual:
2376 return "GreaterThanOrEqual";
2377 case Operator.Inequality:
2379 case Operator.LeftShift:
2380 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2381 case Operator.LessThan:
2383 case Operator.LessThanOrEqual:
2384 return "LessThanOrEqual";
2385 case Operator.LogicalAnd:
2387 case Operator.LogicalOr:
2389 case Operator.Modulus:
2390 return IsCompound ? "ModuloAssign" : "Modulo";
2391 case Operator.Multiply:
2392 return IsCompound ? "MultiplyAssign" : "Multiply";
2393 case Operator.RightShift:
2394 return IsCompound ? "RightShiftAssign" : "RightShift";
2395 case Operator.Subtraction:
2396 return IsCompound ? "SubtractAssign" : "Subtract";
2398 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2402 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2405 case Operator.Addition:
2406 return CSharp.Operator.OpType.Addition;
2407 case Operator.BitwiseAnd:
2408 case Operator.LogicalAnd:
2409 return CSharp.Operator.OpType.BitwiseAnd;
2410 case Operator.BitwiseOr:
2411 case Operator.LogicalOr:
2412 return CSharp.Operator.OpType.BitwiseOr;
2413 case Operator.Division:
2414 return CSharp.Operator.OpType.Division;
2415 case Operator.Equality:
2416 return CSharp.Operator.OpType.Equality;
2417 case Operator.ExclusiveOr:
2418 return CSharp.Operator.OpType.ExclusiveOr;
2419 case Operator.GreaterThan:
2420 return CSharp.Operator.OpType.GreaterThan;
2421 case Operator.GreaterThanOrEqual:
2422 return CSharp.Operator.OpType.GreaterThanOrEqual;
2423 case Operator.Inequality:
2424 return CSharp.Operator.OpType.Inequality;
2425 case Operator.LeftShift:
2426 return CSharp.Operator.OpType.LeftShift;
2427 case Operator.LessThan:
2428 return CSharp.Operator.OpType.LessThan;
2429 case Operator.LessThanOrEqual:
2430 return CSharp.Operator.OpType.LessThanOrEqual;
2431 case Operator.Modulus:
2432 return CSharp.Operator.OpType.Modulus;
2433 case Operator.Multiply:
2434 return CSharp.Operator.OpType.Multiply;
2435 case Operator.RightShift:
2436 return CSharp.Operator.OpType.RightShift;
2437 case Operator.Subtraction:
2438 return CSharp.Operator.OpType.Subtraction;
2440 throw new InternalErrorException (op.ToString ());
2444 public override bool ContainsEmitWithAwait ()
2446 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2449 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l)
2454 case Operator.Multiply:
2455 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2456 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2457 opcode = OpCodes.Mul_Ovf;
2458 else if (!IsFloat (l))
2459 opcode = OpCodes.Mul_Ovf_Un;
2461 opcode = OpCodes.Mul;
2463 opcode = OpCodes.Mul;
2467 case Operator.Division:
2469 opcode = OpCodes.Div_Un;
2471 opcode = OpCodes.Div;
2474 case Operator.Modulus:
2476 opcode = OpCodes.Rem_Un;
2478 opcode = OpCodes.Rem;
2481 case Operator.Addition:
2482 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2483 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2484 opcode = OpCodes.Add_Ovf;
2485 else if (!IsFloat (l))
2486 opcode = OpCodes.Add_Ovf_Un;
2488 opcode = OpCodes.Add;
2490 opcode = OpCodes.Add;
2493 case Operator.Subtraction:
2494 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2495 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2496 opcode = OpCodes.Sub_Ovf;
2497 else if (!IsFloat (l))
2498 opcode = OpCodes.Sub_Ovf_Un;
2500 opcode = OpCodes.Sub;
2502 opcode = OpCodes.Sub;
2505 case Operator.RightShift:
2507 opcode = OpCodes.Shr_Un;
2509 opcode = OpCodes.Shr;
2512 case Operator.LeftShift:
2513 opcode = OpCodes.Shl;
2516 case Operator.Equality:
2517 opcode = OpCodes.Ceq;
2520 case Operator.Inequality:
2521 ec.Emit (OpCodes.Ceq);
2524 opcode = OpCodes.Ceq;
2527 case Operator.LessThan:
2529 opcode = OpCodes.Clt_Un;
2531 opcode = OpCodes.Clt;
2534 case Operator.GreaterThan:
2536 opcode = OpCodes.Cgt_Un;
2538 opcode = OpCodes.Cgt;
2541 case Operator.LessThanOrEqual:
2542 if (IsUnsigned (l) || IsFloat (l))
2543 ec.Emit (OpCodes.Cgt_Un);
2545 ec.Emit (OpCodes.Cgt);
2548 opcode = OpCodes.Ceq;
2551 case Operator.GreaterThanOrEqual:
2552 if (IsUnsigned (l) || IsFloat (l))
2553 ec.Emit (OpCodes.Clt_Un);
2555 ec.Emit (OpCodes.Clt);
2559 opcode = OpCodes.Ceq;
2562 case Operator.BitwiseOr:
2563 opcode = OpCodes.Or;
2566 case Operator.BitwiseAnd:
2567 opcode = OpCodes.And;
2570 case Operator.ExclusiveOr:
2571 opcode = OpCodes.Xor;
2575 throw new InternalErrorException (oper.ToString ());
2581 static bool IsUnsigned (TypeSpec t)
2583 switch (t.BuiltinType) {
2584 case BuiltinTypeSpec.Type.Char:
2585 case BuiltinTypeSpec.Type.UInt:
2586 case BuiltinTypeSpec.Type.ULong:
2587 case BuiltinTypeSpec.Type.UShort:
2588 case BuiltinTypeSpec.Type.Byte:
2595 static bool IsFloat (TypeSpec t)
2597 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2600 Expression ResolveOperator (ResolveContext ec)
2602 TypeSpec l = left.Type;
2603 TypeSpec r = right.Type;
2605 bool primitives_only = false;
2608 // Handles predefined primitive types
2610 if (BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r)) {
2611 if ((oper & Operator.ShiftMask) == 0) {
2612 if (l.BuiltinType != BuiltinTypeSpec.Type.Bool && !DoBinaryOperatorPromotion (ec))
2615 primitives_only = true;
2619 if (l.IsPointer || r.IsPointer)
2620 return ResolveOperatorPointer (ec, l, r);
2623 bool lenum = l.IsEnum;
2624 bool renum = r.IsEnum;
2625 if (lenum || renum) {
2626 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2633 if ((oper == Operator.Addition || oper == Operator.Subtraction) && (l.IsDelegate || r.IsDelegate)) {
2635 expr = ResolveOperatorDelegate (ec, l, r);
2637 // TODO: Can this be ambiguous
2643 expr = ResolveUserOperator (ec, left, right);
2647 // Predefined reference types equality
2648 if ((oper & Operator.EqualityMask) != 0) {
2649 expr = ResolveOperatorEquality (ec, l, r);
2655 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, primitives_only, null);
2658 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2659 // if 'left' is not an enumeration constant, create one from the type of 'right'
2660 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2663 case Operator.BitwiseOr:
2664 case Operator.BitwiseAnd:
2665 case Operator.ExclusiveOr:
2666 case Operator.Equality:
2667 case Operator.Inequality:
2668 case Operator.LessThan:
2669 case Operator.LessThanOrEqual:
2670 case Operator.GreaterThan:
2671 case Operator.GreaterThanOrEqual:
2672 if (left.Type.IsEnum)
2675 if (left.IsZeroInteger)
2676 return left.Reduce (ec, right.Type);
2680 case Operator.Addition:
2681 case Operator.Subtraction:
2684 case Operator.Multiply:
2685 case Operator.Division:
2686 case Operator.Modulus:
2687 case Operator.LeftShift:
2688 case Operator.RightShift:
2689 if (right.Type.IsEnum || left.Type.IsEnum)
2698 // The `|' operator used on types which were extended is dangerous
2700 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2702 OpcodeCast lcast = left as OpcodeCast;
2703 if (lcast != null) {
2704 if (IsUnsigned (lcast.UnderlyingType))
2708 OpcodeCast rcast = right as OpcodeCast;
2709 if (rcast != null) {
2710 if (IsUnsigned (rcast.UnderlyingType))
2714 if (lcast == null && rcast == null)
2717 // FIXME: consider constants
2719 ec.Report.Warning (675, 3, loc,
2720 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2721 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2724 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
2726 return new PredefinedOperator[] {
2728 // Pointer arithmetic:
2730 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2731 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2732 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2733 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2735 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
2736 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
2737 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
2738 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
2741 // T* operator + (int y, T* x);
2742 // T* operator + (uint y, T *x);
2743 // T* operator + (long y, T *x);
2744 // T* operator + (ulong y, T *x);
2746 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
2747 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
2748 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
2749 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
2752 // long operator - (T* x, T *y)
2754 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
2758 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
2760 TypeSpec bool_type = types.Bool;
2761 return new PredefinedOperator[] {
2762 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask),
2763 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
2764 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
2765 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
2766 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
2767 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
2768 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
2770 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
2771 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
2772 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
2773 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
2774 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
2775 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
2776 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
2778 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
2779 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
2780 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
2782 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
2784 new PredefinedShiftOperator (types.Int, types.Int, Operator.ShiftMask),
2785 new PredefinedShiftOperator (types.UInt, types.Int, Operator.ShiftMask),
2786 new PredefinedShiftOperator (types.Long, types.Int, Operator.ShiftMask),
2787 new PredefinedShiftOperator (types.ULong, types.Int, Operator.ShiftMask)
2791 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
2793 TypeSpec bool_type = types.Bool;
2795 return new PredefinedOperator[] {
2796 new PredefinedEqualityOperator (types.String, bool_type),
2797 new PredefinedEqualityOperator (types.Delegate, bool_type),
2798 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type)
2803 // Rules used during binary numeric promotion
2805 static bool DoNumericPromotion (ResolveContext rc, ref Expression prim_expr, ref Expression second_expr, TypeSpec type)
2809 Constant c = prim_expr as Constant;
2811 temp = c.ConvertImplicitly (type);
2818 if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
2819 switch (prim_expr.Type.BuiltinType) {
2820 case BuiltinTypeSpec.Type.Int:
2821 case BuiltinTypeSpec.Type.Short:
2822 case BuiltinTypeSpec.Type.SByte:
2823 case BuiltinTypeSpec.Type.Long:
2824 type = rc.BuiltinTypes.Long;
2826 if (type != second_expr.Type) {
2827 c = second_expr as Constant;
2829 temp = c.ConvertImplicitly (type);
2831 temp = Convert.ImplicitNumericConversion (second_expr, type);
2838 } else if (type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
2840 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2842 switch (type.BuiltinType) {
2843 case BuiltinTypeSpec.Type.Int:
2844 case BuiltinTypeSpec.Type.Long:
2845 case BuiltinTypeSpec.Type.Short:
2846 case BuiltinTypeSpec.Type.SByte:
2851 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2860 // 7.2.6.2 Binary numeric promotions
2862 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2864 TypeSpec ltype = left.Type;
2865 TypeSpec rtype = right.Type;
2868 foreach (TypeSpec t in ec.BuiltinTypes.BinaryPromotionsTypes) {
2870 return t == rtype || DoNumericPromotion (ec, ref right, ref left, t);
2873 return t == ltype || DoNumericPromotion (ec, ref left, ref right, t);
2876 TypeSpec int32 = ec.BuiltinTypes.Int;
2877 if (ltype != int32) {
2878 Constant c = left as Constant;
2880 temp = c.ConvertImplicitly (int32);
2882 temp = Convert.ImplicitNumericConversion (left, int32);
2889 if (rtype != int32) {
2890 Constant c = right as Constant;
2892 temp = c.ConvertImplicitly (int32);
2894 temp = Convert.ImplicitNumericConversion (right, int32);
2904 protected override Expression DoResolve (ResolveContext ec)
2909 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2910 left = ((ParenthesizedExpression) left).Expr;
2911 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2915 if (left.eclass == ExprClass.Type) {
2916 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2920 left = left.Resolve (ec);
2925 Constant lc = left as Constant;
2927 if (lc != null && lc.Type.BuiltinType == BuiltinTypeSpec.Type.Bool &&
2928 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2929 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2931 // FIXME: resolve right expression as unreachable
2932 // right.Resolve (ec);
2934 ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2938 right = right.Resolve (ec);
2942 eclass = ExprClass.Value;
2943 Constant rc = right as Constant;
2945 // The conversion rules are ignored in enum context but why
2946 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
2947 lc = EnumLiftUp (ec, lc, rc, loc);
2949 rc = EnumLiftUp (ec, rc, lc, loc);
2952 if (rc != null && lc != null) {
2953 int prev_e = ec.Report.Errors;
2954 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
2955 if (e != null || ec.Report.Errors != prev_e)
2959 // Comparison warnings
2960 if ((oper & Operator.ComparisonMask) != 0) {
2961 if (left.Equals (right)) {
2962 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2964 CheckOutOfRangeComparison (ec, lc, right.Type);
2965 CheckOutOfRangeComparison (ec, rc, left.Type);
2968 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2970 var rt = right.Type;
2971 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
2972 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
2973 Error_OperatorCannotBeApplied (ec, left, right);
2980 // Special handling for logical boolean operators which require rhs not to be
2981 // evaluated based on lhs value
2983 if ((oper & Operator.LogicalMask) != 0) {
2984 Expression cond_left, cond_right, expr;
2986 args = new Arguments (2);
2988 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2989 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, ec.CurrentBlock, loc);
2991 var cond_args = new Arguments (1);
2992 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left).Resolve (ec)));
2995 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
2996 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
2998 left = temp.CreateReferenceExpression (ec, loc);
2999 if (oper == Operator.LogicalAnd) {
3000 expr = DynamicUnaryConversion.CreateIsFalse (ec, cond_args, loc);
3003 expr = DynamicUnaryConversion.CreateIsTrue (ec, cond_args, loc);
3007 args.Add (new Argument (left));
3008 args.Add (new Argument (right));
3009 cond_right = new DynamicExpressionStatement (this, args, loc);
3011 LocalVariable temp = LocalVariable.CreateCompilerGenerated (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
3013 args.Add (new Argument (temp.CreateReferenceExpression (ec, loc).Resolve (ec)));
3014 args.Add (new Argument (right));
3015 right = new DynamicExpressionStatement (this, args, loc);
3018 // bool && dynamic => (temp = left) ? temp && right : temp;
3019 // bool || dynamic => (temp = left) ? temp : temp || right;
3021 if (oper == Operator.LogicalAnd) {
3023 cond_right = temp.CreateReferenceExpression (ec, loc);
3025 cond_left = temp.CreateReferenceExpression (ec, loc);
3029 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left));
3032 return new Conditional (expr, cond_left, cond_right, loc).Resolve (ec);
3035 args = new Arguments (2);
3036 args.Add (new Argument (left));
3037 args.Add (new Argument (right));
3038 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
3041 if (ec.Module.Compiler.Settings.Version >= LanguageVersion.ISO_2 &&
3042 ((left.Type.IsNullableType && (right is NullLiteral || right.Type.IsNullableType || TypeSpec.IsValueType (right.Type))) ||
3043 (TypeSpec.IsValueType (left.Type) && right is NullLiteral) ||
3044 (right.Type.IsNullableType && (left is NullLiteral || left.Type.IsNullableType || TypeSpec.IsValueType (left.Type))) ||
3045 (TypeSpec.IsValueType (right.Type) && left is NullLiteral))) {
3046 var lifted = new Nullable.LiftedBinaryOperator (oper, left, right);
3047 lifted.state = state;
3048 return lifted.Resolve (ec);
3051 return DoResolveCore (ec, left, right);
3054 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3056 Expression expr = ResolveOperator (ec);
3058 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3060 if (left == null || right == null)
3061 throw new InternalErrorException ("Invalid conversion");
3063 if (oper == Operator.BitwiseOr)
3064 CheckBitwiseOrOnSignExtended (ec);
3069 public override SLE.Expression MakeExpression (BuilderContext ctx)
3071 var le = left.MakeExpression (ctx);
3072 var re = right.MakeExpression (ctx);
3073 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3076 case Operator.Addition:
3077 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3078 case Operator.BitwiseAnd:
3079 return SLE.Expression.And (le, re);
3080 case Operator.BitwiseOr:
3081 return SLE.Expression.Or (le, re);
3082 case Operator.Division:
3083 return SLE.Expression.Divide (le, re);
3084 case Operator.Equality:
3085 return SLE.Expression.Equal (le, re);
3086 case Operator.ExclusiveOr:
3087 return SLE.Expression.ExclusiveOr (le, re);
3088 case Operator.GreaterThan:
3089 return SLE.Expression.GreaterThan (le, re);
3090 case Operator.GreaterThanOrEqual:
3091 return SLE.Expression.GreaterThanOrEqual (le, re);
3092 case Operator.Inequality:
3093 return SLE.Expression.NotEqual (le, re);
3094 case Operator.LeftShift:
3095 return SLE.Expression.LeftShift (le, re);
3096 case Operator.LessThan:
3097 return SLE.Expression.LessThan (le, re);
3098 case Operator.LessThanOrEqual:
3099 return SLE.Expression.LessThanOrEqual (le, re);
3100 case Operator.LogicalAnd:
3101 return SLE.Expression.AndAlso (le, re);
3102 case Operator.LogicalOr:
3103 return SLE.Expression.OrElse (le, re);
3104 case Operator.Modulus:
3105 return SLE.Expression.Modulo (le, re);
3106 case Operator.Multiply:
3107 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3108 case Operator.RightShift:
3109 return SLE.Expression.RightShift (le, re);
3110 case Operator.Subtraction:
3111 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3113 throw new NotImplementedException (oper.ToString ());
3118 // D operator + (D x, D y)
3119 // D operator - (D x, D y)
3121 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3123 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3125 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3126 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3131 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3132 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3142 MethodSpec method = null;
3143 Arguments args = new Arguments (2);
3144 args.Add (new Argument (left));
3145 args.Add (new Argument (right));
3147 if (oper == Operator.Addition) {
3148 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3149 } else if (oper == Operator.Subtraction) {
3150 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3154 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3156 MethodGroupExpr mg = MethodGroupExpr.CreatePredefined (method, ec.BuiltinTypes.Delegate, loc);
3157 Expression expr = new UserOperatorCall (mg.BestCandidate, args, CreateExpressionTree, loc);
3158 return new ClassCast (expr, l);
3162 // Enumeration operators
3164 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3167 // bool operator == (E x, E y);
3168 // bool operator != (E x, E y);
3169 // bool operator < (E x, E y);
3170 // bool operator > (E x, E y);
3171 // bool operator <= (E x, E y);
3172 // bool operator >= (E x, E y);
3174 // E operator & (E x, E y);
3175 // E operator | (E x, E y);
3176 // E operator ^ (E x, E y);
3178 // U operator - (E e, E f)
3179 // E operator - (E e, U x)
3180 // E operator - (U x, E e) // LAMESPEC: Not covered by the specification
3182 // E operator + (E e, U x)
3183 // E operator + (U x, E e)
3185 Expression ltemp = left;
3186 Expression rtemp = right;
3187 TypeSpec underlying_type;
3188 TypeSpec underlying_type_result;
3193 // LAMESPEC: There is never ambiguous conversion between enum operators
3194 // the one which contains more enum parameters always wins even if there
3195 // is an implicit conversion involved
3197 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3199 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3200 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
3207 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3208 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
3218 if ((oper & Operator.BitwiseMask) != 0) {
3220 underlying_type_result = underlying_type;
3223 underlying_type_result = null;
3225 } else if (oper == Operator.Subtraction) {
3227 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3228 if (ltype != rtype) {
3229 expr = Convert.ImplicitConversion (ec, left, rtype, left.Location);
3231 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3237 res_type = underlying_type;
3242 res_type = underlying_type;
3245 underlying_type_result = underlying_type;
3247 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3248 expr = Convert.ImplicitConversion (ec, right, ltype, right.Location);
3249 if (expr == null || expr is EnumConstant) {
3250 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3256 res_type = underlying_type;
3260 underlying_type_result = underlying_type;
3264 } else if (oper == Operator.Addition) {
3266 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3269 if (rtype != underlying_type && (state & (State.RightNullLifted | State.LeftNullLifted)) == 0) {
3270 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3277 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3279 if (ltype != underlying_type) {
3280 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3288 underlying_type_result = underlying_type;
3293 // Unwrap the constant correctly, so DoBinaryOperatorPromotion can do the magic
3294 // with constants and expressions
3295 if (left.Type != underlying_type) {
3296 if (left is Constant)
3297 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
3299 left = EmptyCast.Create (left, underlying_type);
3302 if (right.Type != underlying_type) {
3303 if (right is Constant)
3304 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
3306 right = EmptyCast.Create (right, underlying_type);
3310 // C# specification uses explicit cast syntax which means binary promotion
3311 // should happen, however it seems that csc does not do that
3313 if (!DoBinaryOperatorPromotion (ec)) {
3319 if (underlying_type_result != null && left.Type != underlying_type_result) {
3320 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (left.Type), underlying_type_result);
3323 expr = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, true, res_type);
3335 // If the return type of the selected operator is implicitly convertible to the type of x
3337 if (Convert.ImplicitConversionExists (ec, expr, ltype))
3341 // Otherwise, if the selected operator is a predefined operator, if the return type of the
3342 // selected operator is explicitly convertible to the type of x, and if y is implicitly
3343 // convertible to the type of x or the operator is a shift operator, then the operation
3344 // is evaluated as x = (T)(x op y), where T is the type of x
3346 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
3350 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
3357 // 7.9.6 Reference type equality operators
3359 Expression ResolveOperatorEquality (ResolveContext ec, TypeSpec l, TypeSpec r)
3362 type = ec.BuiltinTypes.Bool;
3365 // a, Both operands are reference-type values or the value null
3366 // b, One operand is a value of type T where T is a type-parameter and
3367 // the other operand is the value null. Furthermore T does not have the
3368 // value type constraint
3370 // LAMESPEC: Very confusing details in the specification, basically any
3371 // reference like type-parameter is allowed
3373 var tparam_l = l as TypeParameterSpec;
3374 var tparam_r = r as TypeParameterSpec;
3375 if (tparam_l != null) {
3376 if (right is NullLiteral && !tparam_l.HasSpecialStruct) {
3377 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3381 if (!tparam_l.IsReferenceType)
3384 l = tparam_l.GetEffectiveBase ();
3385 left = new BoxedCast (left, l);
3386 } else if (left is NullLiteral && tparam_r == null) {
3387 if (!TypeSpec.IsReferenceType (r) || r.Kind == MemberKind.InternalCompilerType)
3393 if (tparam_r != null) {
3394 if (left is NullLiteral && !tparam_r.HasSpecialStruct) {
3395 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3399 if (!tparam_r.IsReferenceType)
3402 r = tparam_r.GetEffectiveBase ();
3403 right = new BoxedCast (right, r);
3404 } else if (right is NullLiteral) {
3405 if (!TypeSpec.IsReferenceType (l) || l.Kind == MemberKind.InternalCompilerType)
3411 bool no_arg_conv = false;
3414 // LAMESPEC: method groups can be compared when they convert to other side delegate
3417 if (right.eclass == ExprClass.MethodGroup) {
3418 result = Convert.ImplicitConversion (ec, right, l, loc);
3424 } else if (r.IsDelegate && l != r) {
3427 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3428 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3435 no_arg_conv = l == r && !l.IsStruct;
3439 // bool operator != (string a, string b)
3440 // bool operator == (string a, string b)
3442 // bool operator != (Delegate a, Delegate b)
3443 // bool operator == (Delegate a, Delegate b)
3445 // bool operator != (bool a, bool b)
3446 // bool operator == (bool a, bool b)
3448 // LAMESPEC: Reference equality comparison can apply to value/reference types when
3449 // they implement an implicit conversion to any of types above. This does
3450 // not apply when both operands are of same reference type
3452 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3453 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv, null);
3459 // bool operator != (object a, object b)
3460 // bool operator == (object a, object b)
3462 // An explicit reference conversion exists from the
3463 // type of either operand to the type of the other operand.
3466 // Optimize common path
3468 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3471 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3472 !Convert.ExplicitReferenceConversionExists (r, l))
3475 // Reject allowed explicit conversions like int->object
3476 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
3479 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3480 ec.Report.Warning (253, 2, loc,
3481 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3482 l.GetSignatureForError ());
3484 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3485 ec.Report.Warning (252, 2, loc,
3486 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3487 r.GetSignatureForError ());
3493 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3496 // bool operator == (void* x, void* y);
3497 // bool operator != (void* x, void* y);
3498 // bool operator < (void* x, void* y);
3499 // bool operator > (void* x, void* y);
3500 // bool operator <= (void* x, void* y);
3501 // bool operator >= (void* x, void* y);
3503 if ((oper & Operator.ComparisonMask) != 0) {
3506 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3513 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3519 type = ec.BuiltinTypes.Bool;
3523 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false, null);
3527 // Build-in operators method overloading
3529 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, TypeSpec enum_type)
3531 PredefinedOperator best_operator = null;
3532 TypeSpec l = left.Type;
3533 TypeSpec r = right.Type;
3534 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3536 foreach (PredefinedOperator po in operators) {
3537 if ((po.OperatorsMask & oper_mask) == 0)
3540 if (primitives_only) {
3541 if (!po.IsPrimitiveApplicable (l, r))
3544 if (!po.IsApplicable (ec, left, right))
3548 if (best_operator == null) {
3550 if (primitives_only)
3556 best_operator = po.ResolveBetterOperator (ec, best_operator);
3558 if (best_operator == null) {
3559 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3560 OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
3567 if (best_operator == null)
3570 Expression expr = best_operator.ConvertResult (ec, this);
3573 // Optimize &/&& constant expressions with 0 value
3575 if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
3576 Constant rc = right as Constant;
3577 Constant lc = left as Constant;
3578 if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
3580 // The result is a constant with side-effect
3582 Constant side_effect = rc == null ?
3583 new SideEffectConstant (lc, right, loc) :
3584 new SideEffectConstant (rc, left, loc);
3586 return ReducedExpression.Create (side_effect, expr);
3590 if (enum_type == null)
3594 // HACK: required by enum_conversion
3596 expr.Type = enum_type;
3597 return EmptyCast.Create (expr, enum_type);
3601 // Performs user-operator overloading
3603 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression left, Expression right)
3605 var op = ConvertBinaryToUserOperator (oper);
3607 if (l.IsNullableType)
3608 l = Nullable.NullableInfo.GetUnderlyingType (l);
3610 if (r.IsNullableType)
3611 r = Nullable.NullableInfo.GetUnderlyingType (r);
3613 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
3614 IList<MemberSpec> right_operators = null;
3617 right_operators = MemberCache.GetUserOperator (r, op, false);
3618 if (right_operators == null && left_operators == null)
3620 } else if (left_operators == null) {
3624 Arguments args = new Arguments (2);
3625 Argument larg = new Argument (left);
3627 Argument rarg = new Argument (right);
3631 // User-defined operator implementations always take precedence
3632 // over predefined operator implementations
3634 if (left_operators != null && right_operators != null) {
3635 left_operators = CombineUserOperators (left_operators, right_operators);
3636 } else if (right_operators != null) {
3637 left_operators = right_operators;
3640 var res = new OverloadResolver (left_operators, OverloadResolver.Restrictions.ProbingOnly |
3641 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded, loc);
3643 var oper_method = res.ResolveOperator (ec, ref args);
3644 if (oper_method == null)
3647 var llifted = (state & State.LeftNullLifted) != 0;
3648 var rlifted = (state & State.RightNullLifted) != 0;
3649 if ((Oper & Operator.EqualityMask) != 0) {
3650 var parameters = oper_method.Parameters;
3651 // LAMESPEC: No idea why this is not allowed
3652 if ((left is Nullable.Unwrap || right is Nullable.Unwrap) && parameters.Types [0] != parameters.Types [1])
3655 // Binary operation was lifted but we have found a user operator
3656 // which requires value-type argument, we downgrade ourself back to
3658 // LAMESPEC: The user operator is not called (it cannot be we are passing null to struct)
3659 // but compilation succeeds
3660 if ((llifted && !parameters.Types[0].IsStruct) || (rlifted && !parameters.Types[1].IsStruct)) {
3661 state &= ~(State.LeftNullLifted | State.RightNullLifted);
3665 Expression oper_expr;
3667 // TODO: CreateExpressionTree is allocated every time
3668 if ((oper & Operator.LogicalMask) != 0) {
3669 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
3670 oper == Operator.LogicalAnd, loc).Resolve (ec);
3672 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
3676 this.left = larg.Expr;
3679 this.right = rarg.Expr;
3685 // Merge two sets of user operators into one, they are mostly distinguish
3686 // except when they share base type and it contains an operator
3688 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
3690 var combined = new List<MemberSpec> (left.Count + right.Count);
3691 combined.AddRange (left);
3692 foreach (var r in right) {
3694 foreach (var l in left) {
3695 if (l.DeclaringType == r.DeclaringType) {
3708 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
3710 if (c is IntegralConstant || c is CharConstant) {
3712 c.ConvertExplicitly (true, type);
3713 } catch (OverflowException) {
3714 ec.Report.Warning (652, 2, loc,
3715 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
3716 TypeManager.CSharpName (type));
3722 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3723 /// context of a conditional bool expression. This function will return
3724 /// false if it is was possible to use EmitBranchable, or true if it was.
3726 /// The expression's code is generated, and we will generate a branch to `target'
3727 /// if the resulting expression value is equal to isTrue
3729 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3732 // This is more complicated than it looks, but its just to avoid
3733 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3734 // but on top of that we want for == and != to use a special path
3735 // if we are comparing against null
3737 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
3738 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3741 // put the constant on the rhs, for simplicity
3743 if (left is Constant) {
3744 Expression swap = right;
3750 // brtrue/brfalse works with native int only
3752 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
3753 left.EmitBranchable (ec, target, my_on_true);
3756 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
3757 // right is a boolean, and it's not 'false' => it is 'true'
3758 left.EmitBranchable (ec, target, !my_on_true);
3762 } else if (oper == Operator.LogicalAnd) {
3765 Label tests_end = ec.DefineLabel ();
3767 left.EmitBranchable (ec, tests_end, false);
3768 right.EmitBranchable (ec, target, true);
3769 ec.MarkLabel (tests_end);
3772 // This optimizes code like this
3773 // if (true && i > 4)
3775 if (!(left is Constant))
3776 left.EmitBranchable (ec, target, false);
3778 if (!(right is Constant))
3779 right.EmitBranchable (ec, target, false);
3784 } else if (oper == Operator.LogicalOr){
3786 left.EmitBranchable (ec, target, true);
3787 right.EmitBranchable (ec, target, true);
3790 Label tests_end = ec.DefineLabel ();
3791 left.EmitBranchable (ec, tests_end, true);
3792 right.EmitBranchable (ec, target, false);
3793 ec.MarkLabel (tests_end);
3798 } else if ((oper & Operator.ComparisonMask) == 0) {
3799 base.EmitBranchable (ec, target, on_true);
3806 TypeSpec t = left.Type;
3807 bool is_float = IsFloat (t);
3808 bool is_unsigned = is_float || IsUnsigned (t);
3811 case Operator.Equality:
3813 ec.Emit (OpCodes.Beq, target);
3815 ec.Emit (OpCodes.Bne_Un, target);
3818 case Operator.Inequality:
3820 ec.Emit (OpCodes.Bne_Un, target);
3822 ec.Emit (OpCodes.Beq, target);
3825 case Operator.LessThan:
3827 if (is_unsigned && !is_float)
3828 ec.Emit (OpCodes.Blt_Un, target);
3830 ec.Emit (OpCodes.Blt, target);
3833 ec.Emit (OpCodes.Bge_Un, target);
3835 ec.Emit (OpCodes.Bge, target);
3838 case Operator.GreaterThan:
3840 if (is_unsigned && !is_float)
3841 ec.Emit (OpCodes.Bgt_Un, target);
3843 ec.Emit (OpCodes.Bgt, target);
3846 ec.Emit (OpCodes.Ble_Un, target);
3848 ec.Emit (OpCodes.Ble, target);
3851 case Operator.LessThanOrEqual:
3853 if (is_unsigned && !is_float)
3854 ec.Emit (OpCodes.Ble_Un, target);
3856 ec.Emit (OpCodes.Ble, target);
3859 ec.Emit (OpCodes.Bgt_Un, target);
3861 ec.Emit (OpCodes.Bgt, target);
3865 case Operator.GreaterThanOrEqual:
3867 if (is_unsigned && !is_float)
3868 ec.Emit (OpCodes.Bge_Un, target);
3870 ec.Emit (OpCodes.Bge, target);
3873 ec.Emit (OpCodes.Blt_Un, target);
3875 ec.Emit (OpCodes.Blt, target);
3878 throw new InternalErrorException (oper.ToString ());
3882 public override void Emit (EmitContext ec)
3884 EmitOperator (ec, left.Type);
3887 protected virtual void EmitOperator (EmitContext ec, TypeSpec l)
3889 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
3890 left = left.EmitToField (ec);
3892 if ((oper & Operator.LogicalMask) == 0) {
3893 right = right.EmitToField (ec);
3898 // Handle short-circuit operators differently
3901 if ((oper & Operator.LogicalMask) != 0) {
3902 Label load_result = ec.DefineLabel ();
3903 Label end = ec.DefineLabel ();
3905 bool is_or = oper == Operator.LogicalOr;
3906 left.EmitBranchable (ec, load_result, is_or);
3908 ec.Emit (OpCodes.Br_S, end);
3910 ec.MarkLabel (load_result);
3911 ec.EmitInt (is_or ? 1 : 0);
3917 // Optimize zero-based operations which cannot be optimized at expression level
3919 if (oper == Operator.Subtraction) {
3920 var lc = left as IntegralConstant;
3921 if (lc != null && lc.IsDefaultValue) {
3923 ec.Emit (OpCodes.Neg);
3930 EmitOperatorOpcode (ec, oper, l);
3933 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3934 // expression because that would wrap lifted binary operation
3936 if (enum_conversion != null)
3937 enum_conversion.Emit (ec);
3940 public override void EmitSideEffect (EmitContext ec)
3942 if ((oper & Operator.LogicalMask) != 0 ||
3943 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3944 base.EmitSideEffect (ec);
3946 left.EmitSideEffect (ec);
3947 right.EmitSideEffect (ec);
3951 public override Expression EmitToField (EmitContext ec)
3953 if ((oper & Operator.LogicalMask) == 0) {
3954 var await_expr = left as Await;
3955 if (await_expr != null && right.IsSideEffectFree) {
3956 await_expr.Statement.EmitPrologue (ec);
3957 left = await_expr.Statement.GetResultExpression (ec);
3961 await_expr = right as Await;
3962 if (await_expr != null && left.IsSideEffectFree) {
3963 await_expr.Statement.EmitPrologue (ec);
3964 right = await_expr.Statement.GetResultExpression (ec);
3969 return base.EmitToField (ec);
3972 protected override void CloneTo (CloneContext clonectx, Expression t)
3974 Binary target = (Binary) t;
3976 target.left = left.Clone (clonectx);
3977 target.right = right.Clone (clonectx);
3980 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3982 Arguments binder_args = new Arguments (4);
3984 MemberAccess sle = new MemberAccess (new MemberAccess (
3985 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3987 CSharpBinderFlags flags = 0;
3988 if (ec.HasSet (ResolveContext.Options.CheckedScope))
3989 flags = CSharpBinderFlags.CheckedContext;
3991 if ((oper & Operator.LogicalMask) != 0)
3992 flags |= CSharpBinderFlags.BinaryOperationLogical;
3994 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
3995 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3996 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
3997 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
3999 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
4002 public override Expression CreateExpressionTree (ResolveContext ec)
4004 return CreateExpressionTree (ec, null);
4007 Expression CreateExpressionTree (ResolveContext ec, Expression method)
4010 bool lift_arg = false;
4013 case Operator.Addition:
4014 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4015 method_name = "AddChecked";
4017 method_name = "Add";
4019 case Operator.BitwiseAnd:
4020 method_name = "And";
4022 case Operator.BitwiseOr:
4025 case Operator.Division:
4026 method_name = "Divide";
4028 case Operator.Equality:
4029 method_name = "Equal";
4032 case Operator.ExclusiveOr:
4033 method_name = "ExclusiveOr";
4035 case Operator.GreaterThan:
4036 method_name = "GreaterThan";
4039 case Operator.GreaterThanOrEqual:
4040 method_name = "GreaterThanOrEqual";
4043 case Operator.Inequality:
4044 method_name = "NotEqual";
4047 case Operator.LeftShift:
4048 method_name = "LeftShift";
4050 case Operator.LessThan:
4051 method_name = "LessThan";
4054 case Operator.LessThanOrEqual:
4055 method_name = "LessThanOrEqual";
4058 case Operator.LogicalAnd:
4059 method_name = "AndAlso";
4061 case Operator.LogicalOr:
4062 method_name = "OrElse";
4064 case Operator.Modulus:
4065 method_name = "Modulo";
4067 case Operator.Multiply:
4068 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4069 method_name = "MultiplyChecked";
4071 method_name = "Multiply";
4073 case Operator.RightShift:
4074 method_name = "RightShift";
4076 case Operator.Subtraction:
4077 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4078 method_name = "SubtractChecked";
4080 method_name = "Subtract";
4084 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4087 Arguments args = new Arguments (2);
4088 args.Add (new Argument (left.CreateExpressionTree (ec)));
4089 args.Add (new Argument (right.CreateExpressionTree (ec)));
4090 if (method != null) {
4092 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4094 args.Add (new Argument (method));
4097 return CreateExpressionFactoryCall (ec, method_name, args);
4100 public override object Accept (StructuralVisitor visitor)
4102 return visitor.Visit (this);
4108 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4109 // b, c, d... may be strings or objects.
4111 public class StringConcat : Expression
4113 Arguments arguments;
4115 StringConcat (Location loc)
4118 arguments = new Arguments (2);
4121 public override bool ContainsEmitWithAwait ()
4123 return arguments.ContainsEmitWithAwait ();
4126 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4128 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4129 throw new ArgumentException ();
4131 var s = new StringConcat (loc);
4132 s.type = rc.BuiltinTypes.String;
4133 s.eclass = ExprClass.Value;
4135 s.Append (rc, left);
4136 s.Append (rc, right);
4140 public override Expression CreateExpressionTree (ResolveContext ec)
4142 Argument arg = arguments [0];
4143 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4147 // Creates nested calls tree from an array of arguments used for IL emit
4149 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4151 Arguments concat_args = new Arguments (2);
4152 Arguments add_args = new Arguments (3);
4154 concat_args.Add (left);
4155 add_args.Add (new Argument (left_etree));
4157 concat_args.Add (arguments [pos]);
4158 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4160 var methods = GetConcatMethodCandidates ();
4161 if (methods == null)
4164 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4165 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4169 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4171 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4172 if (++pos == arguments.Count)
4175 left = new Argument (new EmptyExpression (method.ReturnType));
4176 return CreateExpressionAddCall (ec, left, expr, pos);
4179 protected override Expression DoResolve (ResolveContext ec)
4184 void Append (ResolveContext rc, Expression operand)
4189 StringConstant sc = operand as StringConstant;
4191 if (arguments.Count != 0) {
4192 Argument last_argument = arguments [arguments.Count - 1];
4193 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4194 if (last_expr_constant != null) {
4195 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4201 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4203 StringConcat concat_oper = operand as StringConcat;
4204 if (concat_oper != null) {
4205 arguments.AddRange (concat_oper.arguments);
4210 arguments.Add (new Argument (operand));
4213 IList<MemberSpec> GetConcatMethodCandidates ()
4215 return MemberCache.FindMembers (type, "Concat", true);
4218 public override void Emit (EmitContext ec)
4220 // Optimize by removing any extra null arguments, they are no-op
4221 for (int i = 0; i < arguments.Count; ++i) {
4222 if (arguments[i].Expr is NullConstant)
4223 arguments.RemoveAt (i--);
4226 var members = GetConcatMethodCandidates ();
4227 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4228 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4229 if (method != null) {
4230 var call = new CallEmitter ();
4231 call.EmitPredefined (ec, method, arguments);
4235 public override SLE.Expression MakeExpression (BuilderContext ctx)
4237 if (arguments.Count != 2)
4238 throw new NotImplementedException ("arguments.Count != 2");
4240 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4241 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4246 // User-defined conditional logical operator
4248 public class ConditionalLogicalOperator : UserOperatorCall
4250 readonly bool is_and;
4251 Expression oper_expr;
4253 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4254 : base (oper, arguments, expr_tree, loc)
4256 this.is_and = is_and;
4257 eclass = ExprClass.Unresolved;
4260 protected override Expression DoResolve (ResolveContext ec)
4262 AParametersCollection pd = oper.Parameters;
4263 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4264 ec.Report.Error (217, loc,
4265 "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",
4266 oper.GetSignatureForError ());
4270 Expression left_dup = new EmptyExpression (type);
4271 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4272 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4273 if (op_true == null || op_false == null) {
4274 ec.Report.Error (218, loc,
4275 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4276 TypeManager.CSharpName (type), oper.GetSignatureForError ());
4280 oper_expr = is_and ? op_false : op_true;
4281 eclass = ExprClass.Value;
4285 public override void Emit (EmitContext ec)
4287 Label end_target = ec.DefineLabel ();
4290 // Emit and duplicate left argument
4292 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
4293 if (right_contains_await) {
4294 arguments[0] = arguments[0].EmitToField (ec, false);
4295 arguments[0].Expr.Emit (ec);
4297 arguments[0].Expr.Emit (ec);
4298 ec.Emit (OpCodes.Dup);
4299 arguments.RemoveAt (0);
4302 oper_expr.EmitBranchable (ec, end_target, true);
4306 if (right_contains_await) {
4308 // Special handling when right expression contains await and left argument
4309 // could not be left on stack before logical branch
4311 Label skip_left_load = ec.DefineLabel ();
4312 ec.Emit (OpCodes.Br_S, skip_left_load);
4313 ec.MarkLabel (end_target);
4314 arguments[0].Expr.Emit (ec);
4315 ec.MarkLabel (skip_left_load);
4317 ec.MarkLabel (end_target);
4322 public class PointerArithmetic : Expression {
4323 Expression left, right;
4327 // We assume that `l' is always a pointer
4329 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4338 public override bool ContainsEmitWithAwait ()
4340 throw new NotImplementedException ();
4343 public override Expression CreateExpressionTree (ResolveContext ec)
4345 Error_PointerInsideExpressionTree (ec);
4349 protected override Expression DoResolve (ResolveContext ec)
4351 eclass = ExprClass.Variable;
4353 var pc = left.Type as PointerContainer;
4354 if (pc != null && pc.Element.Kind == MemberKind.Void) {
4355 Error_VoidPointerOperation (ec);
4362 public override void Emit (EmitContext ec)
4364 TypeSpec op_type = left.Type;
4366 // It must be either array or fixed buffer
4368 if (TypeManager.HasElementType (op_type)) {
4369 element = TypeManager.GetElementType (op_type);
4371 FieldExpr fe = left as FieldExpr;
4373 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
4378 int size = BuiltinTypeSpec.GetSize(element);
4379 TypeSpec rtype = right.Type;
4381 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4383 // handle (pointer - pointer)
4387 ec.Emit (OpCodes.Sub);
4391 ec.Emit (OpCodes.Sizeof, element);
4394 ec.Emit (OpCodes.Div);
4396 ec.Emit (OpCodes.Conv_I8);
4399 // handle + and - on (pointer op int)
4401 Constant left_const = left as Constant;
4402 if (left_const != null) {
4404 // Optimize ((T*)null) pointer operations
4406 if (left_const.IsDefaultValue) {
4407 left = EmptyExpression.Null;
4415 var right_const = right as Constant;
4416 if (right_const != null) {
4418 // Optimize 0-based arithmetic
4420 if (right_const.IsDefaultValue)
4424 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
4426 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
4428 // TODO: Should be the checks resolve context sensitive?
4429 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
4430 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
4436 switch (rtype.BuiltinType) {
4437 case BuiltinTypeSpec.Type.SByte:
4438 case BuiltinTypeSpec.Type.Byte:
4439 case BuiltinTypeSpec.Type.Short:
4440 case BuiltinTypeSpec.Type.UShort:
4441 ec.Emit (OpCodes.Conv_I);
4443 case BuiltinTypeSpec.Type.UInt:
4444 ec.Emit (OpCodes.Conv_U);
4448 if (right_const == null && size != 1){
4450 ec.Emit (OpCodes.Sizeof, element);
4453 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4454 ec.Emit (OpCodes.Conv_I8);
4456 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4459 if (left_const == null) {
4460 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
4461 ec.Emit (OpCodes.Conv_I);
4462 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4463 ec.Emit (OpCodes.Conv_U);
4465 Binary.EmitOperatorOpcode (ec, op, op_type);
4472 // A boolean-expression is an expression that yields a result
4475 public class BooleanExpression : ShimExpression
4477 public BooleanExpression (Expression expr)
4480 this.loc = expr.Location;
4483 public override Expression CreateExpressionTree (ResolveContext ec)
4485 // TODO: We should emit IsTrue (v4) instead of direct user operator
4486 // call but that would break csc compatibility
4487 return base.CreateExpressionTree (ec);
4490 protected override Expression DoResolve (ResolveContext ec)
4492 // A boolean-expression is required to be of a type
4493 // that can be implicitly converted to bool or of
4494 // a type that implements operator true
4496 expr = expr.Resolve (ec);
4500 Assign ass = expr as Assign;
4501 if (ass != null && ass.Source is Constant) {
4502 ec.Report.Warning (665, 3, loc,
4503 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4506 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
4509 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4510 Arguments args = new Arguments (1);
4511 args.Add (new Argument (expr));
4512 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
4515 type = ec.BuiltinTypes.Bool;
4516 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4517 if (converted != null)
4521 // If no implicit conversion to bool exists, try using `operator true'
4523 converted = GetOperatorTrue (ec, expr, loc);
4524 if (converted == null) {
4525 expr.Error_ValueCannotBeConverted (ec, type, false);
4532 public override object Accept (StructuralVisitor visitor)
4534 return visitor.Visit (this);
4538 public class BooleanExpressionFalse : Unary
4540 public BooleanExpressionFalse (Expression expr)
4541 : base (Operator.LogicalNot, expr, expr.Location)
4545 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
4547 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
4552 /// Implements the ternary conditional operator (?:)
4554 public class Conditional : Expression {
4555 Expression expr, true_expr, false_expr;
4557 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
4560 this.true_expr = true_expr;
4561 this.false_expr = false_expr;
4567 public Expression Expr {
4573 public Expression TrueExpr {
4579 public Expression FalseExpr {
4587 public override bool ContainsEmitWithAwait ()
4589 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
4592 public override Expression CreateExpressionTree (ResolveContext ec)
4594 Arguments args = new Arguments (3);
4595 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4596 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4597 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4598 return CreateExpressionFactoryCall (ec, "Condition", args);
4601 protected override Expression DoResolve (ResolveContext ec)
4603 expr = expr.Resolve (ec);
4606 // Unreachable code needs different resolve path. For instance for await
4607 // expression to not generate unreachable resumable statement
4609 Constant c = expr as Constant;
4610 if (c != null && ec.CurrentBranching != null) {
4611 bool unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
4613 if (c.IsDefaultValue) {
4614 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
4615 true_expr = true_expr.Resolve (ec);
4616 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
4618 false_expr = false_expr.Resolve (ec);
4620 true_expr = true_expr.Resolve (ec);
4622 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
4623 false_expr = false_expr.Resolve (ec);
4624 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
4627 true_expr = true_expr.Resolve (ec);
4628 false_expr = false_expr.Resolve (ec);
4631 if (true_expr == null || false_expr == null || expr == null)
4634 eclass = ExprClass.Value;
4635 TypeSpec true_type = true_expr.Type;
4636 TypeSpec false_type = false_expr.Type;
4640 // First, if an implicit conversion exists from true_expr
4641 // to false_expr, then the result type is of type false_expr.Type
4643 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
4644 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4645 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
4647 // Check if both can convert implicitly to each other's type
4651 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
4652 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
4654 // LAMESPEC: There seems to be hardcoded promotition to int type when
4655 // both sides are numeric constants and one side is int constant and
4656 // other side is numeric constant convertible to int.
4658 // var res = condition ? (short)1 : 1;
4660 // Type of res is int even if according to the spec the conversion is
4661 // ambiguous because 1 literal can be converted to short.
4663 if (conv_false_expr != null) {
4664 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
4666 conv_false_expr = null;
4667 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
4668 conv_false_expr = null;
4672 if (conv_false_expr != null) {
4673 ec.Report.Error (172, true_expr.Location,
4674 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
4675 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
4680 if (true_expr.Type != type)
4681 true_expr = EmptyCast.Create (true_expr, type);
4682 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4685 ec.Report.Error (173, true_expr.Location,
4686 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4687 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4693 bool is_false = c.IsDefaultValue;
4696 // Don't issue the warning for constant expressions
4698 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
4699 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location,
4700 "Unreachable expression code detected");
4703 return ReducedExpression.Create (
4704 is_false ? false_expr : true_expr, this,
4705 false_expr is Constant && true_expr is Constant).Resolve (ec);
4711 public override void Emit (EmitContext ec)
4713 Label false_target = ec.DefineLabel ();
4714 Label end_target = ec.DefineLabel ();
4716 expr.EmitBranchable (ec, false_target, false);
4717 true_expr.Emit (ec);
4720 // Verifier doesn't support interface merging. When there are two types on
4721 // the stack without common type hint and the common type is an interface.
4722 // Use temporary local to give verifier hint on what type to unify the stack
4724 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
4725 var temp = ec.GetTemporaryLocal (type);
4726 ec.Emit (OpCodes.Stloc, temp);
4727 ec.Emit (OpCodes.Ldloc, temp);
4728 ec.FreeTemporaryLocal (temp, type);
4731 ec.Emit (OpCodes.Br, end_target);
4732 ec.MarkLabel (false_target);
4733 false_expr.Emit (ec);
4734 ec.MarkLabel (end_target);
4737 protected override void CloneTo (CloneContext clonectx, Expression t)
4739 Conditional target = (Conditional) t;
4741 target.expr = expr.Clone (clonectx);
4742 target.true_expr = true_expr.Clone (clonectx);
4743 target.false_expr = false_expr.Clone (clonectx);
4747 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
4749 LocalTemporary temp;
4752 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4753 public abstract void SetHasAddressTaken ();
4754 public abstract void VerifyAssigned (ResolveContext rc);
4756 public abstract bool IsLockedByStatement { get; set; }
4758 public abstract bool IsFixed { get; }
4759 public abstract bool IsRef { get; }
4760 public abstract string Name { get; }
4763 // Variable IL data, it has to be protected to encapsulate hoisted variables
4765 protected abstract ILocalVariable Variable { get; }
4768 // Variable flow-analysis data
4770 public abstract VariableInfo VariableInfo { get; }
4773 public virtual void AddressOf (EmitContext ec, AddressOp mode)
4775 HoistedVariable hv = GetHoistedVariable (ec);
4777 hv.AddressOf (ec, mode);
4781 Variable.EmitAddressOf (ec);
4784 public override bool ContainsEmitWithAwait ()
4789 public override Expression CreateExpressionTree (ResolveContext ec)
4791 HoistedVariable hv = GetHoistedVariable (ec);
4793 return hv.CreateExpressionTree ();
4795 Arguments arg = new Arguments (1);
4796 arg.Add (new Argument (this));
4797 return CreateExpressionFactoryCall (ec, "Constant", arg);
4800 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
4802 if (IsLockedByStatement) {
4803 rc.Report.Warning (728, 2, loc,
4804 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
4811 public override void Emit (EmitContext ec)
4816 public override void EmitSideEffect (EmitContext ec)
4822 // This method is used by parameters that are references, that are
4823 // being passed as references: we only want to pass the pointer (that
4824 // is already stored in the parameter, not the address of the pointer,
4825 // and not the value of the variable).
4827 public void EmitLoad (EmitContext ec)
4832 public void Emit (EmitContext ec, bool leave_copy)
4834 HoistedVariable hv = GetHoistedVariable (ec);
4836 hv.Emit (ec, leave_copy);
4844 // If we are a reference, we loaded on the stack a pointer
4845 // Now lets load the real value
4847 ec.EmitLoadFromPtr (type);
4851 ec.Emit (OpCodes.Dup);
4854 temp = new LocalTemporary (Type);
4860 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4861 bool prepare_for_load)
4863 HoistedVariable hv = GetHoistedVariable (ec);
4865 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4869 New n_source = source as New;
4870 if (n_source != null) {
4871 if (!n_source.Emit (ec, this)) {
4875 ec.EmitLoadFromPtr (type);
4887 ec.Emit (OpCodes.Dup);
4889 temp = new LocalTemporary (Type);
4895 ec.EmitStoreFromPtr (type);
4897 Variable.EmitAssign (ec);
4905 public override Expression EmitToField (EmitContext ec)
4907 HoistedVariable hv = GetHoistedVariable (ec);
4909 return hv.EmitToField (ec);
4912 return base.EmitToField (ec);
4915 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4917 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4920 public HoistedVariable GetHoistedVariable (EmitContext ec)
4922 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4925 public override string GetSignatureForError ()
4930 public bool IsHoisted {
4931 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4936 // Resolved reference to a local variable
4938 public class LocalVariableReference : VariableReference
4940 public LocalVariable local_info;
4942 public LocalVariableReference (LocalVariable li, Location l)
4944 this.local_info = li;
4948 public override VariableInfo VariableInfo {
4949 get { return local_info.VariableInfo; }
4952 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4954 return local_info.HoistedVariant;
4960 // A local variable is always fixed
4962 public override bool IsFixed {
4968 public override bool IsLockedByStatement {
4970 return local_info.IsLocked;
4973 local_info.IsLocked = value;
4977 public override bool IsRef {
4978 get { return false; }
4981 public override string Name {
4982 get { return local_info.Name; }
4987 public override void VerifyAssigned (ResolveContext rc)
4989 VariableInfo variable_info = local_info.VariableInfo;
4990 if (variable_info == null)
4993 if (variable_info.IsAssigned (rc))
4996 rc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
4997 variable_info.SetAssigned (rc);
5000 public override void SetHasAddressTaken ()
5002 local_info.SetHasAddressTaken ();
5005 void DoResolveBase (ResolveContext ec)
5008 // If we are referencing a variable from the external block
5009 // flag it for capturing
5011 if (ec.MustCaptureVariable (local_info)) {
5012 if (local_info.AddressTaken) {
5013 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5014 } else if (local_info.IsFixed) {
5015 ec.Report.Error (1764, loc,
5016 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
5017 GetSignatureForError ());
5020 if (ec.IsVariableCapturingRequired) {
5021 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
5022 storey.CaptureLocalVariable (ec, local_info);
5026 eclass = ExprClass.Variable;
5027 type = local_info.Type;
5030 protected override Expression DoResolve (ResolveContext ec)
5032 local_info.SetIsUsed ();
5034 VerifyAssigned (ec);
5040 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5043 // Don't be too pedantic when variable is used as out param or for some broken code
5044 // which uses property/indexer access to run some initialization
5046 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5047 local_info.SetIsUsed ();
5049 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5052 if (rhs == EmptyExpression.OutAccess) {
5053 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5054 } else if (rhs == EmptyExpression.LValueMemberAccess) {
5055 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
5056 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5057 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5058 } else if (rhs == EmptyExpression.UnaryAddress) {
5059 code = 459; msg = "Cannot take the address of {1} `{0}'";
5061 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5063 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5064 } else if (VariableInfo != null) {
5065 VariableInfo.SetAssigned (ec);
5068 if (eclass == ExprClass.Unresolved)
5071 return base.DoResolveLValue (ec, rhs);
5074 public override int GetHashCode ()
5076 return local_info.GetHashCode ();
5079 public override bool Equals (object obj)
5081 LocalVariableReference lvr = obj as LocalVariableReference;
5085 return local_info == lvr.local_info;
5088 protected override ILocalVariable Variable {
5089 get { return local_info; }
5092 public override string ToString ()
5094 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5097 protected override void CloneTo (CloneContext clonectx, Expression t)
5104 /// This represents a reference to a parameter in the intermediate
5107 public class ParameterReference : VariableReference
5109 protected ParametersBlock.ParameterInfo pi;
5111 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5119 public override bool IsLockedByStatement {
5124 pi.IsLocked = value;
5128 public override bool IsRef {
5129 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5132 bool HasOutModifier {
5133 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5136 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5138 return pi.Parameter.HoistedVariant;
5142 // A ref or out parameter is classified as a moveable variable, even
5143 // if the argument given for the parameter is a fixed variable
5145 public override bool IsFixed {
5146 get { return !IsRef; }
5149 public override string Name {
5150 get { return Parameter.Name; }
5153 public Parameter Parameter {
5154 get { return pi.Parameter; }
5157 public override VariableInfo VariableInfo {
5158 get { return pi.VariableInfo; }
5161 protected override ILocalVariable Variable {
5162 get { return Parameter; }
5167 public override void AddressOf (EmitContext ec, AddressOp mode)
5170 // ParameterReferences might already be a reference
5177 base.AddressOf (ec, mode);
5180 public override void SetHasAddressTaken ()
5182 Parameter.HasAddressTaken = true;
5185 void SetAssigned (ResolveContext ec)
5187 if (HasOutModifier && ec.DoFlowAnalysis)
5188 ec.CurrentBranching.SetAssigned (VariableInfo);
5191 bool DoResolveBase (ResolveContext ec)
5193 if (eclass != ExprClass.Unresolved)
5196 type = pi.ParameterType;
5197 eclass = ExprClass.Variable;
5200 // If we are referencing a parameter from the external block
5201 // flag it for capturing
5203 if (ec.MustCaptureVariable (pi)) {
5204 if (Parameter.HasAddressTaken)
5205 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5208 ec.Report.Error (1628, loc,
5209 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5210 Name, ec.CurrentAnonymousMethod.ContainerType);
5213 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5214 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5215 storey.CaptureParameter (ec, pi, this);
5222 public override int GetHashCode ()
5224 return Name.GetHashCode ();
5227 public override bool Equals (object obj)
5229 ParameterReference pr = obj as ParameterReference;
5233 return Name == pr.Name;
5236 protected override void CloneTo (CloneContext clonectx, Expression target)
5242 public override Expression CreateExpressionTree (ResolveContext ec)
5244 HoistedVariable hv = GetHoistedVariable (ec);
5246 return hv.CreateExpressionTree ();
5248 return Parameter.ExpressionTreeVariableReference ();
5252 // Notice that for ref/out parameters, the type exposed is not the
5253 // same type exposed externally.
5256 // externally we expose "int&"
5257 // here we expose "int".
5259 // We record this in "is_ref". This means that the type system can treat
5260 // the type as it is expected, but when we generate the code, we generate
5261 // the alternate kind of code.
5263 protected override Expression DoResolve (ResolveContext ec)
5265 if (!DoResolveBase (ec))
5268 VerifyAssigned (ec);
5272 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5274 if (!DoResolveBase (ec))
5278 return base.DoResolveLValue (ec, right_side);
5281 public override void VerifyAssigned (ResolveContext rc)
5283 // HACK: Variables are not captured in probing mode
5284 if (rc.IsInProbingMode)
5287 if (HasOutModifier && !VariableInfo.IsAssigned (rc)) {
5288 rc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
5294 /// Invocation of methods or delegates.
5296 public class Invocation : ExpressionStatement
5298 protected Arguments arguments;
5299 protected Expression expr;
5300 protected MethodGroupExpr mg;
5302 public Invocation (Expression expr, Arguments arguments)
5305 this.arguments = arguments;
5307 loc = expr.Location;
5312 public Arguments Arguments {
5318 public Expression Exp {
5324 public MethodGroupExpr MethodGroup {
5330 public override Location StartLocation {
5332 return expr.StartLocation;
5338 protected override void CloneTo (CloneContext clonectx, Expression t)
5340 Invocation target = (Invocation) t;
5342 if (arguments != null)
5343 target.arguments = arguments.Clone (clonectx);
5345 target.expr = expr.Clone (clonectx);
5348 public override bool ContainsEmitWithAwait ()
5350 if (arguments != null && arguments.ContainsEmitWithAwait ())
5353 return mg.ContainsEmitWithAwait ();
5356 public override Expression CreateExpressionTree (ResolveContext ec)
5358 Expression instance = mg.IsInstance ?
5359 mg.InstanceExpression.CreateExpressionTree (ec) :
5360 new NullLiteral (loc);
5362 var args = Arguments.CreateForExpressionTree (ec, arguments,
5364 mg.CreateExpressionTree (ec));
5366 return CreateExpressionFactoryCall (ec, "Call", args);
5369 protected override Expression DoResolve (ResolveContext ec)
5371 Expression member_expr;
5372 var atn = expr as ATypeNameExpression;
5374 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
5375 if (member_expr != null)
5376 member_expr = member_expr.Resolve (ec);
5378 member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5381 if (member_expr == null)
5385 // Next, evaluate all the expressions in the argument list
5387 bool dynamic_arg = false;
5388 if (arguments != null)
5389 arguments.Resolve (ec, out dynamic_arg);
5391 TypeSpec expr_type = member_expr.Type;
5392 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5393 return DoResolveDynamic (ec, member_expr);
5395 mg = member_expr as MethodGroupExpr;
5396 Expression invoke = null;
5399 if (expr_type != null && expr_type.IsDelegate) {
5400 invoke = new DelegateInvocation (member_expr, arguments, loc);
5401 invoke = invoke.Resolve (ec);
5402 if (invoke == null || !dynamic_arg)
5405 if (member_expr is RuntimeValueExpression) {
5406 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
5407 member_expr.Type.GetSignatureForError ()); ;
5411 MemberExpr me = member_expr as MemberExpr;
5413 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5417 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
5418 member_expr.GetSignatureForError ());
5423 if (invoke == null) {
5424 mg = DoResolveOverload (ec);
5430 return DoResolveDynamic (ec, member_expr);
5432 var method = mg.BestCandidate;
5433 type = mg.BestCandidateReturnType;
5435 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
5437 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5439 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5443 IsSpecialMethodInvocation (ec, method, loc);
5445 eclass = ExprClass.Value;
5449 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
5452 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
5454 args = dmb.Arguments;
5455 if (arguments != null)
5456 args.AddRange (arguments);
5457 } else if (mg == null) {
5458 if (arguments == null)
5459 args = new Arguments (1);
5463 args.Insert (0, new Argument (memberExpr));
5467 ec.Report.Error (1971, loc,
5468 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
5473 if (arguments == null)
5474 args = new Arguments (1);
5478 MemberAccess ma = expr as MemberAccess;
5480 var left_type = ma.LeftExpression as TypeExpr;
5481 if (left_type != null) {
5482 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5485 // Any value type has to be pass as by-ref to get back the same
5486 // instance on which the member was called
5488 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
5489 Argument.AType.Ref : Argument.AType.None;
5490 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
5492 } else { // is SimpleName
5494 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5496 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5501 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5504 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5506 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
5509 public override string GetSignatureForError ()
5511 return mg.GetSignatureForError ();
5515 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
5516 // or the type dynamic, then the member is invocable
5518 public static bool IsMemberInvocable (MemberSpec member)
5520 switch (member.Kind) {
5521 case MemberKind.Event:
5523 case MemberKind.Field:
5524 case MemberKind.Property:
5525 var m = member as IInterfaceMemberSpec;
5526 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
5532 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
5534 if (!method.IsReservedMethod)
5537 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
5540 ec.Report.SymbolRelatedToPreviousError (method);
5541 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5542 method.GetSignatureForError ());
5547 public override void Emit (EmitContext ec)
5549 mg.EmitCall (ec, arguments);
5552 public override void EmitStatement (EmitContext ec)
5557 // Pop the return value if there is one
5559 if (type.Kind != MemberKind.Void)
5560 ec.Emit (OpCodes.Pop);
5563 public override SLE.Expression MakeExpression (BuilderContext ctx)
5565 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
5568 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
5571 throw new NotSupportedException ();
5573 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5574 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
5578 public override object Accept (StructuralVisitor visitor)
5580 return visitor.Visit (this);
5585 // Implements simple new expression
5587 public class New : ExpressionStatement, IMemoryLocation
5589 protected Arguments arguments;
5592 // During bootstrap, it contains the RequestedType,
5593 // but if `type' is not null, it *might* contain a NewDelegate
5594 // (because of field multi-initialization)
5596 protected Expression RequestedType;
5598 protected MethodSpec method;
5600 public New (Expression requested_type, Arguments arguments, Location l)
5602 RequestedType = requested_type;
5603 this.arguments = arguments;
5608 public Arguments Arguments {
5615 // Returns true for resolved `new S()'
5617 public bool IsDefaultStruct {
5619 return arguments == null && type.IsStruct && GetType () == typeof (New);
5623 public Expression TypeExpression {
5625 return RequestedType;
5632 /// Converts complex core type syntax like 'new int ()' to simple constant
5634 public static Constant Constantify (TypeSpec t, Location loc)
5636 switch (t.BuiltinType) {
5637 case BuiltinTypeSpec.Type.Int:
5638 return new IntConstant (t, 0, loc);
5639 case BuiltinTypeSpec.Type.UInt:
5640 return new UIntConstant (t, 0, loc);
5641 case BuiltinTypeSpec.Type.Long:
5642 return new LongConstant (t, 0, loc);
5643 case BuiltinTypeSpec.Type.ULong:
5644 return new ULongConstant (t, 0, loc);
5645 case BuiltinTypeSpec.Type.Float:
5646 return new FloatConstant (t, 0, loc);
5647 case BuiltinTypeSpec.Type.Double:
5648 return new DoubleConstant (t, 0, loc);
5649 case BuiltinTypeSpec.Type.Short:
5650 return new ShortConstant (t, 0, loc);
5651 case BuiltinTypeSpec.Type.UShort:
5652 return new UShortConstant (t, 0, loc);
5653 case BuiltinTypeSpec.Type.SByte:
5654 return new SByteConstant (t, 0, loc);
5655 case BuiltinTypeSpec.Type.Byte:
5656 return new ByteConstant (t, 0, loc);
5657 case BuiltinTypeSpec.Type.Char:
5658 return new CharConstant (t, '\0', loc);
5659 case BuiltinTypeSpec.Type.Bool:
5660 return new BoolConstant (t, false, loc);
5661 case BuiltinTypeSpec.Type.Decimal:
5662 return new DecimalConstant (t, 0, loc);
5666 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
5668 if (t.IsNullableType)
5669 return Nullable.LiftedNull.Create (t, loc);
5674 public override bool ContainsEmitWithAwait ()
5676 return arguments != null && arguments.ContainsEmitWithAwait ();
5680 // Checks whether the type is an interface that has the
5681 // [ComImport, CoClass] attributes and must be treated
5684 public Expression CheckComImport (ResolveContext ec)
5686 if (!type.IsInterface)
5690 // Turn the call into:
5691 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5693 var real_class = type.MemberDefinition.GetAttributeCoClass ();
5694 if (real_class == null)
5697 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
5698 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5699 return cast.Resolve (ec);
5702 public override Expression CreateExpressionTree (ResolveContext ec)
5705 if (method == null) {
5706 args = new Arguments (1);
5707 args.Add (new Argument (new TypeOf (type, loc)));
5709 args = Arguments.CreateForExpressionTree (ec,
5710 arguments, new TypeOfMethod (method, loc));
5713 return CreateExpressionFactoryCall (ec, "New", args);
5716 protected override Expression DoResolve (ResolveContext ec)
5718 type = RequestedType.ResolveAsType (ec);
5722 eclass = ExprClass.Value;
5724 if (type.IsPointer) {
5725 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5726 TypeManager.CSharpName (type));
5730 if (arguments == null) {
5731 Constant c = Constantify (type, RequestedType.Location);
5733 return ReducedExpression.Create (c, this);
5736 if (type.IsDelegate) {
5737 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
5740 var tparam = type as TypeParameterSpec;
5741 if (tparam != null) {
5743 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
5744 // where type parameter constraint is inflated to struct
5746 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
5747 ec.Report.Error (304, loc,
5748 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
5749 TypeManager.CSharpName (type));
5752 if ((arguments != null) && (arguments.Count != 0)) {
5753 ec.Report.Error (417, loc,
5754 "`{0}': cannot provide arguments when creating an instance of a variable type",
5755 TypeManager.CSharpName (type));
5761 if (type.IsStatic) {
5762 ec.Report.SymbolRelatedToPreviousError (type);
5763 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5767 if (type.IsInterface || type.IsAbstract){
5768 if (!TypeManager.IsGenericType (type)) {
5769 RequestedType = CheckComImport (ec);
5770 if (RequestedType != null)
5771 return RequestedType;
5774 ec.Report.SymbolRelatedToPreviousError (type);
5775 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5780 // Any struct always defines parameterless constructor
5782 if (type.IsStruct && arguments == null)
5786 if (arguments != null) {
5787 arguments.Resolve (ec, out dynamic);
5792 method = ConstructorLookup (ec, type, ref arguments, loc);
5795 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5796 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
5802 bool DoEmitTypeParameter (EmitContext ec)
5804 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
5808 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
5809 var tparam = (TypeParameterSpec) type;
5811 if (tparam.IsReferenceType) {
5812 ec.Emit (OpCodes.Call, ctor_factory);
5816 // Allow DoEmit() to be called multiple times.
5817 // We need to create a new LocalTemporary each time since
5818 // you can't share LocalBuilders among ILGeneators.
5819 LocalTemporary temp = new LocalTemporary (type);
5821 Label label_activator = ec.DefineLabel ();
5822 Label label_end = ec.DefineLabel ();
5824 temp.AddressOf (ec, AddressOp.Store);
5825 ec.Emit (OpCodes.Initobj, type);
5828 ec.Emit (OpCodes.Box, type);
5829 ec.Emit (OpCodes.Brfalse, label_activator);
5831 temp.AddressOf (ec, AddressOp.Store);
5832 ec.Emit (OpCodes.Initobj, type);
5835 ec.Emit (OpCodes.Br_S, label_end);
5837 ec.MarkLabel (label_activator);
5839 ec.Emit (OpCodes.Call, ctor_factory);
5840 ec.MarkLabel (label_end);
5845 // This Emit can be invoked in two contexts:
5846 // * As a mechanism that will leave a value on the stack (new object)
5847 // * As one that wont (init struct)
5849 // If we are dealing with a ValueType, we have a few
5850 // situations to deal with:
5852 // * The target is a ValueType, and we have been provided
5853 // the instance (this is easy, we are being assigned).
5855 // * The target of New is being passed as an argument,
5856 // to a boxing operation or a function that takes a
5859 // In this case, we need to create a temporary variable
5860 // that is the argument of New.
5862 // Returns whether a value is left on the stack
5864 // *** Implementation note ***
5866 // To benefit from this optimization, each assignable expression
5867 // has to manually cast to New and call this Emit.
5869 // TODO: It's worth to implement it for arrays and fields
5871 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5873 bool is_value_type = TypeSpec.IsValueType (type);
5874 VariableReference vr = target as VariableReference;
5876 if (target != null && is_value_type && (vr != null || method == null)) {
5877 target.AddressOf (ec, AddressOp.Store);
5878 } else if (vr != null && vr.IsRef) {
5882 if (arguments != null) {
5883 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
5884 arguments = arguments.Emit (ec, false, true);
5886 arguments.Emit (ec);
5889 if (is_value_type) {
5890 if (method == null) {
5891 ec.Emit (OpCodes.Initobj, type);
5896 ec.Emit (OpCodes.Call, method);
5901 if (type is TypeParameterSpec)
5902 return DoEmitTypeParameter (ec);
5904 ec.Emit (OpCodes.Newobj, method);
5908 public override void Emit (EmitContext ec)
5910 LocalTemporary v = null;
5911 if (method == null && TypeSpec.IsValueType (type)) {
5912 // TODO: Use temporary variable from pool
5913 v = new LocalTemporary (type);
5920 public override void EmitStatement (EmitContext ec)
5922 LocalTemporary v = null;
5923 if (method == null && TypeSpec.IsValueType (type)) {
5924 // TODO: Use temporary variable from pool
5925 v = new LocalTemporary (type);
5929 ec.Emit (OpCodes.Pop);
5932 public void AddressOf (EmitContext ec, AddressOp mode)
5934 EmitAddressOf (ec, mode);
5937 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5939 LocalTemporary value_target = new LocalTemporary (type);
5941 if (type is TypeParameterSpec) {
5942 DoEmitTypeParameter (ec);
5943 value_target.Store (ec);
5944 value_target.AddressOf (ec, mode);
5945 return value_target;
5948 value_target.AddressOf (ec, AddressOp.Store);
5950 if (method == null) {
5951 ec.Emit (OpCodes.Initobj, type);
5953 if (arguments != null)
5954 arguments.Emit (ec);
5956 ec.Emit (OpCodes.Call, method);
5959 value_target.AddressOf (ec, mode);
5960 return value_target;
5963 protected override void CloneTo (CloneContext clonectx, Expression t)
5965 New target = (New) t;
5967 target.RequestedType = RequestedType.Clone (clonectx);
5968 if (arguments != null){
5969 target.arguments = arguments.Clone (clonectx);
5973 public override SLE.Expression MakeExpression (BuilderContext ctx)
5976 return base.MakeExpression (ctx);
5978 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
5982 public override object Accept (StructuralVisitor visitor)
5984 return visitor.Visit (this);
5989 // Array initializer expression, the expression is allowed in
5990 // variable or field initialization only which makes it tricky as
5991 // the type has to be infered based on the context either from field
5992 // type or variable type (think of multiple declarators)
5994 public class ArrayInitializer : Expression
5996 List<Expression> elements;
5997 BlockVariableDeclaration variable;
5999 public ArrayInitializer (List<Expression> init, Location loc)
6005 public ArrayInitializer (int count, Location loc)
6006 : this (new List<Expression> (count), loc)
6010 public ArrayInitializer (Location loc)
6018 get { return elements.Count; }
6021 public List<Expression> Elements {
6027 public Expression this [int index] {
6029 return elements [index];
6033 public BlockVariableDeclaration VariableDeclaration {
6044 public void Add (Expression expr)
6046 elements.Add (expr);
6049 public override bool ContainsEmitWithAwait ()
6051 throw new NotSupportedException ();
6054 public override Expression CreateExpressionTree (ResolveContext ec)
6056 throw new NotSupportedException ("ET");
6059 protected override void CloneTo (CloneContext clonectx, Expression t)
6061 var target = (ArrayInitializer) t;
6063 target.elements = new List<Expression> (elements.Count);
6064 foreach (var element in elements)
6065 target.elements.Add (element.Clone (clonectx));
6068 protected override Expression DoResolve (ResolveContext rc)
6070 var current_field = rc.CurrentMemberDefinition as FieldBase;
6071 TypeExpression type;
6072 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6073 type = new TypeExpression (current_field.MemberType, current_field.Location);
6074 } else if (variable != null) {
6075 if (variable.TypeExpression is VarExpr) {
6076 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6077 return EmptyExpression.Null;
6080 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6082 throw new NotImplementedException ("Unexpected array initializer context");
6085 return new ArrayCreation (type, this).Resolve (rc);
6088 public override void Emit (EmitContext ec)
6090 throw new InternalErrorException ("Missing Resolve call");
6093 public override object Accept (StructuralVisitor visitor)
6095 return visitor.Visit (this);
6100 /// 14.5.10.2: Represents an array creation expression.
6104 /// There are two possible scenarios here: one is an array creation
6105 /// expression that specifies the dimensions and optionally the
6106 /// initialization data and the other which does not need dimensions
6107 /// specified but where initialization data is mandatory.
6109 public class ArrayCreation : Expression
6111 FullNamedExpression requested_base_type;
6112 ArrayInitializer initializers;
6115 // The list of Argument types.
6116 // This is used to construct the `newarray' or constructor signature
6118 protected List<Expression> arguments;
6120 protected TypeSpec array_element_type;
6121 int num_arguments = 0;
6122 protected int dimensions;
6123 protected readonly ComposedTypeSpecifier rank;
6124 Expression first_emit;
6125 LocalTemporary first_emit_temp;
6127 protected List<Expression> array_data;
6129 Dictionary<int, int> bounds;
6132 // The number of constants in array initializers
6133 int const_initializers_count;
6134 bool only_constant_initializers;
6136 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6137 : this (requested_base_type, rank, initializers, l)
6139 arguments = new List<Expression> (exprs);
6140 num_arguments = arguments.Count;
6144 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6146 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6148 this.requested_base_type = requested_base_type;
6150 this.initializers = initializers;
6154 num_arguments = rank.Dimension;
6158 // For compiler generated single dimensional arrays only
6160 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6161 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6166 // For expressions like int[] foo = { 1, 2, 3 };
6168 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6169 : this (requested_base_type, null, initializers, initializers.Location)
6173 public ComposedTypeSpecifier Rank {
6179 public FullNamedExpression TypeExpression {
6181 return this.requested_base_type;
6185 public ArrayInitializer Initializers {
6187 return this.initializers;
6191 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6193 if (initializers != null && bounds == null) {
6195 // We use this to store all the data values in the order in which we
6196 // will need to store them in the byte blob later
6198 array_data = new List<Expression> (probe.Count);
6199 bounds = new Dictionary<int, int> ();
6202 if (specified_dims) {
6203 Expression a = arguments [idx];
6208 a = ConvertExpressionToArrayIndex (ec, a);
6214 if (initializers != null) {
6215 Constant c = a as Constant;
6216 if (c == null && a is ArrayIndexCast)
6217 c = ((ArrayIndexCast) a).Child as Constant;
6220 ec.Report.Error (150, a.Location, "A constant value is expected");
6226 value = System.Convert.ToInt32 (c.GetValue ());
6228 ec.Report.Error (150, a.Location, "A constant value is expected");
6232 // TODO: probe.Count does not fit ulong in
6233 if (value != probe.Count) {
6234 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6238 bounds[idx] = value;
6242 if (initializers == null)
6245 for (int i = 0; i < probe.Count; ++i) {
6247 if (o is ArrayInitializer) {
6248 var sub_probe = o as ArrayInitializer;
6249 if (idx + 1 >= dimensions){
6250 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6254 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
6255 if (!bounds.ContainsKey(idx + 1))
6256 bounds[idx + 1] = sub_probe.Count;
6258 if (bounds[idx + 1] != sub_probe.Count) {
6259 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
6263 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6266 } else if (child_bounds > 1) {
6267 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6269 Expression element = ResolveArrayElement (ec, o);
6270 if (element == null)
6273 // Initializers with the default values can be ignored
6274 Constant c = element as Constant;
6276 if (!c.IsDefaultInitializer (array_element_type)) {
6277 ++const_initializers_count;
6280 only_constant_initializers = false;
6283 array_data.Add (element);
6290 public override bool ContainsEmitWithAwait ()
6292 foreach (var arg in arguments) {
6293 if (arg.ContainsEmitWithAwait ())
6297 return InitializersContainAwait ();
6300 public override Expression CreateExpressionTree (ResolveContext ec)
6304 if (array_data == null) {
6305 args = new Arguments (arguments.Count + 1);
6306 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6307 foreach (Expression a in arguments)
6308 args.Add (new Argument (a.CreateExpressionTree (ec)));
6310 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6313 if (dimensions > 1) {
6314 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6318 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6319 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6320 if (array_data != null) {
6321 for (int i = 0; i < array_data.Count; ++i) {
6322 Expression e = array_data [i];
6323 args.Add (new Argument (e.CreateExpressionTree (ec)));
6327 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6330 void UpdateIndices (ResolveContext rc)
6333 for (var probe = initializers; probe != null;) {
6334 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
6336 bounds[i++] = probe.Count;
6338 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
6339 probe = (ArrayInitializer) probe[0];
6340 } else if (dimensions > i) {
6348 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
6350 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
6353 bool InitializersContainAwait ()
6355 if (array_data == null)
6358 foreach (var expr in array_data) {
6359 if (expr.ContainsEmitWithAwait ())
6366 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
6368 element = element.Resolve (ec);
6369 if (element == null)
6372 if (element is CompoundAssign.TargetExpression) {
6373 if (first_emit != null)
6374 throw new InternalErrorException ("Can only handle one mutator at a time");
6375 first_emit = element;
6376 element = first_emit_temp = new LocalTemporary (element.Type);
6379 return Convert.ImplicitConversionRequired (
6380 ec, element, array_element_type, loc);
6383 protected bool ResolveInitializers (ResolveContext ec)
6386 only_constant_initializers = true;
6389 if (arguments != null) {
6391 for (int i = 0; i < arguments.Count; ++i) {
6392 res &= CheckIndices (ec, initializers, i, true, dimensions);
6393 if (initializers != null)
6400 arguments = new List<Expression> ();
6402 if (!CheckIndices (ec, initializers, 0, false, dimensions))
6411 // Resolved the type of the array
6413 bool ResolveArrayType (ResolveContext ec)
6418 FullNamedExpression array_type_expr;
6419 if (num_arguments > 0) {
6420 array_type_expr = new ComposedCast (requested_base_type, rank);
6422 array_type_expr = requested_base_type;
6425 type = array_type_expr.ResolveAsType (ec);
6426 if (array_type_expr == null)
6429 var ac = type as ArrayContainer;
6431 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6435 array_element_type = ac.Element;
6436 dimensions = ac.Rank;
6441 protected override Expression DoResolve (ResolveContext ec)
6446 if (!ResolveArrayType (ec))
6450 // validate the initializers and fill in any missing bits
6452 if (!ResolveInitializers (ec))
6455 eclass = ExprClass.Value;
6459 byte [] MakeByteBlob ()
6464 int count = array_data.Count;
6466 TypeSpec element_type = array_element_type;
6467 if (element_type.IsEnum)
6468 element_type = EnumSpec.GetUnderlyingType (element_type);
6470 factor = BuiltinTypeSpec.GetSize (element_type);
6472 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6474 data = new byte [(count * factor + 3) & ~3];
6477 for (int i = 0; i < count; ++i) {
6478 var c = array_data[i] as Constant;
6484 object v = c.GetValue ();
6486 switch (element_type.BuiltinType) {
6487 case BuiltinTypeSpec.Type.Long:
6488 long lval = (long) v;
6490 for (int j = 0; j < factor; ++j) {
6491 data[idx + j] = (byte) (lval & 0xFF);
6495 case BuiltinTypeSpec.Type.ULong:
6496 ulong ulval = (ulong) v;
6498 for (int j = 0; j < factor; ++j) {
6499 data[idx + j] = (byte) (ulval & 0xFF);
6500 ulval = (ulval >> 8);
6503 case BuiltinTypeSpec.Type.Float:
6504 var fval = SingleConverter.SingleToInt32Bits((float) v);
6506 data[idx] = (byte) (fval & 0xff);
6507 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
6508 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
6509 data[idx + 3] = (byte) (fval >> 24);
6511 case BuiltinTypeSpec.Type.Double:
6512 element = BitConverter.GetBytes ((double) v);
6514 for (int j = 0; j < factor; ++j)
6515 data[idx + j] = element[j];
6517 // FIXME: Handle the ARM float format.
6518 if (!BitConverter.IsLittleEndian)
6519 System.Array.Reverse (data, idx, 8);
6521 case BuiltinTypeSpec.Type.Char:
6522 int chval = (int) ((char) v);
6524 data[idx] = (byte) (chval & 0xff);
6525 data[idx + 1] = (byte) (chval >> 8);
6527 case BuiltinTypeSpec.Type.Short:
6528 int sval = (int) ((short) v);
6530 data[idx] = (byte) (sval & 0xff);
6531 data[idx + 1] = (byte) (sval >> 8);
6533 case BuiltinTypeSpec.Type.UShort:
6534 int usval = (int) ((ushort) v);
6536 data[idx] = (byte) (usval & 0xff);
6537 data[idx + 1] = (byte) (usval >> 8);
6539 case BuiltinTypeSpec.Type.Int:
6542 data[idx] = (byte) (val & 0xff);
6543 data[idx + 1] = (byte) ((val >> 8) & 0xff);
6544 data[idx + 2] = (byte) ((val >> 16) & 0xff);
6545 data[idx + 3] = (byte) (val >> 24);
6547 case BuiltinTypeSpec.Type.UInt:
6548 uint uval = (uint) v;
6550 data[idx] = (byte) (uval & 0xff);
6551 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
6552 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
6553 data[idx + 3] = (byte) (uval >> 24);
6555 case BuiltinTypeSpec.Type.SByte:
6556 data[idx] = (byte) (sbyte) v;
6558 case BuiltinTypeSpec.Type.Byte:
6559 data[idx] = (byte) v;
6561 case BuiltinTypeSpec.Type.Bool:
6562 data[idx] = (byte) ((bool) v ? 1 : 0);
6564 case BuiltinTypeSpec.Type.Decimal:
6565 int[] bits = Decimal.GetBits ((decimal) v);
6568 // FIXME: For some reason, this doesn't work on the MS runtime.
6569 int[] nbits = new int[4];
6575 for (int j = 0; j < 4; j++) {
6576 data[p++] = (byte) (nbits[j] & 0xff);
6577 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
6578 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
6579 data[p++] = (byte) (nbits[j] >> 24);
6583 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6592 #if NET_4_0 || MONODROID
6593 public override SLE.Expression MakeExpression (BuilderContext ctx)
6596 return base.MakeExpression (ctx);
6598 var initializers = new SLE.Expression [array_data.Count];
6599 for (var i = 0; i < initializers.Length; i++) {
6600 if (array_data [i] == null)
6601 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
6603 initializers [i] = array_data [i].MakeExpression (ctx);
6606 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
6612 // Emits the initializers for the array
6614 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
6616 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
6621 // First, the static data
6623 byte [] data = MakeByteBlob ();
6624 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
6626 if (stackArray == null) {
6627 ec.Emit (OpCodes.Dup);
6629 stackArray.Emit (ec);
6632 ec.Emit (OpCodes.Ldtoken, fb);
6633 ec.Emit (OpCodes.Call, m);
6638 // Emits pieces of the array that can not be computed at compile
6639 // time (variables and string locations).
6641 // This always expect the top value on the stack to be the array
6643 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
6645 int dims = bounds.Count;
6646 var current_pos = new int [dims];
6648 for (int i = 0; i < array_data.Count; i++){
6650 Expression e = array_data [i];
6651 var c = e as Constant;
6653 // Constant can be initialized via StaticInitializer
6654 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
6658 if (stackArray != null) {
6659 if (e.ContainsEmitWithAwait ()) {
6660 e = e.EmitToField (ec);
6663 stackArray.Emit (ec);
6665 ec.Emit (OpCodes.Dup);
6668 for (int idx = 0; idx < dims; idx++)
6669 ec.EmitInt (current_pos [idx]);
6672 // If we are dealing with a struct, get the
6673 // address of it, so we can store it.
6675 if (dims == 1 && etype.IsStruct) {
6676 switch (etype.BuiltinType) {
6677 case BuiltinTypeSpec.Type.Byte:
6678 case BuiltinTypeSpec.Type.SByte:
6679 case BuiltinTypeSpec.Type.Bool:
6680 case BuiltinTypeSpec.Type.Short:
6681 case BuiltinTypeSpec.Type.UShort:
6682 case BuiltinTypeSpec.Type.Char:
6683 case BuiltinTypeSpec.Type.Int:
6684 case BuiltinTypeSpec.Type.UInt:
6685 case BuiltinTypeSpec.Type.Long:
6686 case BuiltinTypeSpec.Type.ULong:
6687 case BuiltinTypeSpec.Type.Float:
6688 case BuiltinTypeSpec.Type.Double:
6691 ec.Emit (OpCodes.Ldelema, etype);
6698 ec.EmitArrayStore ((ArrayContainer) type);
6704 for (int j = dims - 1; j >= 0; j--){
6706 if (current_pos [j] < bounds [j])
6708 current_pos [j] = 0;
6713 public override void Emit (EmitContext ec)
6715 EmitToFieldSource (ec);
6718 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
6720 if (first_emit != null) {
6721 first_emit.Emit (ec);
6722 first_emit_temp.Store (ec);
6725 FieldExpr await_stack_field;
6726 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
6727 await_stack_field = ec.GetTemporaryField (type);
6730 await_stack_field = null;
6733 EmitExpressionsList (ec, arguments);
6735 ec.EmitArrayNew ((ArrayContainer) type);
6737 if (initializers == null)
6738 return await_stack_field;
6740 if (await_stack_field != null)
6741 await_stack_field.EmitAssignFromStack (ec);
6745 // Emit static initializer for arrays which contain more than 2 items and
6746 // the static initializer will initialize at least 25% of array values or there
6747 // is more than 10 items to be initialized
6749 // NOTE: const_initializers_count does not contain default constant values.
6751 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
6752 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
6753 EmitStaticInitializers (ec, await_stack_field);
6755 if (!only_constant_initializers)
6756 EmitDynamicInitializers (ec, false, await_stack_field);
6760 EmitDynamicInitializers (ec, true, await_stack_field);
6763 if (first_emit_temp != null)
6764 first_emit_temp.Release (ec);
6766 return await_stack_field;
6769 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
6771 // no multi dimensional or jagged arrays
6772 if (arguments.Count != 1 || array_element_type.IsArray) {
6773 base.EncodeAttributeValue (rc, enc, targetType);
6777 // No array covariance, except for array -> object
6778 if (type != targetType) {
6779 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
6780 base.EncodeAttributeValue (rc, enc, targetType);
6784 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
6785 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
6790 // Single dimensional array of 0 size
6791 if (array_data == null) {
6792 IntConstant ic = arguments[0] as IntConstant;
6793 if (ic == null || !ic.IsDefaultValue) {
6794 base.EncodeAttributeValue (rc, enc, targetType);
6802 enc.Encode (array_data.Count);
6803 foreach (var element in array_data) {
6804 element.EncodeAttributeValue (rc, enc, array_element_type);
6808 protected override void CloneTo (CloneContext clonectx, Expression t)
6810 ArrayCreation target = (ArrayCreation) t;
6812 if (requested_base_type != null)
6813 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6815 if (arguments != null){
6816 target.arguments = new List<Expression> (arguments.Count);
6817 foreach (Expression e in arguments)
6818 target.arguments.Add (e.Clone (clonectx));
6821 if (initializers != null)
6822 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
6825 public override object Accept (StructuralVisitor visitor)
6827 return visitor.Visit (this);
6832 // Represents an implicitly typed array epxression
6834 class ImplicitlyTypedArrayCreation : ArrayCreation
6836 TypeInferenceContext best_type_inference;
6838 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6839 : base (null, rank, initializers, loc)
6843 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
6844 : base (null, initializers, loc)
6848 protected override Expression DoResolve (ResolveContext ec)
6853 dimensions = rank.Dimension;
6855 best_type_inference = new TypeInferenceContext ();
6857 if (!ResolveInitializers (ec))
6860 best_type_inference.FixAllTypes (ec);
6861 array_element_type = best_type_inference.InferredTypeArguments[0];
6862 best_type_inference = null;
6864 if (array_element_type == null ||
6865 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
6866 arguments.Count != rank.Dimension) {
6867 ec.Report.Error (826, loc,
6868 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6873 // At this point we found common base type for all initializer elements
6874 // but we have to be sure that all static initializer elements are of
6877 UnifyInitializerElement (ec);
6879 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
6880 eclass = ExprClass.Value;
6885 // Converts static initializer only
6887 void UnifyInitializerElement (ResolveContext ec)
6889 for (int i = 0; i < array_data.Count; ++i) {
6890 Expression e = array_data[i];
6892 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6896 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6898 element = element.Resolve (ec);
6899 if (element != null)
6900 best_type_inference.AddCommonTypeBound (element.Type);
6906 sealed class CompilerGeneratedThis : This
6908 public CompilerGeneratedThis (TypeSpec type, Location loc)
6912 eclass = ExprClass.Variable;
6915 protected override Expression DoResolve (ResolveContext ec)
6920 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6927 /// Represents the `this' construct
6930 public class This : VariableReference
6932 sealed class ThisVariable : ILocalVariable
6934 public static readonly ILocalVariable Instance = new ThisVariable ();
6936 public void Emit (EmitContext ec)
6941 public void EmitAssign (EmitContext ec)
6943 throw new InvalidOperationException ();
6946 public void EmitAddressOf (EmitContext ec)
6952 VariableInfo variable_info;
6954 public This (Location loc)
6961 public override string Name {
6962 get { return "this"; }
6965 public override bool IsLockedByStatement {
6973 public override bool IsRef {
6974 get { return type.IsStruct; }
6977 public override bool IsSideEffectFree {
6983 protected override ILocalVariable Variable {
6984 get { return ThisVariable.Instance; }
6987 public override VariableInfo VariableInfo {
6988 get { return variable_info; }
6991 public override bool IsFixed {
6992 get { return false; }
6997 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
7000 // It's null for all cases when we don't need to check `this'
7001 // definitive assignment
7003 if (variable_info == null)
7006 if (rc.OmitStructFlowAnalysis)
7009 if (!variable_info.IsAssigned (rc)) {
7010 rc.Report.Error (188, loc,
7011 "The `this' object cannot be used before all of its fields are assigned to");
7015 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7017 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7018 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7019 } else if (ec.CurrentAnonymousMethod != null) {
7020 ec.Report.Error (1673, loc,
7021 "Anonymous methods inside structs cannot access instance members of `this'. " +
7022 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7024 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7028 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7033 AnonymousMethodStorey storey = ae.Storey;
7034 return storey != null ? storey.HoistedThis : null;
7037 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7039 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7042 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7045 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7051 public virtual void ResolveBase (ResolveContext ec)
7053 eclass = ExprClass.Variable;
7054 type = ec.CurrentType;
7056 if (!IsThisAvailable (ec, false)) {
7057 Error_ThisNotAvailable (ec);
7061 var block = ec.CurrentBlock;
7062 if (block != null) {
7063 var top = block.ParametersBlock.TopBlock;
7064 if (top.ThisVariable != null)
7065 variable_info = top.ThisVariable.VariableInfo;
7067 AnonymousExpression am = ec.CurrentAnonymousMethod;
7068 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7070 // Hoisted this is almost like hoisted variable but not exactly. When
7071 // there is no variable hoisted we can simply emit an instance method
7072 // without lifting this into a storey. Unfotunatelly this complicates
7073 // things in other cases because we don't know where this will be hoisted
7074 // until top-level block is fully resolved
7076 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7077 am.SetHasThisAccess ();
7082 protected override Expression DoResolve (ResolveContext ec)
7086 CheckStructThisDefiniteAssignment (ec);
7091 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7093 if (eclass == ExprClass.Unresolved)
7096 if (variable_info != null)
7097 variable_info.SetAssigned (ec);
7100 if (right_side == EmptyExpression.UnaryAddress)
7101 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7102 else if (right_side == EmptyExpression.OutAccess)
7103 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7105 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7111 public override int GetHashCode()
7113 throw new NotImplementedException ();
7116 public override bool Equals (object obj)
7118 This t = obj as This;
7125 protected override void CloneTo (CloneContext clonectx, Expression t)
7130 public override void SetHasAddressTaken ()
7135 public override void VerifyAssigned (ResolveContext rc)
7139 public override object Accept (StructuralVisitor visitor)
7141 return visitor.Visit (this);
7146 /// Represents the `__arglist' construct
7148 public class ArglistAccess : Expression
7150 public ArglistAccess (Location loc)
7155 protected override void CloneTo (CloneContext clonectx, Expression target)
7160 public override bool ContainsEmitWithAwait ()
7165 public override Expression CreateExpressionTree (ResolveContext ec)
7167 throw new NotSupportedException ("ET");
7170 protected override Expression DoResolve (ResolveContext ec)
7172 eclass = ExprClass.Variable;
7173 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
7175 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7176 ec.Report.Error (190, loc,
7177 "The __arglist construct is valid only within a variable argument method");
7183 public override void Emit (EmitContext ec)
7185 ec.Emit (OpCodes.Arglist);
7188 public override object Accept (StructuralVisitor visitor)
7190 return visitor.Visit (this);
7195 /// Represents the `__arglist (....)' construct
7197 public class Arglist : Expression
7199 Arguments arguments;
7201 public Arglist (Location loc)
7206 public Arglist (Arguments args, Location l)
7212 public Arguments Arguments {
7218 public MetaType[] ArgumentTypes {
7220 if (arguments == null)
7221 return MetaType.EmptyTypes;
7223 var retval = new MetaType[arguments.Count];
7224 for (int i = 0; i < retval.Length; i++)
7225 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
7231 public override bool ContainsEmitWithAwait ()
7233 throw new NotImplementedException ();
7236 public override Expression CreateExpressionTree (ResolveContext ec)
7238 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7242 protected override Expression DoResolve (ResolveContext ec)
7244 eclass = ExprClass.Variable;
7245 type = InternalType.Arglist;
7246 if (arguments != null) {
7247 bool dynamic; // Can be ignored as there is always only 1 overload
7248 arguments.Resolve (ec, out dynamic);
7254 public override void Emit (EmitContext ec)
7256 if (arguments != null)
7257 arguments.Emit (ec);
7260 protected override void CloneTo (CloneContext clonectx, Expression t)
7262 Arglist target = (Arglist) t;
7264 if (arguments != null)
7265 target.arguments = arguments.Clone (clonectx);
7268 public override object Accept (StructuralVisitor visitor)
7270 return visitor.Visit (this);
7274 public class RefValueExpr : ShimExpression, IAssignMethod
7276 FullNamedExpression texpr;
7278 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7285 public FullNamedExpression TypeExpression {
7291 public override bool ContainsEmitWithAwait ()
7296 protected override Expression DoResolve (ResolveContext rc)
7298 expr = expr.Resolve (rc);
7299 type = texpr.ResolveAsType (rc);
7300 if (expr == null || type == null)
7303 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7304 eclass = ExprClass.Value;
7308 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7310 return DoResolve (rc);
7313 public override void Emit (EmitContext ec)
7316 ec.Emit (OpCodes.Refanyval, type);
7317 ec.EmitLoadFromPtr (type);
7320 public void Emit (EmitContext ec, bool leave_copy)
7322 throw new NotImplementedException ();
7325 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7328 ec.Emit (OpCodes.Refanyval, type);
7331 LocalTemporary temporary = null;
7333 ec.Emit (OpCodes.Dup);
7334 temporary = new LocalTemporary (source.Type);
7335 temporary.Store (ec);
7338 ec.EmitStoreFromPtr (type);
7340 if (temporary != null) {
7341 temporary.Emit (ec);
7342 temporary.Release (ec);
7346 public override object Accept (StructuralVisitor visitor)
7348 return visitor.Visit (this);
7352 public class RefTypeExpr : ShimExpression
7354 public RefTypeExpr (Expression expr, Location loc)
7360 protected override Expression DoResolve (ResolveContext rc)
7362 expr = expr.Resolve (rc);
7366 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7370 type = rc.BuiltinTypes.Type;
7371 eclass = ExprClass.Value;
7375 public override void Emit (EmitContext ec)
7378 ec.Emit (OpCodes.Refanytype);
7379 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7381 ec.Emit (OpCodes.Call, m);
7384 public override object Accept (StructuralVisitor visitor)
7386 return visitor.Visit (this);
7390 public class MakeRefExpr : ShimExpression
7392 public MakeRefExpr (Expression expr, Location loc)
7398 public override bool ContainsEmitWithAwait ()
7400 throw new NotImplementedException ();
7403 protected override Expression DoResolve (ResolveContext rc)
7405 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
7406 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
7407 eclass = ExprClass.Value;
7411 public override void Emit (EmitContext ec)
7413 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
7414 ec.Emit (OpCodes.Mkrefany, expr.Type);
7417 public override object Accept (StructuralVisitor visitor)
7419 return visitor.Visit (this);
7424 /// Implements the typeof operator
7426 public class TypeOf : Expression {
7427 FullNamedExpression QueriedType;
7430 public TypeOf (FullNamedExpression queried_type, Location l)
7432 QueriedType = queried_type;
7437 // Use this constructor for any compiler generated typeof expression
7439 public TypeOf (TypeSpec type, Location loc)
7441 this.typearg = type;
7447 public override bool IsSideEffectFree {
7453 public TypeSpec TypeArgument {
7459 public FullNamedExpression TypeExpression {
7468 protected override void CloneTo (CloneContext clonectx, Expression t)
7470 TypeOf target = (TypeOf) t;
7471 if (QueriedType != null)
7472 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
7475 public override bool ContainsEmitWithAwait ()
7480 public override Expression CreateExpressionTree (ResolveContext ec)
7482 Arguments args = new Arguments (2);
7483 args.Add (new Argument (this));
7484 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7485 return CreateExpressionFactoryCall (ec, "Constant", args);
7488 protected override Expression DoResolve (ResolveContext ec)
7490 if (eclass != ExprClass.Unresolved)
7493 if (typearg == null) {
7495 // Pointer types are allowed without explicit unsafe, they are just tokens
7497 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
7498 typearg = QueriedType.ResolveAsType (ec);
7501 if (typearg == null)
7504 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7505 ec.Report.Error (1962, QueriedType.Location,
7506 "The typeof operator cannot be used on the dynamic type");
7510 type = ec.BuiltinTypes.Type;
7512 // Even though what is returned is a type object, it's treated as a value by the compiler.
7513 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7514 eclass = ExprClass.Value;
7518 static bool ContainsDynamicType (TypeSpec type)
7520 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7523 var element_container = type as ElementTypeSpec;
7524 if (element_container != null)
7525 return ContainsDynamicType (element_container.Element);
7527 foreach (var t in type.TypeArguments) {
7528 if (ContainsDynamicType (t)) {
7536 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7538 // Target type is not System.Type therefore must be object
7539 // and we need to use different encoding sequence
7540 if (targetType != type)
7543 if (typearg is InflatedTypeSpec) {
7546 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
7547 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7548 typearg.GetSignatureForError ());
7552 gt = gt.DeclaringType;
7553 } while (gt != null);
7556 if (ContainsDynamicType (typearg)) {
7557 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7561 enc.EncodeTypeName (typearg);
7564 public override void Emit (EmitContext ec)
7566 ec.Emit (OpCodes.Ldtoken, typearg);
7567 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7569 ec.Emit (OpCodes.Call, m);
7572 public override object Accept (StructuralVisitor visitor)
7574 return visitor.Visit (this);
7578 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
7580 public TypeOfMethod (MethodSpec method, Location loc)
7581 : base (method, loc)
7585 protected override Expression DoResolve (ResolveContext ec)
7587 if (member.IsConstructor) {
7588 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
7590 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
7596 return base.DoResolve (ec);
7599 public override void Emit (EmitContext ec)
7601 ec.Emit (OpCodes.Ldtoken, member);
7604 ec.Emit (OpCodes.Castclass, type);
7607 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7609 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
7612 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7614 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
7618 abstract class TypeOfMember<T> : Expression where T : MemberSpec
7620 protected readonly T member;
7622 protected TypeOfMember (T member, Location loc)
7624 this.member = member;
7628 public override bool IsSideEffectFree {
7634 public override bool ContainsEmitWithAwait ()
7639 public override Expression CreateExpressionTree (ResolveContext ec)
7641 Arguments args = new Arguments (2);
7642 args.Add (new Argument (this));
7643 args.Add (new Argument (new TypeOf (type, loc)));
7644 return CreateExpressionFactoryCall (ec, "Constant", args);
7647 protected override Expression DoResolve (ResolveContext ec)
7649 eclass = ExprClass.Value;
7653 public override void Emit (EmitContext ec)
7655 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
7656 PredefinedMember<MethodSpec> p;
7658 p = GetTypeFromHandleGeneric (ec);
7659 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
7661 p = GetTypeFromHandle (ec);
7664 var mi = p.Resolve (loc);
7666 ec.Emit (OpCodes.Call, mi);
7669 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
7670 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
7673 sealed class TypeOfField : TypeOfMember<FieldSpec>
7675 public TypeOfField (FieldSpec field, Location loc)
7680 protected override Expression DoResolve (ResolveContext ec)
7682 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
7686 return base.DoResolve (ec);
7689 public override void Emit (EmitContext ec)
7691 ec.Emit (OpCodes.Ldtoken, member);
7695 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7697 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
7700 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7702 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
7707 /// Implements the sizeof expression
7709 public class SizeOf : Expression {
7710 readonly Expression texpr;
7711 TypeSpec type_queried;
7713 public SizeOf (Expression queried_type, Location l)
7715 this.texpr = queried_type;
7719 public override bool IsSideEffectFree {
7725 public Expression TypeExpression {
7731 public override bool ContainsEmitWithAwait ()
7736 public override Expression CreateExpressionTree (ResolveContext ec)
7738 Error_PointerInsideExpressionTree (ec);
7742 protected override Expression DoResolve (ResolveContext ec)
7744 type_queried = texpr.ResolveAsType (ec);
7745 if (type_queried == null)
7748 if (type_queried.IsEnum)
7749 type_queried = EnumSpec.GetUnderlyingType (type_queried);
7751 int size_of = BuiltinTypeSpec.GetSize (type_queried);
7753 return new IntConstant (ec.BuiltinTypes, size_of, loc);
7756 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
7761 ec.Report.Error (233, loc,
7762 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7763 TypeManager.CSharpName (type_queried));
7766 type = ec.BuiltinTypes.Int;
7767 eclass = ExprClass.Value;
7771 public override void Emit (EmitContext ec)
7773 ec.Emit (OpCodes.Sizeof, type_queried);
7776 protected override void CloneTo (CloneContext clonectx, Expression t)
7780 public override object Accept (StructuralVisitor visitor)
7782 return visitor.Visit (this);
7787 /// Implements the qualified-alias-member (::) expression.
7789 public class QualifiedAliasMember : MemberAccess
7791 readonly string alias;
7792 public static readonly string GlobalAlias = "global";
7794 public QualifiedAliasMember (string alias, string identifier, Location l)
7795 : base (null, identifier, l)
7800 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7801 : base (null, identifier, targs, l)
7806 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
7807 : base (null, identifier, arity, l)
7812 public string Alias {
7818 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
7820 if (alias == GlobalAlias) {
7821 expr = ec.Module.GlobalRootNamespace;
7822 return base.ResolveAsTypeOrNamespace (ec);
7825 int errors = ec.Module.Compiler.Report.Errors;
7826 expr = ec.LookupNamespaceAlias (alias);
7828 if (errors == ec.Module.Compiler.Report.Errors)
7829 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7833 return base.ResolveAsTypeOrNamespace (ec);
7836 protected override Expression DoResolve (ResolveContext ec)
7838 return ResolveAsTypeOrNamespace (ec);
7841 public override string GetSignatureForError ()
7844 if (targs != null) {
7845 name = Name + "<" + targs.GetSignatureForError () + ">";
7848 return alias + "::" + name;
7851 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7853 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
7854 rc.Module.Compiler.Report.Error (687, loc,
7855 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
7856 GetSignatureForError ());
7861 return DoResolve (rc);
7864 protected override void CloneTo (CloneContext clonectx, Expression t)
7869 public override object Accept (StructuralVisitor visitor)
7871 return visitor.Visit (this);
7876 /// Implements the member access expression
7878 public class MemberAccess : ATypeNameExpression
7880 protected Expression expr;
7882 public MemberAccess (Expression expr, string id)
7883 : base (id, expr.Location)
7888 public MemberAccess (Expression expr, string identifier, Location loc)
7889 : base (identifier, loc)
7894 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7895 : base (identifier, args, loc)
7900 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
7901 : base (identifier, arity, loc)
7906 public Expression LeftExpression {
7912 public override Location StartLocation {
7914 return expr == null ? loc : expr.StartLocation;
7918 protected override Expression DoResolve (ResolveContext rc)
7920 var e = DoResolveName (rc, null);
7922 if (!rc.OmitStructFlowAnalysis) {
7923 var fe = e as FieldExpr;
7925 fe.VerifyAssignedStructField (rc, null);
7932 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
7934 var e = DoResolveName (rc, rhs);
7936 if (!rc.OmitStructFlowAnalysis) {
7937 var fe = e as FieldExpr;
7938 if (fe != null && fe.InstanceExpression is FieldExpr) {
7939 fe = (FieldExpr) fe.InstanceExpression;
7940 fe.VerifyAssignedStructField (rc, rhs);
7947 Expression DoResolveName (ResolveContext rc, Expression right_side)
7949 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
7953 if (right_side != null) {
7954 if (e is TypeExpr) {
7955 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
7959 e = e.ResolveLValue (rc, right_side);
7961 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
7967 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
7969 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
7970 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
7972 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
7975 public static bool IsValidDotExpression (TypeSpec type)
7977 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
7978 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
7980 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7983 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7985 var sn = expr as SimpleName;
7986 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
7989 // Resolve the expression with flow analysis turned off, we'll do the definite
7990 // assignment checks later. This is because we don't know yet what the expression
7991 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7992 // definite assignment check on the actual field and not on the whole struct.
7994 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
7996 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
7999 // Resolve expression which does have type set as we need expression type
8000 // with disable flow analysis as we don't know whether left side expression
8001 // is used as variable or type
8003 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8004 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
8005 expr = expr.Resolve (rc);
8007 } else if (expr is TypeParameterExpr) {
8008 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8012 expr = expr.Resolve (rc, flags);
8019 Namespace ns = expr as Namespace;
8021 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8023 if (retval == null) {
8024 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8028 if (HasTypeArguments)
8029 return new GenericTypeExpr (retval.Type, targs, loc);
8035 TypeSpec expr_type = expr.Type;
8036 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8037 me = expr as MemberExpr;
8039 me.ResolveInstanceExpression (rc, null);
8042 // Run defined assigned checks on expressions resolved with
8043 // disabled flow-analysis
8046 var vr = expr as VariableReference;
8048 vr.VerifyAssigned (rc);
8051 Arguments args = new Arguments (1);
8052 args.Add (new Argument (expr));
8053 return new DynamicMemberBinder (Name, args, loc);
8056 if (!IsValidDotExpression (expr_type)) {
8057 Error_OperatorCannotBeApplied (rc, expr_type);
8061 var lookup_arity = Arity;
8062 bool errorMode = false;
8063 Expression member_lookup;
8065 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8066 if (member_lookup == null) {
8068 // Try to look for extension method when member lookup failed
8070 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8071 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8072 if (methods != null) {
8073 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8074 if (HasTypeArguments) {
8075 if (!targs.Resolve (rc))
8078 emg.SetTypeArguments (rc, targs);
8082 // Run defined assigned checks on expressions resolved with
8083 // disabled flow-analysis
8085 if (sn != null && !errorMode) {
8086 var vr = expr as VariableReference;
8088 vr.VerifyAssigned (rc);
8091 // TODO: it should really skip the checks bellow
8092 return emg.Resolve (rc);
8098 if (member_lookup == null) {
8099 var dep = expr_type.GetMissingDependencies ();
8101 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8102 } else if (expr is TypeExpr) {
8103 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8105 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8111 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8112 // Leave it to overload resolution to report correct error
8113 } else if (!(member_lookup is TypeExpr)) {
8114 // TODO: rc.SymbolRelatedToPreviousError
8115 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8120 if (member_lookup != null)
8124 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8128 TypeExpr texpr = member_lookup as TypeExpr;
8129 if (texpr != null) {
8130 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8131 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8132 Name, texpr.GetSignatureForError ());
8135 if (!texpr.Type.IsAccessible (rc)) {
8136 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8137 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8141 if (HasTypeArguments) {
8142 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8145 return member_lookup;
8148 me = member_lookup as MemberExpr;
8150 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8154 me = me.ResolveMemberAccess (rc, expr, sn);
8157 if (!targs.Resolve (rc))
8160 me.SetTypeArguments (rc, targs);
8164 // Run defined assigned checks on expressions resolved with
8165 // disabled flow-analysis
8167 if (sn != null && !(me is FieldExpr && TypeSpec.IsValueType (expr_type))) {
8168 var vr = expr as VariableReference;
8170 vr.VerifyAssigned (rc);
8176 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8178 FullNamedExpression fexpr = expr as FullNamedExpression;
8179 if (fexpr == null) {
8180 expr.ResolveAsType (rc);
8184 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8186 if (expr_resolved == null)
8189 Namespace ns = expr_resolved as Namespace;
8191 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8193 if (retval == null) {
8194 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8195 } else if (HasTypeArguments) {
8196 retval = new GenericTypeExpr (retval.Type, targs, loc);
8197 if (retval.ResolveAsType (rc) == null)
8204 var tnew_expr = expr_resolved.ResolveAsType (rc);
8205 if (tnew_expr == null)
8208 TypeSpec expr_type = tnew_expr;
8209 if (TypeManager.IsGenericParameter (expr_type)) {
8210 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8211 tnew_expr.GetSignatureForError ());
8215 var qam = this as QualifiedAliasMember;
8217 rc.Module.Compiler.Report.Error (431, loc,
8218 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8223 TypeSpec nested = null;
8224 while (expr_type != null) {
8225 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8226 if (nested == null) {
8227 if (expr_type == tnew_expr) {
8228 Error_IdentifierNotFound (rc, expr_type, Name);
8232 expr_type = tnew_expr;
8233 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8234 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
8238 if (nested.IsAccessible (rc))
8242 // Keep looking after inaccessible candidate but only if
8243 // we are not in same context as the definition itself
8245 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
8248 expr_type = expr_type.BaseType;
8253 if (HasTypeArguments) {
8254 texpr = new GenericTypeExpr (nested, targs, loc);
8256 texpr = new GenericOpenTypeExpr (nested, loc);
8259 texpr = new TypeExpression (nested, loc);
8262 if (texpr.ResolveAsType (rc) == null)
8268 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
8270 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
8272 if (nested != null) {
8273 Error_TypeArgumentsCannotBeUsed (rc, nested, Arity, expr.Location);
8277 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
8278 if (any_other_member != null) {
8279 any_other_member.Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
8283 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
8284 Name, expr_type.GetSignatureForError ());
8287 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
8289 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
8292 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
8294 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8295 ec.Report.SymbolRelatedToPreviousError (type);
8297 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, type, name, Arity);
8299 // a using directive or an assembly reference
8301 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
8303 missing = "an assembly reference";
8306 ec.Report.Error (1061, loc,
8307 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
8308 type.GetSignatureForError (), name, missing);
8312 base.Error_TypeDoesNotContainDefinition (ec, type, name);
8315 public override string GetSignatureForError ()
8317 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
8320 protected override void CloneTo (CloneContext clonectx, Expression t)
8322 MemberAccess target = (MemberAccess) t;
8324 target.expr = expr.Clone (clonectx);
8327 public override object Accept (StructuralVisitor visitor)
8329 return visitor.Visit (this);
8334 /// Implements checked expressions
8336 public class CheckedExpr : Expression {
8338 public Expression Expr;
8340 public CheckedExpr (Expression e, Location l)
8346 public override bool ContainsEmitWithAwait ()
8348 return Expr.ContainsEmitWithAwait ();
8351 public override Expression CreateExpressionTree (ResolveContext ec)
8353 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
8354 return Expr.CreateExpressionTree (ec);
8357 protected override Expression DoResolve (ResolveContext ec)
8359 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
8360 Expr = Expr.Resolve (ec);
8365 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8368 eclass = Expr.eclass;
8373 public override void Emit (EmitContext ec)
8375 using (ec.With (EmitContext.Options.CheckedScope, true))
8379 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8381 using (ec.With (EmitContext.Options.CheckedScope, true))
8382 Expr.EmitBranchable (ec, target, on_true);
8385 public override SLE.Expression MakeExpression (BuilderContext ctx)
8387 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
8388 return Expr.MakeExpression (ctx);
8392 protected override void CloneTo (CloneContext clonectx, Expression t)
8394 CheckedExpr target = (CheckedExpr) t;
8396 target.Expr = Expr.Clone (clonectx);
8399 public override object Accept (StructuralVisitor visitor)
8401 return visitor.Visit (this);
8406 /// Implements the unchecked expression
8408 public class UnCheckedExpr : Expression {
8410 public Expression Expr;
8412 public UnCheckedExpr (Expression e, Location l)
8418 public override bool ContainsEmitWithAwait ()
8420 return Expr.ContainsEmitWithAwait ();
8423 public override Expression CreateExpressionTree (ResolveContext ec)
8425 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8426 return Expr.CreateExpressionTree (ec);
8429 protected override Expression DoResolve (ResolveContext ec)
8431 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8432 Expr = Expr.Resolve (ec);
8437 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8440 eclass = Expr.eclass;
8445 public override void Emit (EmitContext ec)
8447 using (ec.With (EmitContext.Options.CheckedScope, false))
8451 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8453 using (ec.With (EmitContext.Options.CheckedScope, false))
8454 Expr.EmitBranchable (ec, target, on_true);
8457 protected override void CloneTo (CloneContext clonectx, Expression t)
8459 UnCheckedExpr target = (UnCheckedExpr) t;
8461 target.Expr = Expr.Clone (clonectx);
8464 public override object Accept (StructuralVisitor visitor)
8466 return visitor.Visit (this);
8471 /// An Element Access expression.
8473 /// During semantic analysis these are transformed into
8474 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
8476 public class ElementAccess : Expression
8478 public Arguments Arguments;
8479 public Expression Expr;
8481 public ElementAccess (Expression e, Arguments args, Location loc)
8485 this.Arguments = args;
8488 public override Location StartLocation {
8490 return Expr.StartLocation;
8494 public override bool ContainsEmitWithAwait ()
8496 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
8500 // We perform some simple tests, and then to "split" the emit and store
8501 // code we create an instance of a different class, and return that.
8503 Expression CreateAccessExpression (ResolveContext ec)
8506 return (new ArrayAccess (this, loc));
8509 return MakePointerAccess (ec, type);
8511 FieldExpr fe = Expr as FieldExpr;
8513 var ff = fe.Spec as FixedFieldSpec;
8515 return MakePointerAccess (ec, ff.ElementType);
8519 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
8520 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8521 return new IndexerExpr (indexers, type, this);
8524 if (type != InternalType.ErrorType) {
8525 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8526 type.GetSignatureForError ());
8532 public override Expression CreateExpressionTree (ResolveContext ec)
8534 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
8535 Expr.CreateExpressionTree (ec));
8537 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
8540 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
8542 if (Arguments.Count != 1){
8543 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
8547 if (Arguments [0] is NamedArgument)
8548 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
8550 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
8551 return new Indirection (p, loc);
8554 protected override Expression DoResolve (ResolveContext ec)
8556 Expr = Expr.Resolve (ec);
8562 // TODO: Create 1 result for Resolve and ResolveLValue ?
8563 var res = CreateAccessExpression (ec);
8567 return res.Resolve (ec);
8570 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
8572 Expr = Expr.Resolve (ec);
8578 var res = CreateAccessExpression (ec);
8582 return res.ResolveLValue (ec, rhs);
8585 public override void Emit (EmitContext ec)
8587 throw new Exception ("Should never be reached");
8590 public static void Error_NamedArgument (NamedArgument na, Report Report)
8592 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
8595 public override string GetSignatureForError ()
8597 return Expr.GetSignatureForError ();
8600 protected override void CloneTo (CloneContext clonectx, Expression t)
8602 ElementAccess target = (ElementAccess) t;
8604 target.Expr = Expr.Clone (clonectx);
8605 if (Arguments != null)
8606 target.Arguments = Arguments.Clone (clonectx);
8609 public override object Accept (StructuralVisitor visitor)
8611 return visitor.Visit (this);
8616 /// Implements array access
8618 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
8620 // Points to our "data" repository
8624 LocalTemporary temp;
8626 bool? has_await_args;
8628 public ArrayAccess (ElementAccess ea_data, Location l)
8634 public void AddressOf (EmitContext ec, AddressOp mode)
8636 var ac = (ArrayContainer) ea.Expr.Type;
8638 LoadInstanceAndArguments (ec, false, false);
8640 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
8641 ec.Emit (OpCodes.Readonly);
8643 ec.EmitArrayAddress (ac);
8646 public override Expression CreateExpressionTree (ResolveContext ec)
8648 return ea.CreateExpressionTree (ec);
8651 public override bool ContainsEmitWithAwait ()
8653 return ea.ContainsEmitWithAwait ();
8656 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8658 return DoResolve (ec);
8661 protected override Expression DoResolve (ResolveContext ec)
8663 // dynamic is used per argument in ConvertExpressionToArrayIndex case
8665 ea.Arguments.Resolve (ec, out dynamic);
8667 var ac = ea.Expr.Type as ArrayContainer;
8668 int rank = ea.Arguments.Count;
8669 if (ac.Rank != rank) {
8670 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8671 rank.ToString (), ac.Rank.ToString ());
8676 if (type.IsPointer && !ec.IsUnsafe) {
8677 UnsafeError (ec, ea.Location);
8680 foreach (Argument a in ea.Arguments) {
8681 if (a is NamedArgument)
8682 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
8684 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
8687 eclass = ExprClass.Variable;
8692 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8694 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8698 // Load the array arguments into the stack.
8700 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
8703 ea.Expr = ea.Expr.EmitToField (ec);
8704 } else if (duplicateArguments) {
8706 ec.Emit (OpCodes.Dup);
8708 var copy = new LocalTemporary (ea.Expr.Type);
8715 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
8716 if (dup_args != null)
8717 ea.Arguments = dup_args;
8720 public void Emit (EmitContext ec, bool leave_copy)
8722 var ac = ea.Expr.Type as ArrayContainer;
8725 ec.EmitLoadFromPtr (type);
8727 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
8728 LoadInstanceAndArguments (ec, false, true);
8731 LoadInstanceAndArguments (ec, false, false);
8732 ec.EmitArrayLoad (ac);
8736 ec.Emit (OpCodes.Dup);
8737 temp = new LocalTemporary (this.type);
8742 public override void Emit (EmitContext ec)
8747 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8749 var ac = (ArrayContainer) ea.Expr.Type;
8750 TypeSpec t = source.Type;
8752 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
8755 // When we are dealing with a struct, get the address of it to avoid value copy
8756 // Same cannot be done for reference type because array covariance and the
8757 // check in ldelema requires to specify the type of array element stored at the index
8759 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
8760 LoadInstanceAndArguments (ec, false, has_await_args.Value);
8762 if (has_await_args.Value) {
8763 if (source.ContainsEmitWithAwait ()) {
8764 source = source.EmitToField (ec);
8769 LoadInstanceAndArguments (ec, isCompound, false);
8774 ec.EmitArrayAddress (ac);
8777 ec.Emit (OpCodes.Dup);
8781 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
8783 if (has_await_args.Value) {
8784 if (source.ContainsEmitWithAwait ())
8785 source = source.EmitToField (ec);
8787 LoadInstanceAndArguments (ec, false, false);
8794 var lt = ea.Expr as LocalTemporary;
8800 ec.Emit (OpCodes.Dup);
8801 temp = new LocalTemporary (this.type);
8806 ec.EmitStoreFromPtr (t);
8808 ec.EmitArrayStore (ac);
8817 public override Expression EmitToField (EmitContext ec)
8820 // Have to be specialized for arrays to get access to
8821 // underlying element. Instead of another result copy we
8822 // need direct access to element
8826 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
8828 ea.Expr = ea.Expr.EmitToField (ec);
8832 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8834 #if NET_4_0 || MONODROID
8835 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8837 throw new NotImplementedException ();
8841 public override SLE.Expression MakeExpression (BuilderContext ctx)
8843 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8846 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
8848 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
8849 return Arguments.MakeExpression (ea.Arguments, ctx);
8855 // Indexer access expression
8857 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
8859 IList<MemberSpec> indexers;
8860 Arguments arguments;
8861 TypeSpec queried_type;
8863 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
8864 : base (ea.Location)
8866 this.indexers = indexers;
8867 this.queried_type = queriedType;
8868 this.InstanceExpression = ea.Expr;
8869 this.arguments = ea.Arguments;
8874 protected override Arguments Arguments {
8883 protected override TypeSpec DeclaringType {
8885 return best_candidate.DeclaringType;
8889 public override bool IsInstance {
8895 public override bool IsStatic {
8901 public override string KindName {
8902 get { return "indexer"; }
8905 public override string Name {
8913 public override bool ContainsEmitWithAwait ()
8915 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
8918 public override Expression CreateExpressionTree (ResolveContext ec)
8920 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8921 InstanceExpression.CreateExpressionTree (ec),
8922 new TypeOfMethod (Getter, loc));
8924 return CreateExpressionFactoryCall (ec, "Call", args);
8927 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8929 LocalTemporary await_source_arg = null;
8932 emitting_compound_assignment = true;
8933 if (source is DynamicExpressionStatement) {
8938 emitting_compound_assignment = false;
8940 if (has_await_arguments) {
8941 await_source_arg = new LocalTemporary (Type);
8942 await_source_arg.Store (ec);
8944 arguments.Add (new Argument (await_source_arg));
8947 temp = await_source_arg;
8950 has_await_arguments = false;
8955 ec.Emit (OpCodes.Dup);
8956 temp = new LocalTemporary (Type);
8962 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
8963 source = source.EmitToField (ec);
8965 temp = new LocalTemporary (Type);
8972 arguments.Add (new Argument (source));
8975 var call = new CallEmitter ();
8976 call.InstanceExpression = InstanceExpression;
8977 if (arguments == null)
8978 call.InstanceExpressionOnStack = true;
8980 call.Emit (ec, Setter, arguments, loc);
8985 } else if (leave_copy) {
8989 if (await_source_arg != null) {
8990 await_source_arg.Release (ec);
8994 public override string GetSignatureForError ()
8996 return best_candidate.GetSignatureForError ();
8999 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9002 throw new NotSupportedException ();
9004 var value = new[] { source.MakeExpression (ctx) };
9005 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9006 #if NET_4_0 || MONODROID
9007 return SLE.Expression.Block (
9008 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9011 return args.First ();
9016 public override SLE.Expression MakeExpression (BuilderContext ctx)
9019 return base.MakeExpression (ctx);
9021 var args = Arguments.MakeExpression (arguments, ctx);
9022 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9026 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9028 if (best_candidate != null)
9031 eclass = ExprClass.IndexerAccess;
9034 arguments.Resolve (rc, out dynamic);
9036 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9039 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9040 res.BaseMembersProvider = this;
9041 res.InstanceQualifier = this;
9043 // TODO: Do I need 2 argument sets?
9044 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9045 if (best_candidate != null)
9046 type = res.BestCandidateReturnType;
9047 else if (!res.BestCandidateIsDynamic)
9052 // It has dynamic arguments
9055 Arguments args = new Arguments (arguments.Count + 1);
9057 rc.Report.Error (1972, loc,
9058 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9060 args.Add (new Argument (InstanceExpression));
9062 args.AddRange (arguments);
9064 best_candidate = null;
9065 return new DynamicIndexBinder (args, loc);
9069 // Try to avoid resolving left expression again
9071 if (right_side != null)
9072 ResolveInstanceExpression (rc, right_side);
9077 protected override void CloneTo (CloneContext clonectx, Expression t)
9079 IndexerExpr target = (IndexerExpr) t;
9081 if (arguments != null)
9082 target.arguments = arguments.Clone (clonectx);
9085 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9087 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9090 #region IBaseMembersProvider Members
9092 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9094 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9097 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9099 if (queried_type == member.DeclaringType)
9102 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9103 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9106 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9115 // A base access expression
9117 public class BaseThis : This
9119 public BaseThis (Location loc)
9124 public BaseThis (TypeSpec type, Location loc)
9128 eclass = ExprClass.Variable;
9133 public override string Name {
9141 public override Expression CreateExpressionTree (ResolveContext ec)
9143 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9144 return base.CreateExpressionTree (ec);
9147 public override void Emit (EmitContext ec)
9151 var context_type = ec.CurrentType;
9152 if (context_type.IsStruct) {
9153 ec.Emit (OpCodes.Ldobj, context_type);
9154 ec.Emit (OpCodes.Box, context_type);
9158 protected override void Error_ThisNotAvailable (ResolveContext ec)
9161 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9163 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9167 public override void ResolveBase (ResolveContext ec)
9169 base.ResolveBase (ec);
9170 type = ec.CurrentType.BaseType;
9173 public override object Accept (StructuralVisitor visitor)
9175 return visitor.Visit (this);
9180 /// This class exists solely to pass the Type around and to be a dummy
9181 /// that can be passed to the conversion functions (this is used by
9182 /// foreach implementation to typecast the object return value from
9183 /// get_Current into the proper type. All code has been generated and
9184 /// we only care about the side effect conversions to be performed
9186 /// This is also now used as a placeholder where a no-action expression
9187 /// is needed (the `New' class).
9189 public class EmptyExpression : Expression
9191 sealed class OutAccessExpression : EmptyExpression
9193 public OutAccessExpression (TypeSpec t)
9198 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9200 rc.Report.Error (206, right_side.Location,
9201 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
9207 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
9208 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
9209 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
9210 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
9211 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
9212 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
9213 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
9214 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
9216 public EmptyExpression (TypeSpec t)
9219 eclass = ExprClass.Value;
9220 loc = Location.Null;
9223 public override bool ContainsEmitWithAwait ()
9228 public override Expression CreateExpressionTree (ResolveContext ec)
9230 throw new NotSupportedException ("ET");
9233 protected override Expression DoResolve (ResolveContext ec)
9238 public override void Emit (EmitContext ec)
9240 // nothing, as we only exist to not do anything.
9243 public override void EmitSideEffect (EmitContext ec)
9247 public override object Accept (StructuralVisitor visitor)
9249 return visitor.Visit (this);
9253 sealed class EmptyAwaitExpression : EmptyExpression
9255 public EmptyAwaitExpression (TypeSpec type)
9260 public override bool ContainsEmitWithAwait ()
9267 // Empty statement expression
9269 public sealed class EmptyExpressionStatement : ExpressionStatement
9271 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
9273 private EmptyExpressionStatement ()
9275 loc = Location.Null;
9278 public override bool ContainsEmitWithAwait ()
9283 public override Expression CreateExpressionTree (ResolveContext ec)
9288 public override void EmitStatement (EmitContext ec)
9293 protected override Expression DoResolve (ResolveContext ec)
9295 eclass = ExprClass.Value;
9296 type = ec.BuiltinTypes.Object;
9300 public override void Emit (EmitContext ec)
9305 public override object Accept (StructuralVisitor visitor)
9307 return visitor.Visit (this);
9311 public class ErrorExpression : EmptyExpression
9313 public static readonly ErrorExpression Instance = new ErrorExpression ();
9315 private ErrorExpression ()
9316 : base (InternalType.ErrorType)
9320 public override Expression CreateExpressionTree (ResolveContext ec)
9325 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9330 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
9334 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
9338 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
9342 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
9346 public override object Accept (StructuralVisitor visitor)
9348 return visitor.Visit (this);
9352 public class UserCast : Expression {
9356 public UserCast (MethodSpec method, Expression source, Location l)
9359 throw new ArgumentNullException ("source");
9361 this.method = method;
9362 this.source = source;
9363 type = method.ReturnType;
9367 public Expression Source {
9373 public override bool ContainsEmitWithAwait ()
9375 return source.ContainsEmitWithAwait ();
9378 public override Expression CreateExpressionTree (ResolveContext ec)
9380 Arguments args = new Arguments (3);
9381 args.Add (new Argument (source.CreateExpressionTree (ec)));
9382 args.Add (new Argument (new TypeOf (type, loc)));
9383 args.Add (new Argument (new TypeOfMethod (method, loc)));
9384 return CreateExpressionFactoryCall (ec, "Convert", args);
9387 protected override Expression DoResolve (ResolveContext ec)
9389 ObsoleteAttribute oa = method.GetAttributeObsolete ();
9391 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
9393 eclass = ExprClass.Value;
9397 public override void Emit (EmitContext ec)
9400 ec.Emit (OpCodes.Call, method);
9403 public override string GetSignatureForError ()
9405 return TypeManager.CSharpSignature (method);
9408 public override SLE.Expression MakeExpression (BuilderContext ctx)
9411 return base.MakeExpression (ctx);
9413 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
9419 // Holds additional type specifiers like ?, *, []
9421 public class ComposedTypeSpecifier
9423 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
9425 public readonly int Dimension;
9426 public readonly Location Location;
9428 public ComposedTypeSpecifier (int specifier, Location loc)
9430 this.Dimension = specifier;
9431 this.Location = loc;
9435 public bool IsNullable {
9437 return Dimension == -1;
9441 public bool IsPointer {
9443 return Dimension == -2;
9447 public ComposedTypeSpecifier Next { get; set; }
9451 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
9453 return new ComposedTypeSpecifier (dimension, loc);
9456 public static ComposedTypeSpecifier CreateNullable (Location loc)
9458 return new ComposedTypeSpecifier (-1, loc);
9461 public static ComposedTypeSpecifier CreatePointer (Location loc)
9463 return new ComposedTypeSpecifier (-2, loc);
9466 public string GetSignatureForError ()
9471 ArrayContainer.GetPostfixSignature (Dimension);
9473 return Next != null ? s + Next.GetSignatureForError () : s;
9478 // This class is used to "construct" the type during a typecast
9479 // operation. Since the Type.GetType class in .NET can parse
9480 // the type specification, we just use this to construct the type
9481 // one bit at a time.
9483 public class ComposedCast : TypeExpr {
9484 FullNamedExpression left;
9485 ComposedTypeSpecifier spec;
9487 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
9490 throw new ArgumentNullException ("spec");
9494 this.loc = left.Location;
9497 public override TypeSpec ResolveAsType (IMemberContext ec)
9499 type = left.ResolveAsType (ec);
9503 eclass = ExprClass.Type;
9505 var single_spec = spec;
9507 if (single_spec.IsNullable) {
9508 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
9512 single_spec = single_spec.Next;
9513 } else if (single_spec.IsPointer) {
9514 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
9518 UnsafeError (ec.Module.Compiler.Report, loc);
9522 type = PointerContainer.MakeType (ec.Module, type);
9523 single_spec = single_spec.Next;
9524 } while (single_spec != null && single_spec.IsPointer);
9527 if (single_spec != null && single_spec.Dimension > 0) {
9528 if (type.IsSpecialRuntimeType) {
9529 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
9530 } else if (type.IsStatic) {
9531 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
9532 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9533 type.GetSignatureForError ());
9535 MakeArray (ec.Module, single_spec);
9542 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
9544 if (spec.Next != null)
9545 MakeArray (module, spec.Next);
9547 type = ArrayContainer.MakeType (module, type, spec.Dimension);
9550 public override string GetSignatureForError ()
9552 return left.GetSignatureForError () + spec.GetSignatureForError ();
9555 public override object Accept (StructuralVisitor visitor)
9557 return visitor.Visit (this);
9561 class FixedBufferPtr : Expression
9563 readonly Expression array;
9565 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
9567 this.type = array_type;
9572 public override bool ContainsEmitWithAwait ()
9574 throw new NotImplementedException ();
9577 public override Expression CreateExpressionTree (ResolveContext ec)
9579 Error_PointerInsideExpressionTree (ec);
9583 public override void Emit(EmitContext ec)
9588 protected override Expression DoResolve (ResolveContext ec)
9590 type = PointerContainer.MakeType (ec.Module, type);
9591 eclass = ExprClass.Value;
9598 // This class is used to represent the address of an array, used
9599 // only by the Fixed statement, this generates "&a [0]" construct
9600 // for fixed (char *pa = a)
9602 class ArrayPtr : FixedBufferPtr
9604 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
9605 base (array, array_type, l)
9609 public override void Emit (EmitContext ec)
9614 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
9619 // Encapsulates a conversion rules required for array indexes
9621 public class ArrayIndexCast : TypeCast
9623 public ArrayIndexCast (Expression expr, TypeSpec returnType)
9624 : base (expr, returnType)
9626 if (expr.Type == returnType) // int -> int
9627 throw new ArgumentException ("unnecessary array index conversion");
9630 public override Expression CreateExpressionTree (ResolveContext ec)
9632 using (ec.Set (ResolveContext.Options.CheckedScope)) {
9633 return base.CreateExpressionTree (ec);
9637 public override void Emit (EmitContext ec)
9641 switch (child.Type.BuiltinType) {
9642 case BuiltinTypeSpec.Type.UInt:
9643 ec.Emit (OpCodes.Conv_U);
9645 case BuiltinTypeSpec.Type.Long:
9646 ec.Emit (OpCodes.Conv_Ovf_I);
9648 case BuiltinTypeSpec.Type.ULong:
9649 ec.Emit (OpCodes.Conv_Ovf_I_Un);
9652 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9658 // Implements the `stackalloc' keyword
9660 public class StackAlloc : Expression {
9665 public StackAlloc (Expression type, Expression count, Location l)
9672 public Expression TypeExpression {
9678 public Expression CountExpression {
9684 public override bool ContainsEmitWithAwait ()
9689 public override Expression CreateExpressionTree (ResolveContext ec)
9691 throw new NotSupportedException ("ET");
9694 protected override Expression DoResolve (ResolveContext ec)
9696 count = count.Resolve (ec);
9700 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
9701 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
9706 Constant c = count as Constant;
9707 if (c != null && c.IsNegative) {
9708 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9711 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9712 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9715 otype = t.ResolveAsType (ec);
9719 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
9722 type = PointerContainer.MakeType (ec.Module, otype);
9723 eclass = ExprClass.Value;
9728 public override void Emit (EmitContext ec)
9730 int size = BuiltinTypeSpec.GetSize (otype);
9735 ec.Emit (OpCodes.Sizeof, otype);
9739 ec.Emit (OpCodes.Mul_Ovf_Un);
9740 ec.Emit (OpCodes.Localloc);
9743 protected override void CloneTo (CloneContext clonectx, Expression t)
9745 StackAlloc target = (StackAlloc) t;
9746 target.count = count.Clone (clonectx);
9747 target.t = t.Clone (clonectx);
9750 public override object Accept (StructuralVisitor visitor)
9752 return visitor.Visit (this);
9757 // An object initializer expression
9759 public class ElementInitializer : Assign
9761 public readonly string Name;
9763 public ElementInitializer (string name, Expression initializer, Location loc)
9764 : base (null, initializer, loc)
9769 protected override void CloneTo (CloneContext clonectx, Expression t)
9771 ElementInitializer target = (ElementInitializer) t;
9772 target.source = source.Clone (clonectx);
9775 public override Expression CreateExpressionTree (ResolveContext ec)
9777 Arguments args = new Arguments (2);
9778 FieldExpr fe = target as FieldExpr;
9780 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9782 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
9785 Expression arg_expr;
9786 var cinit = source as CollectionOrObjectInitializers;
9787 if (cinit == null) {
9789 arg_expr = source.CreateExpressionTree (ec);
9791 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
9792 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
9795 args.Add (new Argument (arg_expr));
9796 return CreateExpressionFactoryCall (ec, mname, args);
9799 protected override Expression DoResolve (ResolveContext ec)
9802 return EmptyExpressionStatement.Instance;
9804 var t = ec.CurrentInitializerVariable.Type;
9805 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9806 Arguments args = new Arguments (1);
9807 args.Add (new Argument (ec.CurrentInitializerVariable));
9808 target = new DynamicMemberBinder (Name, args, loc);
9811 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9812 if (member == null) {
9813 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9815 if (member != null) {
9816 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
9817 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
9822 if (member == null) {
9823 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
9827 if (!(member is PropertyExpr || member is FieldExpr)) {
9828 ec.Report.Error (1913, loc,
9829 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
9830 member.GetSignatureForError ());
9835 var me = member as MemberExpr;
9837 ec.Report.Error (1914, loc,
9838 "Static field or property `{0}' cannot be assigned in an object initializer",
9839 me.GetSignatureForError ());
9843 me.InstanceExpression = ec.CurrentInitializerVariable;
9846 if (source is CollectionOrObjectInitializers) {
9847 Expression previous = ec.CurrentInitializerVariable;
9848 ec.CurrentInitializerVariable = target;
9849 source = source.Resolve (ec);
9850 ec.CurrentInitializerVariable = previous;
9854 eclass = source.eclass;
9859 return base.DoResolve (ec);
9862 public override void EmitStatement (EmitContext ec)
9864 if (source is CollectionOrObjectInitializers)
9867 base.EmitStatement (ec);
9872 // A collection initializer expression
9874 class CollectionElementInitializer : Invocation
9876 public class ElementInitializerArgument : Argument
9878 public ElementInitializerArgument (Expression e)
9884 sealed class AddMemberAccess : MemberAccess
9886 public AddMemberAccess (Expression expr, Location loc)
9887 : base (expr, "Add", loc)
9891 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9893 if (TypeManager.HasElementType (type))
9896 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9900 public CollectionElementInitializer (Expression argument)
9901 : base (null, new Arguments (1))
9903 base.arguments.Add (new ElementInitializerArgument (argument));
9904 this.loc = argument.Location;
9907 public CollectionElementInitializer (List<Expression> arguments, Location loc)
9908 : base (null, new Arguments (arguments.Count))
9910 foreach (Expression e in arguments)
9911 base.arguments.Add (new ElementInitializerArgument (e));
9916 public override Expression CreateExpressionTree (ResolveContext ec)
9918 Arguments args = new Arguments (2);
9919 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9921 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
9922 foreach (Argument a in arguments)
9923 expr_initializers.Add (a.CreateExpressionTree (ec));
9925 args.Add (new Argument (new ArrayCreation (
9926 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
9927 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9930 protected override void CloneTo (CloneContext clonectx, Expression t)
9932 CollectionElementInitializer target = (CollectionElementInitializer) t;
9933 if (arguments != null)
9934 target.arguments = arguments.Clone (clonectx);
9937 protected override Expression DoResolve (ResolveContext ec)
9939 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9941 return base.DoResolve (ec);
9946 // A block of object or collection initializers
9948 public class CollectionOrObjectInitializers : ExpressionStatement
9950 IList<Expression> initializers;
9951 bool is_collection_initialization;
9953 public CollectionOrObjectInitializers (Location loc)
9954 : this (new Expression[0], loc)
9958 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
9960 this.initializers = initializers;
9964 public IList<Expression> Initializers {
9966 return initializers;
9970 public bool IsEmpty {
9972 return initializers.Count == 0;
9976 public bool IsCollectionInitializer {
9978 return is_collection_initialization;
9982 protected override void CloneTo (CloneContext clonectx, Expression target)
9984 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9986 t.initializers = new List<Expression> (initializers.Count);
9987 foreach (var e in initializers)
9988 t.initializers.Add (e.Clone (clonectx));
9991 public override bool ContainsEmitWithAwait ()
9993 foreach (var e in initializers) {
9994 if (e.ContainsEmitWithAwait ())
10001 public override Expression CreateExpressionTree (ResolveContext ec)
10003 return CreateExpressionTree (ec, false);
10006 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10008 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10009 foreach (Expression e in initializers) {
10010 Expression expr = e.CreateExpressionTree (ec);
10012 expr_initializers.Add (expr);
10016 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10018 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10021 protected override Expression DoResolve (ResolveContext ec)
10023 List<string> element_names = null;
10024 for (int i = 0; i < initializers.Count; ++i) {
10025 Expression initializer = initializers [i];
10026 ElementInitializer element_initializer = initializer as ElementInitializer;
10029 if (element_initializer != null) {
10030 element_names = new List<string> (initializers.Count);
10031 element_names.Add (element_initializer.Name);
10032 } else if (initializer is CompletingExpression){
10033 initializer.Resolve (ec);
10034 throw new InternalErrorException ("This line should never be reached");
10036 var t = ec.CurrentInitializerVariable.Type;
10037 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10038 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10039 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10040 "object initializer because type `{1}' does not implement `{2}' interface",
10041 ec.CurrentInitializerVariable.GetSignatureForError (),
10042 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
10043 TypeManager.CSharpName (ec.BuiltinTypes.IEnumerable));
10046 is_collection_initialization = true;
10049 if (is_collection_initialization != (element_initializer == null)) {
10050 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10051 is_collection_initialization ? "collection initializer" : "object initializer");
10055 if (!is_collection_initialization) {
10056 if (element_names.Contains (element_initializer.Name)) {
10057 ec.Report.Error (1912, element_initializer.Location,
10058 "An object initializer includes more than one member `{0}' initialization",
10059 element_initializer.Name);
10061 element_names.Add (element_initializer.Name);
10066 Expression e = initializer.Resolve (ec);
10067 if (e == EmptyExpressionStatement.Instance)
10068 initializers.RemoveAt (i--);
10070 initializers [i] = e;
10073 type = ec.CurrentInitializerVariable.Type;
10074 if (is_collection_initialization) {
10075 if (TypeManager.HasElementType (type)) {
10076 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10077 TypeManager.CSharpName (type));
10081 eclass = ExprClass.Variable;
10085 public override void Emit (EmitContext ec)
10087 EmitStatement (ec);
10090 public override void EmitStatement (EmitContext ec)
10092 foreach (ExpressionStatement e in initializers) {
10093 // TODO: need location region
10094 ec.Mark (e.Location);
10095 e.EmitStatement (ec);
10101 // New expression with element/object initializers
10103 public class NewInitialize : New
10106 // This class serves as a proxy for variable initializer target instances.
10107 // A real variable is assigned later when we resolve left side of an
10110 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10112 NewInitialize new_instance;
10114 public InitializerTargetExpression (NewInitialize newInstance)
10116 this.type = newInstance.type;
10117 this.loc = newInstance.loc;
10118 this.eclass = newInstance.eclass;
10119 this.new_instance = newInstance;
10122 public override bool ContainsEmitWithAwait ()
10127 public override Expression CreateExpressionTree (ResolveContext ec)
10129 // Should not be reached
10130 throw new NotSupportedException ("ET");
10133 protected override Expression DoResolve (ResolveContext ec)
10138 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10143 public override void Emit (EmitContext ec)
10145 Expression e = (Expression) new_instance.instance;
10149 public override Expression EmitToField (EmitContext ec)
10151 return (Expression) new_instance.instance;
10154 #region IMemoryLocation Members
10156 public void AddressOf (EmitContext ec, AddressOp mode)
10158 new_instance.instance.AddressOf (ec, mode);
10164 CollectionOrObjectInitializers initializers;
10165 IMemoryLocation instance;
10166 DynamicExpressionStatement dynamic;
10168 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10169 : base (requested_type, arguments, l)
10171 this.initializers = initializers;
10174 public CollectionOrObjectInitializers Initializers {
10176 return initializers;
10180 protected override void CloneTo (CloneContext clonectx, Expression t)
10182 base.CloneTo (clonectx, t);
10184 NewInitialize target = (NewInitialize) t;
10185 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
10188 public override bool ContainsEmitWithAwait ()
10190 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
10193 public override Expression CreateExpressionTree (ResolveContext ec)
10195 Arguments args = new Arguments (2);
10196 args.Add (new Argument (base.CreateExpressionTree (ec)));
10197 if (!initializers.IsEmpty)
10198 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
10200 return CreateExpressionFactoryCall (ec,
10201 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
10205 protected override Expression DoResolve (ResolveContext ec)
10207 Expression e = base.DoResolve (ec);
10211 if (type.IsDelegate) {
10212 ec.Report.Error (1958, Initializers.Location,
10213 "Object and collection initializers cannot be used to instantiate a delegate");
10216 Expression previous = ec.CurrentInitializerVariable;
10217 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
10218 initializers.Resolve (ec);
10219 ec.CurrentInitializerVariable = previous;
10221 dynamic = e as DynamicExpressionStatement;
10222 if (dynamic != null)
10228 public override bool Emit (EmitContext ec, IMemoryLocation target)
10230 bool left_on_stack;
10231 if (dynamic != null) {
10233 left_on_stack = true;
10235 left_on_stack = base.Emit (ec, target);
10238 if (initializers.IsEmpty)
10239 return left_on_stack;
10241 LocalTemporary temp = null;
10243 instance = target as LocalTemporary;
10245 if (instance == null) {
10246 if (!left_on_stack) {
10247 VariableReference vr = target as VariableReference;
10249 // FIXME: This still does not work correctly for pre-set variables
10250 if (vr != null && vr.IsRef)
10251 target.AddressOf (ec, AddressOp.Load);
10253 ((Expression) target).Emit (ec);
10254 left_on_stack = true;
10257 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
10258 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
10260 temp = new LocalTemporary (type);
10265 if (left_on_stack && temp != null)
10268 initializers.Emit (ec);
10270 if (left_on_stack) {
10271 if (temp != null) {
10275 ((Expression) instance).Emit (ec);
10279 return left_on_stack;
10282 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
10284 instance = base.EmitAddressOf (ec, Mode);
10286 if (!initializers.IsEmpty)
10287 initializers.Emit (ec);
10292 public override object Accept (StructuralVisitor visitor)
10294 return visitor.Visit (this);
10298 public class NewAnonymousType : New
10300 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
10302 List<AnonymousTypeParameter> parameters;
10303 readonly TypeContainer parent;
10304 AnonymousTypeClass anonymous_type;
10306 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
10307 : base (null, null, loc)
10309 this.parameters = parameters;
10310 this.parent = parent;
10313 public List<AnonymousTypeParameter> Parameters {
10315 return this.parameters;
10319 protected override void CloneTo (CloneContext clonectx, Expression target)
10321 if (parameters == null)
10324 NewAnonymousType t = (NewAnonymousType) target;
10325 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
10326 foreach (AnonymousTypeParameter atp in parameters)
10327 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
10330 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
10332 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
10336 type = AnonymousTypeClass.Create (parent, parameters, loc);
10340 int errors = ec.Report.Errors;
10341 type.CreateContainer ();
10342 type.DefineContainer ();
10344 if ((ec.Report.Errors - errors) == 0) {
10345 parent.Module.AddAnonymousType (type);
10351 public override Expression CreateExpressionTree (ResolveContext ec)
10353 if (parameters == null)
10354 return base.CreateExpressionTree (ec);
10356 var init = new ArrayInitializer (parameters.Count, loc);
10357 foreach (var m in anonymous_type.Members) {
10358 var p = m as Property;
10360 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
10363 var ctor_args = new ArrayInitializer (arguments.Count, loc);
10364 foreach (Argument a in arguments)
10365 ctor_args.Add (a.CreateExpressionTree (ec));
10367 Arguments args = new Arguments (3);
10368 args.Add (new Argument (new TypeOfMethod (method, loc)));
10369 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
10370 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
10372 return CreateExpressionFactoryCall (ec, "New", args);
10375 protected override Expression DoResolve (ResolveContext ec)
10377 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
10378 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
10382 if (parameters == null) {
10383 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
10384 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
10385 return base.DoResolve (ec);
10388 bool error = false;
10389 arguments = new Arguments (parameters.Count);
10390 var t_args = new TypeSpec [parameters.Count];
10391 for (int i = 0; i < parameters.Count; ++i) {
10392 Expression e = parameters [i].Resolve (ec);
10398 arguments.Add (new Argument (e));
10399 t_args [i] = e.Type;
10405 anonymous_type = CreateAnonymousType (ec, parameters);
10406 if (anonymous_type == null)
10409 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
10410 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
10411 eclass = ExprClass.Value;
10415 public override void EmitStatement (EmitContext ec)
10417 base.EmitStatement (ec);
10420 public override object Accept (StructuralVisitor visitor)
10422 return visitor.Visit (this);
10426 public class AnonymousTypeParameter : ShimExpression
10428 public readonly string Name;
10430 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
10431 : base (initializer)
10437 public AnonymousTypeParameter (Parameter parameter)
10438 : base (new SimpleName (parameter.Name, parameter.Location))
10440 this.Name = parameter.Name;
10441 this.loc = parameter.Location;
10444 public override bool Equals (object o)
10446 AnonymousTypeParameter other = o as AnonymousTypeParameter;
10447 return other != null && Name == other.Name;
10450 public override int GetHashCode ()
10452 return Name.GetHashCode ();
10455 protected override Expression DoResolve (ResolveContext ec)
10457 Expression e = expr.Resolve (ec);
10461 if (e.eclass == ExprClass.MethodGroup) {
10462 Error_InvalidInitializer (ec, e.ExprClassName);
10467 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
10468 Error_InvalidInitializer (ec, type.GetSignatureForError ());
10475 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
10477 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
10478 Name, initializer);