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)
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 protected override void CloneTo (CloneContext clonectx, Expression t)
829 Indirection target = (Indirection) t;
830 target.expr = expr.Clone (clonectx);
833 public override bool ContainsEmitWithAwait ()
835 throw new NotImplementedException ();
838 public override Expression CreateExpressionTree (ResolveContext ec)
840 Error_PointerInsideExpressionTree (ec);
844 public override void Emit (EmitContext ec)
849 ec.EmitLoadFromPtr (Type);
852 public void Emit (EmitContext ec, bool leave_copy)
856 ec.Emit (OpCodes.Dup);
857 temporary = new LocalTemporary (expr.Type);
858 temporary.Store (ec);
862 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
864 prepared = isCompound;
869 ec.Emit (OpCodes.Dup);
873 ec.Emit (OpCodes.Dup);
874 temporary = new LocalTemporary (source.Type);
875 temporary.Store (ec);
878 ec.EmitStoreFromPtr (type);
880 if (temporary != null) {
882 temporary.Release (ec);
886 public void AddressOf (EmitContext ec, AddressOp Mode)
891 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
893 return DoResolve (ec);
896 protected override Expression DoResolve (ResolveContext ec)
898 expr = expr.Resolve (ec);
903 UnsafeError (ec, loc);
905 var pc = expr.Type as PointerContainer;
908 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
914 if (type.Kind == MemberKind.Void) {
915 Error_VoidPointerOperation (ec);
919 eclass = ExprClass.Variable;
923 public override object Accept (StructuralVisitor visitor)
925 return visitor.Visit (this);
930 /// Unary Mutator expressions (pre and post ++ and --)
934 /// UnaryMutator implements ++ and -- expressions. It derives from
935 /// ExpressionStatement becuase the pre/post increment/decrement
936 /// operators can be used in a statement context.
938 /// FIXME: Idea, we could split this up in two classes, one simpler
939 /// for the common case, and one with the extra fields for more complex
940 /// classes (indexers require temporary access; overloaded require method)
943 public class UnaryMutator : ExpressionStatement
945 class DynamicPostMutator : Expression, IAssignMethod
950 public DynamicPostMutator (Expression expr)
953 this.type = expr.Type;
954 this.loc = expr.Location;
957 public override Expression CreateExpressionTree (ResolveContext ec)
959 throw new NotImplementedException ("ET");
962 protected override Expression DoResolve (ResolveContext rc)
964 eclass = expr.eclass;
968 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
970 expr.DoResolveLValue (ec, right_side);
971 return DoResolve (ec);
974 public override void Emit (EmitContext ec)
979 public void Emit (EmitContext ec, bool leave_copy)
981 throw new NotImplementedException ();
985 // Emits target assignment using unmodified source value
987 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
990 // Allocate temporary variable to keep original value before it's modified
992 temp = new LocalTemporary (type);
996 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1007 public enum Mode : byte {
1014 PreDecrement = IsDecrement,
1015 PostIncrement = IsPost,
1016 PostDecrement = IsPost | IsDecrement
1020 bool is_expr, recurse;
1022 protected Expression expr;
1024 // Holds the real operation
1025 Expression operation;
1027 public UnaryMutator (Mode m, Expression e, Location loc)
1034 public Mode UnaryMutatorMode {
1040 public Expression Expr {
1046 public override bool ContainsEmitWithAwait ()
1048 return expr.ContainsEmitWithAwait ();
1051 public override Expression CreateExpressionTree (ResolveContext ec)
1053 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1056 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1059 // Predefined ++ and -- operators exist for the following types:
1060 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1062 return new TypeSpec[] {
1078 protected override Expression DoResolve (ResolveContext ec)
1080 expr = expr.Resolve (ec);
1085 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1087 // Handle postfix unary operators using local
1088 // temporary variable
1090 if ((mode & Mode.IsPost) != 0)
1091 expr = new DynamicPostMutator (expr);
1093 Arguments args = new Arguments (1);
1094 args.Add (new Argument (expr));
1095 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1098 if (expr.Type.IsNullableType)
1099 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1101 return DoResolveOperation (ec);
1104 protected Expression DoResolveOperation (ResolveContext ec)
1106 eclass = ExprClass.Value;
1109 if (expr is RuntimeValueExpression) {
1112 // Use itself at the top of the stack
1113 operation = new EmptyExpression (type);
1117 // The operand of the prefix/postfix increment decrement operators
1118 // should be an expression that is classified as a variable,
1119 // a property access or an indexer access
1121 // TODO: Move to parser, expr is ATypeNameExpression
1122 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1123 expr = expr.ResolveLValue (ec, expr);
1125 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1129 // Step 1: Try to find a user operator, it has priority over predefined ones
1131 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1132 var methods = MemberCache.GetUserOperator (type, user_op, false);
1134 if (methods != null) {
1135 Arguments args = new Arguments (1);
1136 args.Add (new Argument (expr));
1138 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1139 var method = res.ResolveOperator (ec, ref args);
1143 args[0].Expr = operation;
1144 operation = new UserOperatorCall (method, args, null, loc);
1145 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1150 // Step 2: Try predefined types
1153 Expression source = null;
1154 bool primitive_type;
1157 // Predefined without user conversion first for speed-up
1159 // Predefined ++ and -- operators exist for the following types:
1160 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1162 switch (type.BuiltinType) {
1163 case BuiltinTypeSpec.Type.Byte:
1164 case BuiltinTypeSpec.Type.SByte:
1165 case BuiltinTypeSpec.Type.Short:
1166 case BuiltinTypeSpec.Type.UShort:
1167 case BuiltinTypeSpec.Type.Int:
1168 case BuiltinTypeSpec.Type.UInt:
1169 case BuiltinTypeSpec.Type.Long:
1170 case BuiltinTypeSpec.Type.ULong:
1171 case BuiltinTypeSpec.Type.Char:
1172 case BuiltinTypeSpec.Type.Float:
1173 case BuiltinTypeSpec.Type.Double:
1174 case BuiltinTypeSpec.Type.Decimal:
1176 primitive_type = true;
1179 primitive_type = false;
1181 // ++/-- on pointer variables of all types except void*
1182 if (type.IsPointer) {
1183 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1184 Error_VoidPointerOperation (ec);
1190 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1191 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1193 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1194 if (source != null) {
1200 // ++/-- on enum types
1201 if (source == null && type.IsEnum)
1204 if (source == null) {
1205 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1212 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1213 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1214 operation = new Binary (op, source, one);
1215 operation = operation.Resolve (ec);
1216 if (operation == null)
1217 throw new NotImplementedException ("should not be reached");
1219 if (operation.Type != type) {
1221 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1223 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1229 void EmitCode (EmitContext ec, bool is_expr)
1232 this.is_expr = is_expr;
1233 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1236 public override void Emit (EmitContext ec)
1239 // We use recurse to allow ourselfs to be the source
1240 // of an assignment. This little hack prevents us from
1241 // having to allocate another expression
1244 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1252 EmitCode (ec, true);
1255 protected virtual void EmitOperation (EmitContext ec)
1257 operation.Emit (ec);
1260 public override void EmitStatement (EmitContext ec)
1262 EmitCode (ec, false);
1266 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1268 string GetOperatorExpressionTypeName ()
1270 return IsDecrement ? "Decrement" : "Increment";
1274 get { return (mode & Mode.IsDecrement) != 0; }
1278 #if NET_4_0 || MONODROID
1279 public override SLE.Expression MakeExpression (BuilderContext ctx)
1281 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1282 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1283 return SLE.Expression.Assign (target, source);
1287 protected override void CloneTo (CloneContext clonectx, Expression t)
1289 UnaryMutator target = (UnaryMutator) t;
1291 target.expr = expr.Clone (clonectx);
1294 public override object Accept (StructuralVisitor visitor)
1296 return visitor.Visit (this);
1302 // Base class for the `is' and `as' operators
1304 public abstract class Probe : Expression
1306 public Expression ProbeType;
1307 protected Expression expr;
1308 protected TypeSpec probe_type_expr;
1310 public Probe (Expression expr, Expression probe_type, Location l)
1312 ProbeType = probe_type;
1317 public Expression Expr {
1323 public override bool ContainsEmitWithAwait ()
1325 return expr.ContainsEmitWithAwait ();
1328 protected override Expression DoResolve (ResolveContext ec)
1330 probe_type_expr = ProbeType.ResolveAsType (ec);
1331 if (probe_type_expr == null)
1334 expr = expr.Resolve (ec);
1338 if (probe_type_expr.IsStatic) {
1339 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1343 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1344 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1349 if (expr.Type == InternalType.AnonymousMethod) {
1350 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1358 protected abstract string OperatorName { get; }
1360 protected override void CloneTo (CloneContext clonectx, Expression t)
1362 Probe target = (Probe) t;
1364 target.expr = expr.Clone (clonectx);
1365 target.ProbeType = ProbeType.Clone (clonectx);
1371 /// Implementation of the `is' operator.
1373 public class Is : Probe
1375 Nullable.Unwrap expr_unwrap;
1377 public Is (Expression expr, Expression probe_type, Location l)
1378 : base (expr, probe_type, l)
1382 protected override string OperatorName {
1383 get { return "is"; }
1386 public override Expression CreateExpressionTree (ResolveContext ec)
1388 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1389 expr.CreateExpressionTree (ec),
1390 new TypeOf (probe_type_expr, loc));
1392 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1395 public override void Emit (EmitContext ec)
1397 if (expr_unwrap != null) {
1398 expr_unwrap.EmitCheck (ec);
1404 // Only to make verifier happy
1405 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1406 ec.Emit (OpCodes.Box, expr.Type);
1408 ec.Emit (OpCodes.Isinst, probe_type_expr);
1410 ec.Emit (OpCodes.Cgt_Un);
1413 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1415 if (expr_unwrap != null) {
1416 expr_unwrap.EmitCheck (ec);
1419 ec.Emit (OpCodes.Isinst, probe_type_expr);
1421 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1424 Expression CreateConstantResult (ResolveContext ec, bool result)
1427 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1428 TypeManager.CSharpName (probe_type_expr));
1430 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1431 TypeManager.CSharpName (probe_type_expr));
1433 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, result, loc), this);
1436 protected override Expression DoResolve (ResolveContext ec)
1438 if (base.DoResolve (ec) == null)
1441 TypeSpec d = expr.Type;
1442 bool d_is_nullable = false;
1445 // If E is a method group or the null literal, or if the type of E is a reference
1446 // type or a nullable type and the value of E is null, the result is false
1448 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1449 return CreateConstantResult (ec, false);
1451 if (d.IsNullableType) {
1452 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1453 if (!ut.IsGenericParameter) {
1455 d_is_nullable = true;
1459 type = ec.BuiltinTypes.Bool;
1460 eclass = ExprClass.Value;
1461 TypeSpec t = probe_type_expr;
1462 bool t_is_nullable = false;
1463 if (t.IsNullableType) {
1464 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1465 if (!ut.IsGenericParameter) {
1467 t_is_nullable = true;
1474 // D and T are the same value types but D can be null
1476 if (d_is_nullable && !t_is_nullable) {
1477 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1482 // The result is true if D and T are the same value types
1484 return CreateConstantResult (ec, true);
1487 var tp = d as TypeParameterSpec;
1489 return ResolveGenericParameter (ec, t, tp);
1492 // An unboxing conversion exists
1494 if (Convert.ExplicitReferenceConversionExists (d, t))
1497 if (TypeManager.IsGenericParameter (t))
1498 return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
1500 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1501 ec.Report.Warning (1981, 3, loc,
1502 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1503 OperatorName, t.GetSignatureForError ());
1506 if (TypeManager.IsGenericParameter (d))
1507 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1509 if (TypeSpec.IsValueType (d)) {
1510 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1511 if (d_is_nullable && !t_is_nullable) {
1512 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1516 return CreateConstantResult (ec, true);
1519 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1521 // Do not optimize for imported type
1523 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None)
1527 // Turn is check into simple null check for implicitly convertible reference types
1529 return ReducedExpression.Create (
1530 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1534 if (Convert.ExplicitReferenceConversionExists (d, t)) {
1540 return CreateConstantResult (ec, false);
1543 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1545 if (t.IsReferenceType) {
1547 return CreateConstantResult (ec, false);
1550 if (TypeManager.IsGenericParameter (expr.Type)) {
1551 if (expr.Type == d && TypeSpec.IsValueType (t))
1552 return CreateConstantResult (ec, true);
1554 expr = new BoxedCast (expr, d);
1560 public override object Accept (StructuralVisitor visitor)
1562 return visitor.Visit (this);
1567 /// Implementation of the `as' operator.
1569 public class As : Probe {
1570 Expression resolved_type;
1572 public As (Expression expr, Expression probe_type, Location l)
1573 : base (expr, probe_type, l)
1577 protected override string OperatorName {
1578 get { return "as"; }
1581 public override Expression CreateExpressionTree (ResolveContext ec)
1583 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1584 expr.CreateExpressionTree (ec),
1585 new TypeOf (probe_type_expr, loc));
1587 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1590 public override void Emit (EmitContext ec)
1594 ec.Emit (OpCodes.Isinst, type);
1596 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1597 ec.Emit (OpCodes.Unbox_Any, type);
1600 protected override Expression DoResolve (ResolveContext ec)
1602 if (resolved_type == null) {
1603 resolved_type = base.DoResolve (ec);
1605 if (resolved_type == null)
1609 type = probe_type_expr;
1610 eclass = ExprClass.Value;
1611 TypeSpec etype = expr.Type;
1613 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1614 if (TypeManager.IsGenericParameter (type)) {
1615 ec.Report.Error (413, loc,
1616 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1617 probe_type_expr.GetSignatureForError ());
1619 ec.Report.Error (77, loc,
1620 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1621 TypeManager.CSharpName (type));
1626 if (expr.IsNull && type.IsNullableType) {
1627 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1630 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1631 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1635 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1637 e = EmptyCast.Create (e, type);
1638 return ReducedExpression.Create (e, this).Resolve (ec);
1641 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1642 if (TypeManager.IsGenericParameter (etype))
1643 expr = new BoxedCast (expr, etype);
1648 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1649 expr = new BoxedCast (expr, etype);
1653 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1654 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1659 public override object Accept (StructuralVisitor visitor)
1661 return visitor.Visit (this);
1666 // This represents a typecast in the source language.
1668 public class Cast : ShimExpression {
1669 Expression target_type;
1671 public Cast (Expression cast_type, Expression expr, Location loc)
1674 this.target_type = cast_type;
1678 public Expression TargetType {
1679 get { return target_type; }
1682 protected override Expression DoResolve (ResolveContext ec)
1684 expr = expr.Resolve (ec);
1688 type = target_type.ResolveAsType (ec);
1692 if (type.IsStatic) {
1693 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1697 if (type.IsPointer && !ec.IsUnsafe) {
1698 UnsafeError (ec, loc);
1701 eclass = ExprClass.Value;
1703 Constant c = expr as Constant;
1705 c = c.Reduce (ec, type);
1710 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1712 return EmptyCast.Create (res, type);
1717 protected override void CloneTo (CloneContext clonectx, Expression t)
1719 Cast target = (Cast) t;
1721 target.target_type = target_type.Clone (clonectx);
1722 target.expr = expr.Clone (clonectx);
1725 public override object Accept (StructuralVisitor visitor)
1727 return visitor.Visit (this);
1731 public class ImplicitCast : ShimExpression
1735 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1738 this.loc = expr.Location;
1740 this.arrayAccess = arrayAccess;
1743 protected override Expression DoResolve (ResolveContext ec)
1745 expr = expr.Resolve (ec);
1750 expr = ConvertExpressionToArrayIndex (ec, expr);
1752 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1759 // C# 2.0 Default value expression
1761 public class DefaultValueExpression : Expression
1765 public DefaultValueExpression (Expression expr, Location loc)
1771 public Expression Expr {
1777 public override bool IsSideEffectFree {
1783 public override bool ContainsEmitWithAwait ()
1788 public override Expression CreateExpressionTree (ResolveContext ec)
1790 Arguments args = new Arguments (2);
1791 args.Add (new Argument (this));
1792 args.Add (new Argument (new TypeOf (type, loc)));
1793 return CreateExpressionFactoryCall (ec, "Constant", args);
1796 protected override Expression DoResolve (ResolveContext ec)
1798 type = expr.ResolveAsType (ec);
1802 if (type.IsStatic) {
1803 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1807 return new NullLiteral (Location).ConvertImplicitly (type);
1809 if (TypeSpec.IsReferenceType (type))
1810 return new NullConstant (type, loc);
1812 Constant c = New.Constantify (type, expr.Location);
1816 eclass = ExprClass.Variable;
1820 public override void Emit (EmitContext ec)
1822 LocalTemporary temp_storage = new LocalTemporary(type);
1824 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1825 ec.Emit(OpCodes.Initobj, type);
1826 temp_storage.Emit(ec);
1827 temp_storage.Release (ec);
1830 #if (NET_4_0 || MONODROID) && !STATIC
1831 public override SLE.Expression MakeExpression (BuilderContext ctx)
1833 return SLE.Expression.Default (type.GetMetaInfo ());
1837 protected override void CloneTo (CloneContext clonectx, Expression t)
1839 DefaultValueExpression target = (DefaultValueExpression) t;
1841 target.expr = expr.Clone (clonectx);
1844 public override object Accept (StructuralVisitor visitor)
1846 return visitor.Visit (this);
1851 /// Binary operators
1853 public class Binary : Expression, IDynamicBinder
1855 public class PredefinedOperator
1857 protected readonly TypeSpec left;
1858 protected readonly TypeSpec right;
1859 public readonly Operator OperatorsMask;
1860 public TypeSpec ReturnType;
1862 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1863 : this (ltype, rtype, op_mask, ltype)
1867 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1868 : this (type, type, op_mask, return_type)
1872 public PredefinedOperator (TypeSpec type, Operator op_mask)
1873 : this (type, type, op_mask, type)
1877 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1879 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1880 throw new InternalErrorException ("Only masked values can be used");
1884 this.OperatorsMask = op_mask;
1885 this.ReturnType = return_type;
1888 public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1890 b.type = ReturnType;
1892 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1893 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1896 // A user operators does not support multiple user conversions, but decimal type
1897 // is considered to be predefined type therefore we apply predefined operators rules
1898 // and then look for decimal user-operator implementation
1900 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal)
1901 return b.ResolveUserOperator (ec, b.left, b.right);
1903 var c = b.right as Constant;
1905 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1906 return ReducedExpression.Create (b.left, b).Resolve (ec);
1907 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
1908 return ReducedExpression.Create (b.left, b).Resolve (ec);
1912 c = b.left as Constant;
1914 if (c.IsDefaultValue && (b.oper == Operator.Addition || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1915 return ReducedExpression.Create (b.right, b).Resolve (ec);
1916 if (b.oper == Operator.Multiply && c.IsOneInteger)
1917 return ReducedExpression.Create (b.right, b).Resolve (ec);
1924 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
1927 // We are dealing with primitive types only
1929 return left == ltype && ltype == rtype;
1932 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1935 if (left == lexpr.Type && right == rexpr.Type)
1938 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1939 Convert.ImplicitConversionExists (ec, rexpr, right);
1942 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1945 if (left != null && best_operator.left != null) {
1946 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left, left);
1950 // When second argument is same as the first one, the result is same
1952 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1953 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right, right);
1956 if (result == 0 || result > 2)
1959 return result == 1 ? best_operator : this;
1963 sealed class PredefinedStringOperator : PredefinedOperator
1965 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
1966 : base (type, type, op_mask, retType)
1970 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
1971 : base (ltype, rtype, op_mask, retType)
1975 public override Expression ConvertResult (ResolveContext ec, Binary b)
1978 // Use original expression for nullable arguments
1980 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1982 b.left = unwrap.Original;
1984 unwrap = b.right as Nullable.Unwrap;
1986 b.right = unwrap.Original;
1988 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1989 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1992 // Start a new concat expression using converted expression
1994 return StringConcat.Create (ec, b.left, b.right, b.loc);
1998 sealed class PredefinedShiftOperator : PredefinedOperator
2000 public PredefinedShiftOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2001 : base (ltype, rtype, op_mask)
2005 public override Expression ConvertResult (ResolveContext ec, Binary b)
2007 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2009 Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2011 int right_mask = left.BuiltinType == BuiltinTypeSpec.Type.Int || left.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
2014 // b = b.left >> b.right & (0x1f|0x3f)
2016 b.right = new Binary (Operator.BitwiseAnd,
2017 b.right, new IntConstant (ec.BuiltinTypes, right_mask, b.right.Location)).Resolve (ec);
2020 // Expression tree representation does not use & mask
2022 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
2023 b.type = ReturnType;
2026 // Optimize shift by 0
2028 var c = b.right as Constant;
2029 if (c != null && c.IsDefaultValue)
2030 return ReducedExpression.Create (b.left, b).Resolve (ec);
2036 sealed class PredefinedEqualityOperator : PredefinedOperator
2038 MethodSpec equal_method, inequal_method;
2040 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
2041 : base (arg, arg, Operator.EqualityMask, retType)
2045 public override Expression ConvertResult (ResolveContext ec, Binary b)
2047 b.type = ReturnType;
2049 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2050 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2052 Arguments args = new Arguments (2);
2053 args.Add (new Argument (b.left));
2054 args.Add (new Argument (b.right));
2057 if (b.oper == Operator.Equality) {
2058 if (equal_method == null) {
2059 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2060 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2061 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2062 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2064 throw new NotImplementedException (left.GetSignatureForError ());
2067 method = equal_method;
2069 if (inequal_method == null) {
2070 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2071 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2072 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2073 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2075 throw new NotImplementedException (left.GetSignatureForError ());
2078 method = inequal_method;
2081 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2085 class PredefinedPointerOperator : PredefinedOperator
2087 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2088 : base (ltype, rtype, op_mask)
2092 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2093 : base (ltype, rtype, op_mask, retType)
2097 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2098 : base (type, op_mask, return_type)
2102 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2105 if (!lexpr.Type.IsPointer)
2108 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2112 if (right == null) {
2113 if (!rexpr.Type.IsPointer)
2116 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2123 public override Expression ConvertResult (ResolveContext ec, Binary b)
2126 b.left = EmptyCast.Create (b.left, left);
2127 } else if (right != null) {
2128 b.right = EmptyCast.Create (b.right, right);
2131 TypeSpec r_type = ReturnType;
2132 Expression left_arg, right_arg;
2133 if (r_type == null) {
2136 right_arg = b.right;
2137 r_type = b.left.Type;
2141 r_type = b.right.Type;
2145 right_arg = b.right;
2148 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2153 public enum Operator {
2154 Multiply = 0 | ArithmeticMask,
2155 Division = 1 | ArithmeticMask,
2156 Modulus = 2 | ArithmeticMask,
2157 Addition = 3 | ArithmeticMask | AdditionMask,
2158 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2160 LeftShift = 5 | ShiftMask,
2161 RightShift = 6 | ShiftMask,
2163 LessThan = 7 | ComparisonMask | RelationalMask,
2164 GreaterThan = 8 | ComparisonMask | RelationalMask,
2165 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2166 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2167 Equality = 11 | ComparisonMask | EqualityMask,
2168 Inequality = 12 | ComparisonMask | EqualityMask,
2170 BitwiseAnd = 13 | BitwiseMask,
2171 ExclusiveOr = 14 | BitwiseMask,
2172 BitwiseOr = 15 | BitwiseMask,
2174 LogicalAnd = 16 | LogicalMask,
2175 LogicalOr = 17 | LogicalMask,
2180 ValuesOnlyMask = ArithmeticMask - 1,
2181 ArithmeticMask = 1 << 5,
2183 ComparisonMask = 1 << 7,
2184 EqualityMask = 1 << 8,
2185 BitwiseMask = 1 << 9,
2186 LogicalMask = 1 << 10,
2187 AdditionMask = 1 << 11,
2188 SubtractionMask = 1 << 12,
2189 RelationalMask = 1 << 13
2192 protected enum State
2196 LeftNullLifted = 1 << 2,
2197 RightNullLifted = 1 << 3
2200 readonly Operator oper;
2201 protected Expression left, right;
2202 protected State state;
2203 Expression enum_conversion;
2205 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
2206 : this (oper, left, right)
2209 state |= State.Compound;
2212 public Binary (Operator oper, Expression left, Expression right)
2217 this.loc = left.Location;
2222 public bool IsCompound {
2224 return (state & State.Compound) != 0;
2228 public Operator Oper {
2234 public Expression Left {
2240 public Expression Right {
2249 /// Returns a stringified representation of the Operator
2251 string OperName (Operator oper)
2255 case Operator.Multiply:
2258 case Operator.Division:
2261 case Operator.Modulus:
2264 case Operator.Addition:
2267 case Operator.Subtraction:
2270 case Operator.LeftShift:
2273 case Operator.RightShift:
2276 case Operator.LessThan:
2279 case Operator.GreaterThan:
2282 case Operator.LessThanOrEqual:
2285 case Operator.GreaterThanOrEqual:
2288 case Operator.Equality:
2291 case Operator.Inequality:
2294 case Operator.BitwiseAnd:
2297 case Operator.BitwiseOr:
2300 case Operator.ExclusiveOr:
2303 case Operator.LogicalOr:
2306 case Operator.LogicalAnd:
2310 s = oper.ToString ();
2320 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2322 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2325 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2327 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
2331 l = TypeManager.CSharpName (left.Type);
2332 r = TypeManager.CSharpName (right.Type);
2334 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2338 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2340 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2344 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2346 string GetOperatorExpressionTypeName ()
2349 case Operator.Addition:
2350 return IsCompound ? "AddAssign" : "Add";
2351 case Operator.BitwiseAnd:
2352 return IsCompound ? "AndAssign" : "And";
2353 case Operator.BitwiseOr:
2354 return IsCompound ? "OrAssign" : "Or";
2355 case Operator.Division:
2356 return IsCompound ? "DivideAssign" : "Divide";
2357 case Operator.ExclusiveOr:
2358 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2359 case Operator.Equality:
2361 case Operator.GreaterThan:
2362 return "GreaterThan";
2363 case Operator.GreaterThanOrEqual:
2364 return "GreaterThanOrEqual";
2365 case Operator.Inequality:
2367 case Operator.LeftShift:
2368 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2369 case Operator.LessThan:
2371 case Operator.LessThanOrEqual:
2372 return "LessThanOrEqual";
2373 case Operator.LogicalAnd:
2375 case Operator.LogicalOr:
2377 case Operator.Modulus:
2378 return IsCompound ? "ModuloAssign" : "Modulo";
2379 case Operator.Multiply:
2380 return IsCompound ? "MultiplyAssign" : "Multiply";
2381 case Operator.RightShift:
2382 return IsCompound ? "RightShiftAssign" : "RightShift";
2383 case Operator.Subtraction:
2384 return IsCompound ? "SubtractAssign" : "Subtract";
2386 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2390 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2393 case Operator.Addition:
2394 return CSharp.Operator.OpType.Addition;
2395 case Operator.BitwiseAnd:
2396 case Operator.LogicalAnd:
2397 return CSharp.Operator.OpType.BitwiseAnd;
2398 case Operator.BitwiseOr:
2399 case Operator.LogicalOr:
2400 return CSharp.Operator.OpType.BitwiseOr;
2401 case Operator.Division:
2402 return CSharp.Operator.OpType.Division;
2403 case Operator.Equality:
2404 return CSharp.Operator.OpType.Equality;
2405 case Operator.ExclusiveOr:
2406 return CSharp.Operator.OpType.ExclusiveOr;
2407 case Operator.GreaterThan:
2408 return CSharp.Operator.OpType.GreaterThan;
2409 case Operator.GreaterThanOrEqual:
2410 return CSharp.Operator.OpType.GreaterThanOrEqual;
2411 case Operator.Inequality:
2412 return CSharp.Operator.OpType.Inequality;
2413 case Operator.LeftShift:
2414 return CSharp.Operator.OpType.LeftShift;
2415 case Operator.LessThan:
2416 return CSharp.Operator.OpType.LessThan;
2417 case Operator.LessThanOrEqual:
2418 return CSharp.Operator.OpType.LessThanOrEqual;
2419 case Operator.Modulus:
2420 return CSharp.Operator.OpType.Modulus;
2421 case Operator.Multiply:
2422 return CSharp.Operator.OpType.Multiply;
2423 case Operator.RightShift:
2424 return CSharp.Operator.OpType.RightShift;
2425 case Operator.Subtraction:
2426 return CSharp.Operator.OpType.Subtraction;
2428 throw new InternalErrorException (op.ToString ());
2432 public override bool ContainsEmitWithAwait ()
2434 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2437 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l)
2442 case Operator.Multiply:
2443 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2444 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2445 opcode = OpCodes.Mul_Ovf;
2446 else if (!IsFloat (l))
2447 opcode = OpCodes.Mul_Ovf_Un;
2449 opcode = OpCodes.Mul;
2451 opcode = OpCodes.Mul;
2455 case Operator.Division:
2457 opcode = OpCodes.Div_Un;
2459 opcode = OpCodes.Div;
2462 case Operator.Modulus:
2464 opcode = OpCodes.Rem_Un;
2466 opcode = OpCodes.Rem;
2469 case Operator.Addition:
2470 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2471 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2472 opcode = OpCodes.Add_Ovf;
2473 else if (!IsFloat (l))
2474 opcode = OpCodes.Add_Ovf_Un;
2476 opcode = OpCodes.Add;
2478 opcode = OpCodes.Add;
2481 case Operator.Subtraction:
2482 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2483 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2484 opcode = OpCodes.Sub_Ovf;
2485 else if (!IsFloat (l))
2486 opcode = OpCodes.Sub_Ovf_Un;
2488 opcode = OpCodes.Sub;
2490 opcode = OpCodes.Sub;
2493 case Operator.RightShift:
2495 opcode = OpCodes.Shr_Un;
2497 opcode = OpCodes.Shr;
2500 case Operator.LeftShift:
2501 opcode = OpCodes.Shl;
2504 case Operator.Equality:
2505 opcode = OpCodes.Ceq;
2508 case Operator.Inequality:
2509 ec.Emit (OpCodes.Ceq);
2512 opcode = OpCodes.Ceq;
2515 case Operator.LessThan:
2517 opcode = OpCodes.Clt_Un;
2519 opcode = OpCodes.Clt;
2522 case Operator.GreaterThan:
2524 opcode = OpCodes.Cgt_Un;
2526 opcode = OpCodes.Cgt;
2529 case Operator.LessThanOrEqual:
2530 if (IsUnsigned (l) || IsFloat (l))
2531 ec.Emit (OpCodes.Cgt_Un);
2533 ec.Emit (OpCodes.Cgt);
2536 opcode = OpCodes.Ceq;
2539 case Operator.GreaterThanOrEqual:
2540 if (IsUnsigned (l) || IsFloat (l))
2541 ec.Emit (OpCodes.Clt_Un);
2543 ec.Emit (OpCodes.Clt);
2547 opcode = OpCodes.Ceq;
2550 case Operator.BitwiseOr:
2551 opcode = OpCodes.Or;
2554 case Operator.BitwiseAnd:
2555 opcode = OpCodes.And;
2558 case Operator.ExclusiveOr:
2559 opcode = OpCodes.Xor;
2563 throw new InternalErrorException (oper.ToString ());
2569 static bool IsUnsigned (TypeSpec t)
2571 switch (t.BuiltinType) {
2572 case BuiltinTypeSpec.Type.Char:
2573 case BuiltinTypeSpec.Type.UInt:
2574 case BuiltinTypeSpec.Type.ULong:
2575 case BuiltinTypeSpec.Type.UShort:
2576 case BuiltinTypeSpec.Type.Byte:
2583 static bool IsFloat (TypeSpec t)
2585 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2588 Expression ResolveOperator (ResolveContext ec)
2590 TypeSpec l = left.Type;
2591 TypeSpec r = right.Type;
2593 bool primitives_only = false;
2596 // Handles predefined primitive types
2598 if (BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r)) {
2599 if ((oper & Operator.ShiftMask) == 0) {
2600 if (l.BuiltinType != BuiltinTypeSpec.Type.Bool && !DoBinaryOperatorPromotion (ec))
2603 primitives_only = true;
2607 if (l.IsPointer || r.IsPointer)
2608 return ResolveOperatorPointer (ec, l, r);
2611 bool lenum = l.IsEnum;
2612 bool renum = r.IsEnum;
2613 if (lenum || renum) {
2614 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2621 if ((oper == Operator.Addition || oper == Operator.Subtraction) && (l.IsDelegate || r.IsDelegate)) {
2623 expr = ResolveOperatorDelegate (ec, l, r);
2625 // TODO: Can this be ambiguous
2631 expr = ResolveUserOperator (ec, left, right);
2635 // Predefined reference types equality
2636 if ((oper & Operator.EqualityMask) != 0) {
2637 expr = ResolveOperatorEquality (ec, l, r);
2643 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, primitives_only, null);
2646 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2647 // if 'left' is not an enumeration constant, create one from the type of 'right'
2648 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2651 case Operator.BitwiseOr:
2652 case Operator.BitwiseAnd:
2653 case Operator.ExclusiveOr:
2654 case Operator.Equality:
2655 case Operator.Inequality:
2656 case Operator.LessThan:
2657 case Operator.LessThanOrEqual:
2658 case Operator.GreaterThan:
2659 case Operator.GreaterThanOrEqual:
2660 if (left.Type.IsEnum)
2663 if (left.IsZeroInteger)
2664 return left.Reduce (ec, right.Type);
2668 case Operator.Addition:
2669 case Operator.Subtraction:
2672 case Operator.Multiply:
2673 case Operator.Division:
2674 case Operator.Modulus:
2675 case Operator.LeftShift:
2676 case Operator.RightShift:
2677 if (right.Type.IsEnum || left.Type.IsEnum)
2686 // The `|' operator used on types which were extended is dangerous
2688 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2690 OpcodeCast lcast = left as OpcodeCast;
2691 if (lcast != null) {
2692 if (IsUnsigned (lcast.UnderlyingType))
2696 OpcodeCast rcast = right as OpcodeCast;
2697 if (rcast != null) {
2698 if (IsUnsigned (rcast.UnderlyingType))
2702 if (lcast == null && rcast == null)
2705 // FIXME: consider constants
2707 ec.Report.Warning (675, 3, loc,
2708 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2709 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2712 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
2714 return new PredefinedOperator[] {
2716 // Pointer arithmetic:
2718 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2719 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2720 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2721 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2723 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
2724 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
2725 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
2726 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
2729 // T* operator + (int y, T* x);
2730 // T* operator + (uint y, T *x);
2731 // T* operator + (long y, T *x);
2732 // T* operator + (ulong y, T *x);
2734 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
2735 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
2736 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
2737 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
2740 // long operator - (T* x, T *y)
2742 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
2746 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
2748 TypeSpec bool_type = types.Bool;
2749 return new PredefinedOperator[] {
2750 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask),
2751 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
2752 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
2753 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
2754 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
2755 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
2756 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
2758 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
2759 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
2760 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
2761 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
2762 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
2763 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
2764 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
2766 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
2767 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
2768 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
2770 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
2772 new PredefinedShiftOperator (types.Int, types.Int, Operator.ShiftMask),
2773 new PredefinedShiftOperator (types.UInt, types.Int, Operator.ShiftMask),
2774 new PredefinedShiftOperator (types.Long, types.Int, Operator.ShiftMask),
2775 new PredefinedShiftOperator (types.ULong, types.Int, Operator.ShiftMask)
2779 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
2781 TypeSpec bool_type = types.Bool;
2783 return new PredefinedOperator[] {
2784 new PredefinedEqualityOperator (types.String, bool_type),
2785 new PredefinedEqualityOperator (types.Delegate, bool_type),
2786 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type)
2791 // Rules used during binary numeric promotion
2793 static bool DoNumericPromotion (ResolveContext rc, ref Expression prim_expr, ref Expression second_expr, TypeSpec type)
2797 Constant c = prim_expr as Constant;
2799 temp = c.ConvertImplicitly (type);
2806 if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
2807 switch (prim_expr.Type.BuiltinType) {
2808 case BuiltinTypeSpec.Type.Int:
2809 case BuiltinTypeSpec.Type.Short:
2810 case BuiltinTypeSpec.Type.SByte:
2811 case BuiltinTypeSpec.Type.Long:
2812 type = rc.BuiltinTypes.Long;
2814 if (type != second_expr.Type) {
2815 c = second_expr as Constant;
2817 temp = c.ConvertImplicitly (type);
2819 temp = Convert.ImplicitNumericConversion (second_expr, type);
2826 } else if (type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
2828 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2830 switch (type.BuiltinType) {
2831 case BuiltinTypeSpec.Type.Int:
2832 case BuiltinTypeSpec.Type.Long:
2833 case BuiltinTypeSpec.Type.Short:
2834 case BuiltinTypeSpec.Type.SByte:
2839 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2848 // 7.2.6.2 Binary numeric promotions
2850 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2852 TypeSpec ltype = left.Type;
2853 TypeSpec rtype = right.Type;
2856 foreach (TypeSpec t in ec.BuiltinTypes.BinaryPromotionsTypes) {
2858 return t == rtype || DoNumericPromotion (ec, ref right, ref left, t);
2861 return t == ltype || DoNumericPromotion (ec, ref left, ref right, t);
2864 TypeSpec int32 = ec.BuiltinTypes.Int;
2865 if (ltype != int32) {
2866 Constant c = left as Constant;
2868 temp = c.ConvertImplicitly (int32);
2870 temp = Convert.ImplicitNumericConversion (left, int32);
2877 if (rtype != int32) {
2878 Constant c = right as Constant;
2880 temp = c.ConvertImplicitly (int32);
2882 temp = Convert.ImplicitNumericConversion (right, int32);
2892 protected override Expression DoResolve (ResolveContext ec)
2897 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2898 left = ((ParenthesizedExpression) left).Expr;
2899 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2903 if (left.eclass == ExprClass.Type) {
2904 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2908 left = left.Resolve (ec);
2913 Constant lc = left as Constant;
2915 if (lc != null && lc.Type.BuiltinType == BuiltinTypeSpec.Type.Bool &&
2916 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2917 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2919 // FIXME: resolve right expression as unreachable
2920 // right.Resolve (ec);
2922 ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2926 right = right.Resolve (ec);
2930 eclass = ExprClass.Value;
2931 Constant rc = right as Constant;
2933 // The conversion rules are ignored in enum context but why
2934 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
2935 lc = EnumLiftUp (ec, lc, rc, loc);
2937 rc = EnumLiftUp (ec, rc, lc, loc);
2940 if (rc != null && lc != null) {
2941 int prev_e = ec.Report.Errors;
2942 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
2943 if (e != null || ec.Report.Errors != prev_e)
2947 // Comparison warnings
2948 if ((oper & Operator.ComparisonMask) != 0) {
2949 if (left.Equals (right)) {
2950 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2952 CheckOutOfRangeComparison (ec, lc, right.Type);
2953 CheckOutOfRangeComparison (ec, rc, left.Type);
2956 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2958 var rt = right.Type;
2959 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
2960 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
2961 Error_OperatorCannotBeApplied (ec, left, right);
2968 // Special handling for logical boolean operators which require rhs not to be
2969 // evaluated based on lhs value
2971 if ((oper & Operator.LogicalMask) != 0) {
2972 Expression cond_left, cond_right, expr;
2974 args = new Arguments (2);
2976 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2977 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, ec.CurrentBlock, loc);
2979 var cond_args = new Arguments (1);
2980 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left).Resolve (ec)));
2983 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
2984 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
2986 left = temp.CreateReferenceExpression (ec, loc);
2987 if (oper == Operator.LogicalAnd) {
2988 expr = DynamicUnaryConversion.CreateIsFalse (ec, cond_args, loc);
2991 expr = DynamicUnaryConversion.CreateIsTrue (ec, cond_args, loc);
2995 args.Add (new Argument (left));
2996 args.Add (new Argument (right));
2997 cond_right = new DynamicExpressionStatement (this, args, loc);
2999 LocalVariable temp = LocalVariable.CreateCompilerGenerated (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
3001 args.Add (new Argument (temp.CreateReferenceExpression (ec, loc).Resolve (ec)));
3002 args.Add (new Argument (right));
3003 right = new DynamicExpressionStatement (this, args, loc);
3006 // bool && dynamic => (temp = left) ? temp && right : temp;
3007 // bool || dynamic => (temp = left) ? temp : temp || right;
3009 if (oper == Operator.LogicalAnd) {
3011 cond_right = temp.CreateReferenceExpression (ec, loc);
3013 cond_left = temp.CreateReferenceExpression (ec, loc);
3017 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left));
3020 return new Conditional (expr, cond_left, cond_right, loc).Resolve (ec);
3023 args = new Arguments (2);
3024 args.Add (new Argument (left));
3025 args.Add (new Argument (right));
3026 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
3029 if (ec.Module.Compiler.Settings.Version >= LanguageVersion.ISO_2 &&
3030 ((left.Type.IsNullableType && (right is NullLiteral || right.Type.IsNullableType || TypeSpec.IsValueType (right.Type))) ||
3031 (TypeSpec.IsValueType (left.Type) && right is NullLiteral) ||
3032 (right.Type.IsNullableType && (left is NullLiteral || left.Type.IsNullableType || TypeSpec.IsValueType (left.Type))) ||
3033 (TypeSpec.IsValueType (right.Type) && left is NullLiteral))) {
3034 var lifted = new Nullable.LiftedBinaryOperator (oper, left, right);
3035 lifted.state = state;
3036 return lifted.Resolve (ec);
3039 return DoResolveCore (ec, left, right);
3042 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3044 Expression expr = ResolveOperator (ec);
3046 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3048 if (left == null || right == null)
3049 throw new InternalErrorException ("Invalid conversion");
3051 if (oper == Operator.BitwiseOr)
3052 CheckBitwiseOrOnSignExtended (ec);
3057 public override SLE.Expression MakeExpression (BuilderContext ctx)
3059 var le = left.MakeExpression (ctx);
3060 var re = right.MakeExpression (ctx);
3061 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3064 case Operator.Addition:
3065 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3066 case Operator.BitwiseAnd:
3067 return SLE.Expression.And (le, re);
3068 case Operator.BitwiseOr:
3069 return SLE.Expression.Or (le, re);
3070 case Operator.Division:
3071 return SLE.Expression.Divide (le, re);
3072 case Operator.Equality:
3073 return SLE.Expression.Equal (le, re);
3074 case Operator.ExclusiveOr:
3075 return SLE.Expression.ExclusiveOr (le, re);
3076 case Operator.GreaterThan:
3077 return SLE.Expression.GreaterThan (le, re);
3078 case Operator.GreaterThanOrEqual:
3079 return SLE.Expression.GreaterThanOrEqual (le, re);
3080 case Operator.Inequality:
3081 return SLE.Expression.NotEqual (le, re);
3082 case Operator.LeftShift:
3083 return SLE.Expression.LeftShift (le, re);
3084 case Operator.LessThan:
3085 return SLE.Expression.LessThan (le, re);
3086 case Operator.LessThanOrEqual:
3087 return SLE.Expression.LessThanOrEqual (le, re);
3088 case Operator.LogicalAnd:
3089 return SLE.Expression.AndAlso (le, re);
3090 case Operator.LogicalOr:
3091 return SLE.Expression.OrElse (le, re);
3092 case Operator.Modulus:
3093 return SLE.Expression.Modulo (le, re);
3094 case Operator.Multiply:
3095 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3096 case Operator.RightShift:
3097 return SLE.Expression.RightShift (le, re);
3098 case Operator.Subtraction:
3099 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3101 throw new NotImplementedException (oper.ToString ());
3106 // D operator + (D x, D y)
3107 // D operator - (D x, D y)
3109 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3111 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3113 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3114 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3119 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3120 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3130 MethodSpec method = null;
3131 Arguments args = new Arguments (2);
3132 args.Add (new Argument (left));
3133 args.Add (new Argument (right));
3135 if (oper == Operator.Addition) {
3136 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3137 } else if (oper == Operator.Subtraction) {
3138 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3142 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3144 MethodGroupExpr mg = MethodGroupExpr.CreatePredefined (method, ec.BuiltinTypes.Delegate, loc);
3145 Expression expr = new UserOperatorCall (mg.BestCandidate, args, CreateExpressionTree, loc);
3146 return new ClassCast (expr, l);
3150 // Enumeration operators
3152 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3155 // bool operator == (E x, E y);
3156 // bool operator != (E x, E y);
3157 // bool operator < (E x, E y);
3158 // bool operator > (E x, E y);
3159 // bool operator <= (E x, E y);
3160 // bool operator >= (E x, E y);
3162 // E operator & (E x, E y);
3163 // E operator | (E x, E y);
3164 // E operator ^ (E x, E y);
3166 // U operator - (E e, E f)
3167 // E operator - (E e, U x)
3168 // E operator - (U x, E e) // LAMESPEC: Not covered by the specification
3170 // E operator + (E e, U x)
3171 // E operator + (U x, E e)
3173 Expression ltemp = left;
3174 Expression rtemp = right;
3175 TypeSpec underlying_type;
3176 TypeSpec underlying_type_result;
3181 // LAMESPEC: There is never ambiguous conversion between enum operators
3182 // the one which contains more enum parameters always wins even if there
3183 // is an implicit conversion involved
3185 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3187 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3188 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
3195 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3196 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
3206 if ((oper & Operator.BitwiseMask) != 0) {
3208 underlying_type_result = underlying_type;
3211 underlying_type_result = null;
3213 } else if (oper == Operator.Subtraction) {
3215 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3216 if (ltype != rtype) {
3217 expr = Convert.ImplicitConversion (ec, left, rtype, left.Location);
3219 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3225 res_type = underlying_type;
3230 res_type = underlying_type;
3233 underlying_type_result = underlying_type;
3235 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3236 expr = Convert.ImplicitConversion (ec, right, ltype, right.Location);
3237 if (expr == null || expr is EnumConstant) {
3238 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3244 res_type = underlying_type;
3248 underlying_type_result = underlying_type;
3252 } else if (oper == Operator.Addition) {
3254 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3257 if (rtype != underlying_type && (state & (State.RightNullLifted | State.LeftNullLifted)) == 0) {
3258 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3265 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3267 if (ltype != underlying_type) {
3268 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3276 underlying_type_result = underlying_type;
3281 // Unwrap the constant correctly, so DoBinaryOperatorPromotion can do the magic
3282 // with constants and expressions
3283 if (left.Type != underlying_type) {
3284 if (left is Constant)
3285 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
3287 left = EmptyCast.Create (left, underlying_type);
3290 if (right.Type != underlying_type) {
3291 if (right is Constant)
3292 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
3294 right = EmptyCast.Create (right, underlying_type);
3298 // C# specification uses explicit cast syntax which means binary promotion
3299 // should happen, however it seems that csc does not do that
3301 if (!DoBinaryOperatorPromotion (ec)) {
3307 if (underlying_type_result != null && left.Type != underlying_type_result) {
3308 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (left.Type), underlying_type_result);
3311 expr = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, true, res_type);
3323 // If the return type of the selected operator is implicitly convertible to the type of x
3325 if (Convert.ImplicitConversionExists (ec, expr, ltype))
3329 // Otherwise, if the selected operator is a predefined operator, if the return type of the
3330 // selected operator is explicitly convertible to the type of x, and if y is implicitly
3331 // convertible to the type of x or the operator is a shift operator, then the operation
3332 // is evaluated as x = (T)(x op y), where T is the type of x
3334 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
3338 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
3345 // 7.9.6 Reference type equality operators
3347 Expression ResolveOperatorEquality (ResolveContext ec, TypeSpec l, TypeSpec r)
3350 type = ec.BuiltinTypes.Bool;
3353 // a, Both operands are reference-type values or the value null
3354 // b, One operand is a value of type T where T is a type-parameter and
3355 // the other operand is the value null. Furthermore T does not have the
3356 // value type constraint
3358 // LAMESPEC: Very confusing details in the specification, basically any
3359 // reference like type-parameter is allowed
3361 var tparam_l = l as TypeParameterSpec;
3362 var tparam_r = r as TypeParameterSpec;
3363 if (tparam_l != null) {
3364 if (right is NullLiteral && !tparam_l.HasSpecialStruct) {
3365 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3369 if (!tparam_l.IsReferenceType)
3372 l = tparam_l.GetEffectiveBase ();
3373 left = new BoxedCast (left, l);
3374 } else if (left is NullLiteral && tparam_r == null) {
3375 if (!TypeSpec.IsReferenceType (r) || r.Kind == MemberKind.InternalCompilerType)
3381 if (tparam_r != null) {
3382 if (left is NullLiteral && !tparam_r.HasSpecialStruct) {
3383 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3387 if (!tparam_r.IsReferenceType)
3390 r = tparam_r.GetEffectiveBase ();
3391 right = new BoxedCast (right, r);
3392 } else if (right is NullLiteral) {
3393 if (!TypeSpec.IsReferenceType (l) || l.Kind == MemberKind.InternalCompilerType)
3399 bool no_arg_conv = false;
3402 // LAMESPEC: method groups can be compared when they convert to other side delegate
3405 if (right.eclass == ExprClass.MethodGroup) {
3406 result = Convert.ImplicitConversion (ec, right, l, loc);
3412 } else if (r.IsDelegate && l != r) {
3415 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3416 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3423 no_arg_conv = l == r && !l.IsStruct;
3427 // bool operator != (string a, string b)
3428 // bool operator == (string a, string b)
3430 // bool operator != (Delegate a, Delegate b)
3431 // bool operator == (Delegate a, Delegate b)
3433 // bool operator != (bool a, bool b)
3434 // bool operator == (bool a, bool b)
3436 // LAMESPEC: Reference equality comparison can apply to value/reference types when
3437 // they implement an implicit conversion to any of types above. This does
3438 // not apply when both operands are of same reference type
3440 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3441 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv, null);
3447 // bool operator != (object a, object b)
3448 // bool operator == (object a, object b)
3450 // An explicit reference conversion exists from the
3451 // type of either operand to the type of the other operand.
3454 // Optimize common path
3456 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3459 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3460 !Convert.ExplicitReferenceConversionExists (r, l))
3463 // Reject allowed explicit conversions like int->object
3464 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
3467 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3468 ec.Report.Warning (253, 2, loc,
3469 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3470 l.GetSignatureForError ());
3472 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3473 ec.Report.Warning (252, 2, loc,
3474 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3475 r.GetSignatureForError ());
3481 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3484 // bool operator == (void* x, void* y);
3485 // bool operator != (void* x, void* y);
3486 // bool operator < (void* x, void* y);
3487 // bool operator > (void* x, void* y);
3488 // bool operator <= (void* x, void* y);
3489 // bool operator >= (void* x, void* y);
3491 if ((oper & Operator.ComparisonMask) != 0) {
3494 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3501 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3507 type = ec.BuiltinTypes.Bool;
3511 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false, null);
3515 // Build-in operators method overloading
3517 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, TypeSpec enum_type)
3519 PredefinedOperator best_operator = null;
3520 TypeSpec l = left.Type;
3521 TypeSpec r = right.Type;
3522 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3524 foreach (PredefinedOperator po in operators) {
3525 if ((po.OperatorsMask & oper_mask) == 0)
3528 if (primitives_only) {
3529 if (!po.IsPrimitiveApplicable (l, r))
3532 if (!po.IsApplicable (ec, left, right))
3536 if (best_operator == null) {
3538 if (primitives_only)
3544 best_operator = po.ResolveBetterOperator (ec, best_operator);
3546 if (best_operator == null) {
3547 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3548 OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
3555 if (best_operator == null)
3558 Expression expr = best_operator.ConvertResult (ec, this);
3561 // Optimize &/&& constant expressions with 0 value
3563 if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
3564 Constant rc = right as Constant;
3565 Constant lc = left as Constant;
3566 if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
3568 // The result is a constant with side-effect
3570 Constant side_effect = rc == null ?
3571 new SideEffectConstant (lc, right, loc) :
3572 new SideEffectConstant (rc, left, loc);
3574 return ReducedExpression.Create (side_effect, expr);
3578 if (enum_type == null)
3582 // HACK: required by enum_conversion
3584 expr.Type = enum_type;
3585 return EmptyCast.Create (expr, enum_type);
3589 // Performs user-operator overloading
3591 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression left, Expression right)
3593 var op = ConvertBinaryToUserOperator (oper);
3595 if (l.IsNullableType)
3596 l = Nullable.NullableInfo.GetUnderlyingType (l);
3598 if (r.IsNullableType)
3599 r = Nullable.NullableInfo.GetUnderlyingType (r);
3601 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
3602 IList<MemberSpec> right_operators = null;
3605 right_operators = MemberCache.GetUserOperator (r, op, false);
3606 if (right_operators == null && left_operators == null)
3608 } else if (left_operators == null) {
3612 Arguments args = new Arguments (2);
3613 Argument larg = new Argument (left);
3615 Argument rarg = new Argument (right);
3619 // User-defined operator implementations always take precedence
3620 // over predefined operator implementations
3622 if (left_operators != null && right_operators != null) {
3623 left_operators = CombineUserOperators (left_operators, right_operators);
3624 } else if (right_operators != null) {
3625 left_operators = right_operators;
3628 var res = new OverloadResolver (left_operators, OverloadResolver.Restrictions.ProbingOnly |
3629 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded, loc);
3631 var oper_method = res.ResolveOperator (ec, ref args);
3632 if (oper_method == null)
3635 var llifted = (state & State.LeftNullLifted) != 0;
3636 var rlifted = (state & State.RightNullLifted) != 0;
3637 if ((Oper & Operator.EqualityMask) != 0) {
3638 var parameters = oper_method.Parameters;
3639 // LAMESPEC: No idea why this is not allowed
3640 if ((left is Nullable.Unwrap || right is Nullable.Unwrap) && parameters.Types [0] != parameters.Types [1])
3643 // Binary operation was lifted but we have found a user operator
3644 // which requires value-type argument, we downgrade ourself back to
3646 // LAMESPEC: The user operator is not called (it cannot be we are passing null to struct)
3647 // but compilation succeeds
3648 if ((llifted && !parameters.Types[0].IsStruct) || (rlifted && !parameters.Types[1].IsStruct)) {
3649 state &= ~(State.LeftNullLifted | State.RightNullLifted);
3653 Expression oper_expr;
3655 // TODO: CreateExpressionTree is allocated every time
3656 if ((oper & Operator.LogicalMask) != 0) {
3657 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
3658 oper == Operator.LogicalAnd, loc).Resolve (ec);
3660 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
3664 this.left = larg.Expr;
3667 this.right = rarg.Expr;
3673 // Merge two sets of user operators into one, they are mostly distinguish
3674 // except when they share base type and it contains an operator
3676 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
3678 var combined = new List<MemberSpec> (left.Count + right.Count);
3679 combined.AddRange (left);
3680 foreach (var r in right) {
3682 foreach (var l in left) {
3683 if (l.DeclaringType == r.DeclaringType) {
3696 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
3698 if (c is IntegralConstant || c is CharConstant) {
3700 c.ConvertExplicitly (true, type);
3701 } catch (OverflowException) {
3702 ec.Report.Warning (652, 2, loc,
3703 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
3704 TypeManager.CSharpName (type));
3710 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3711 /// context of a conditional bool expression. This function will return
3712 /// false if it is was possible to use EmitBranchable, or true if it was.
3714 /// The expression's code is generated, and we will generate a branch to `target'
3715 /// if the resulting expression value is equal to isTrue
3717 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3720 // This is more complicated than it looks, but its just to avoid
3721 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3722 // but on top of that we want for == and != to use a special path
3723 // if we are comparing against null
3725 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
3726 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3729 // put the constant on the rhs, for simplicity
3731 if (left is Constant) {
3732 Expression swap = right;
3738 // brtrue/brfalse works with native int only
3740 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
3741 left.EmitBranchable (ec, target, my_on_true);
3744 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
3745 // right is a boolean, and it's not 'false' => it is 'true'
3746 left.EmitBranchable (ec, target, !my_on_true);
3750 } else if (oper == Operator.LogicalAnd) {
3753 Label tests_end = ec.DefineLabel ();
3755 left.EmitBranchable (ec, tests_end, false);
3756 right.EmitBranchable (ec, target, true);
3757 ec.MarkLabel (tests_end);
3760 // This optimizes code like this
3761 // if (true && i > 4)
3763 if (!(left is Constant))
3764 left.EmitBranchable (ec, target, false);
3766 if (!(right is Constant))
3767 right.EmitBranchable (ec, target, false);
3772 } else if (oper == Operator.LogicalOr){
3774 left.EmitBranchable (ec, target, true);
3775 right.EmitBranchable (ec, target, true);
3778 Label tests_end = ec.DefineLabel ();
3779 left.EmitBranchable (ec, tests_end, true);
3780 right.EmitBranchable (ec, target, false);
3781 ec.MarkLabel (tests_end);
3786 } else if ((oper & Operator.ComparisonMask) == 0) {
3787 base.EmitBranchable (ec, target, on_true);
3794 TypeSpec t = left.Type;
3795 bool is_float = IsFloat (t);
3796 bool is_unsigned = is_float || IsUnsigned (t);
3799 case Operator.Equality:
3801 ec.Emit (OpCodes.Beq, target);
3803 ec.Emit (OpCodes.Bne_Un, target);
3806 case Operator.Inequality:
3808 ec.Emit (OpCodes.Bne_Un, target);
3810 ec.Emit (OpCodes.Beq, target);
3813 case Operator.LessThan:
3815 if (is_unsigned && !is_float)
3816 ec.Emit (OpCodes.Blt_Un, target);
3818 ec.Emit (OpCodes.Blt, target);
3821 ec.Emit (OpCodes.Bge_Un, target);
3823 ec.Emit (OpCodes.Bge, target);
3826 case Operator.GreaterThan:
3828 if (is_unsigned && !is_float)
3829 ec.Emit (OpCodes.Bgt_Un, target);
3831 ec.Emit (OpCodes.Bgt, target);
3834 ec.Emit (OpCodes.Ble_Un, target);
3836 ec.Emit (OpCodes.Ble, target);
3839 case Operator.LessThanOrEqual:
3841 if (is_unsigned && !is_float)
3842 ec.Emit (OpCodes.Ble_Un, target);
3844 ec.Emit (OpCodes.Ble, target);
3847 ec.Emit (OpCodes.Bgt_Un, target);
3849 ec.Emit (OpCodes.Bgt, target);
3853 case Operator.GreaterThanOrEqual:
3855 if (is_unsigned && !is_float)
3856 ec.Emit (OpCodes.Bge_Un, target);
3858 ec.Emit (OpCodes.Bge, target);
3861 ec.Emit (OpCodes.Blt_Un, target);
3863 ec.Emit (OpCodes.Blt, target);
3866 throw new InternalErrorException (oper.ToString ());
3870 public override void Emit (EmitContext ec)
3872 EmitOperator (ec, left.Type);
3875 protected virtual void EmitOperator (EmitContext ec, TypeSpec l)
3877 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
3878 left = left.EmitToField (ec);
3880 if ((oper & Operator.LogicalMask) == 0) {
3881 right = right.EmitToField (ec);
3886 // Handle short-circuit operators differently
3889 if ((oper & Operator.LogicalMask) != 0) {
3890 Label load_result = ec.DefineLabel ();
3891 Label end = ec.DefineLabel ();
3893 bool is_or = oper == Operator.LogicalOr;
3894 left.EmitBranchable (ec, load_result, is_or);
3896 ec.Emit (OpCodes.Br_S, end);
3898 ec.MarkLabel (load_result);
3899 ec.EmitInt (is_or ? 1 : 0);
3905 // Optimize zero-based operations which cannot be optimized at expression level
3907 if (oper == Operator.Subtraction) {
3908 var lc = left as IntegralConstant;
3909 if (lc != null && lc.IsDefaultValue) {
3911 ec.Emit (OpCodes.Neg);
3918 EmitOperatorOpcode (ec, oper, l);
3921 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3922 // expression because that would wrap lifted binary operation
3924 if (enum_conversion != null)
3925 enum_conversion.Emit (ec);
3928 public override void EmitSideEffect (EmitContext ec)
3930 if ((oper & Operator.LogicalMask) != 0 ||
3931 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3932 base.EmitSideEffect (ec);
3934 left.EmitSideEffect (ec);
3935 right.EmitSideEffect (ec);
3939 public override Expression EmitToField (EmitContext ec)
3941 if ((oper & Operator.LogicalMask) == 0) {
3942 var await_expr = left as Await;
3943 if (await_expr != null && right.IsSideEffectFree) {
3944 await_expr.Statement.EmitPrologue (ec);
3945 left = await_expr.Statement.GetResultExpression (ec);
3949 await_expr = right as Await;
3950 if (await_expr != null && left.IsSideEffectFree) {
3951 await_expr.Statement.EmitPrologue (ec);
3952 right = await_expr.Statement.GetResultExpression (ec);
3957 return base.EmitToField (ec);
3960 protected override void CloneTo (CloneContext clonectx, Expression t)
3962 Binary target = (Binary) t;
3964 target.left = left.Clone (clonectx);
3965 target.right = right.Clone (clonectx);
3968 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3970 Arguments binder_args = new Arguments (4);
3972 MemberAccess sle = new MemberAccess (new MemberAccess (
3973 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3975 CSharpBinderFlags flags = 0;
3976 if (ec.HasSet (ResolveContext.Options.CheckedScope))
3977 flags = CSharpBinderFlags.CheckedContext;
3979 if ((oper & Operator.LogicalMask) != 0)
3980 flags |= CSharpBinderFlags.BinaryOperationLogical;
3982 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
3983 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3984 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
3985 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
3987 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
3990 public override Expression CreateExpressionTree (ResolveContext ec)
3992 return CreateExpressionTree (ec, null);
3995 Expression CreateExpressionTree (ResolveContext ec, Expression method)
3998 bool lift_arg = false;
4001 case Operator.Addition:
4002 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4003 method_name = "AddChecked";
4005 method_name = "Add";
4007 case Operator.BitwiseAnd:
4008 method_name = "And";
4010 case Operator.BitwiseOr:
4013 case Operator.Division:
4014 method_name = "Divide";
4016 case Operator.Equality:
4017 method_name = "Equal";
4020 case Operator.ExclusiveOr:
4021 method_name = "ExclusiveOr";
4023 case Operator.GreaterThan:
4024 method_name = "GreaterThan";
4027 case Operator.GreaterThanOrEqual:
4028 method_name = "GreaterThanOrEqual";
4031 case Operator.Inequality:
4032 method_name = "NotEqual";
4035 case Operator.LeftShift:
4036 method_name = "LeftShift";
4038 case Operator.LessThan:
4039 method_name = "LessThan";
4042 case Operator.LessThanOrEqual:
4043 method_name = "LessThanOrEqual";
4046 case Operator.LogicalAnd:
4047 method_name = "AndAlso";
4049 case Operator.LogicalOr:
4050 method_name = "OrElse";
4052 case Operator.Modulus:
4053 method_name = "Modulo";
4055 case Operator.Multiply:
4056 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4057 method_name = "MultiplyChecked";
4059 method_name = "Multiply";
4061 case Operator.RightShift:
4062 method_name = "RightShift";
4064 case Operator.Subtraction:
4065 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4066 method_name = "SubtractChecked";
4068 method_name = "Subtract";
4072 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4075 Arguments args = new Arguments (2);
4076 args.Add (new Argument (left.CreateExpressionTree (ec)));
4077 args.Add (new Argument (right.CreateExpressionTree (ec)));
4078 if (method != null) {
4080 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4082 args.Add (new Argument (method));
4085 return CreateExpressionFactoryCall (ec, method_name, args);
4088 public override object Accept (StructuralVisitor visitor)
4090 return visitor.Visit (this);
4096 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4097 // b, c, d... may be strings or objects.
4099 public class StringConcat : Expression
4101 Arguments arguments;
4103 StringConcat (Location loc)
4106 arguments = new Arguments (2);
4109 public override bool ContainsEmitWithAwait ()
4111 return arguments.ContainsEmitWithAwait ();
4114 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4116 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4117 throw new ArgumentException ();
4119 var s = new StringConcat (loc);
4120 s.type = rc.BuiltinTypes.String;
4121 s.eclass = ExprClass.Value;
4123 s.Append (rc, left);
4124 s.Append (rc, right);
4128 public override Expression CreateExpressionTree (ResolveContext ec)
4130 Argument arg = arguments [0];
4131 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4135 // Creates nested calls tree from an array of arguments used for IL emit
4137 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4139 Arguments concat_args = new Arguments (2);
4140 Arguments add_args = new Arguments (3);
4142 concat_args.Add (left);
4143 add_args.Add (new Argument (left_etree));
4145 concat_args.Add (arguments [pos]);
4146 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4148 var methods = GetConcatMethodCandidates ();
4149 if (methods == null)
4152 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4153 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4157 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4159 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4160 if (++pos == arguments.Count)
4163 left = new Argument (new EmptyExpression (method.ReturnType));
4164 return CreateExpressionAddCall (ec, left, expr, pos);
4167 protected override Expression DoResolve (ResolveContext ec)
4172 void Append (ResolveContext rc, Expression operand)
4177 StringConstant sc = operand as StringConstant;
4179 if (arguments.Count != 0) {
4180 Argument last_argument = arguments [arguments.Count - 1];
4181 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4182 if (last_expr_constant != null) {
4183 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4189 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4191 StringConcat concat_oper = operand as StringConcat;
4192 if (concat_oper != null) {
4193 arguments.AddRange (concat_oper.arguments);
4198 arguments.Add (new Argument (operand));
4201 IList<MemberSpec> GetConcatMethodCandidates ()
4203 return MemberCache.FindMembers (type, "Concat", true);
4206 public override void Emit (EmitContext ec)
4208 var members = GetConcatMethodCandidates ();
4209 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4210 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4211 if (method != null) {
4212 var call = new CallEmitter ();
4213 call.EmitPredefined (ec, method, arguments);
4217 public override SLE.Expression MakeExpression (BuilderContext ctx)
4219 if (arguments.Count != 2)
4220 throw new NotImplementedException ("arguments.Count != 2");
4222 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4223 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4228 // User-defined conditional logical operator
4230 public class ConditionalLogicalOperator : UserOperatorCall
4232 readonly bool is_and;
4233 Expression oper_expr;
4235 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4236 : base (oper, arguments, expr_tree, loc)
4238 this.is_and = is_and;
4239 eclass = ExprClass.Unresolved;
4242 protected override Expression DoResolve (ResolveContext ec)
4244 AParametersCollection pd = oper.Parameters;
4245 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4246 ec.Report.Error (217, loc,
4247 "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",
4248 oper.GetSignatureForError ());
4252 Expression left_dup = new EmptyExpression (type);
4253 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4254 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4255 if (op_true == null || op_false == null) {
4256 ec.Report.Error (218, loc,
4257 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4258 TypeManager.CSharpName (type), oper.GetSignatureForError ());
4262 oper_expr = is_and ? op_false : op_true;
4263 eclass = ExprClass.Value;
4267 public override void Emit (EmitContext ec)
4269 Label end_target = ec.DefineLabel ();
4272 // Emit and duplicate left argument
4274 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
4275 if (right_contains_await) {
4276 arguments[0] = arguments[0].EmitToField (ec, false);
4277 arguments[0].Expr.Emit (ec);
4279 arguments[0].Expr.Emit (ec);
4280 ec.Emit (OpCodes.Dup);
4281 arguments.RemoveAt (0);
4284 oper_expr.EmitBranchable (ec, end_target, true);
4288 if (right_contains_await) {
4290 // Special handling when right expression contains await and left argument
4291 // could not be left on stack before logical branch
4293 Label skip_left_load = ec.DefineLabel ();
4294 ec.Emit (OpCodes.Br_S, skip_left_load);
4295 ec.MarkLabel (end_target);
4296 arguments[0].Expr.Emit (ec);
4297 ec.MarkLabel (skip_left_load);
4299 ec.MarkLabel (end_target);
4304 public class PointerArithmetic : Expression {
4305 Expression left, right;
4309 // We assume that `l' is always a pointer
4311 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4320 public override bool ContainsEmitWithAwait ()
4322 throw new NotImplementedException ();
4325 public override Expression CreateExpressionTree (ResolveContext ec)
4327 Error_PointerInsideExpressionTree (ec);
4331 protected override Expression DoResolve (ResolveContext ec)
4333 eclass = ExprClass.Variable;
4335 var pc = left.Type as PointerContainer;
4336 if (pc != null && pc.Element.Kind == MemberKind.Void) {
4337 Error_VoidPointerOperation (ec);
4344 public override void Emit (EmitContext ec)
4346 TypeSpec op_type = left.Type;
4348 // It must be either array or fixed buffer
4350 if (TypeManager.HasElementType (op_type)) {
4351 element = TypeManager.GetElementType (op_type);
4353 FieldExpr fe = left as FieldExpr;
4355 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
4360 int size = BuiltinTypeSpec.GetSize(element);
4361 TypeSpec rtype = right.Type;
4363 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4365 // handle (pointer - pointer)
4369 ec.Emit (OpCodes.Sub);
4373 ec.Emit (OpCodes.Sizeof, element);
4376 ec.Emit (OpCodes.Div);
4378 ec.Emit (OpCodes.Conv_I8);
4381 // handle + and - on (pointer op int)
4383 Constant left_const = left as Constant;
4384 if (left_const != null) {
4386 // Optimize ((T*)null) pointer operations
4388 if (left_const.IsDefaultValue) {
4389 left = EmptyExpression.Null;
4397 var right_const = right as Constant;
4398 if (right_const != null) {
4400 // Optimize 0-based arithmetic
4402 if (right_const.IsDefaultValue)
4406 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
4408 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
4410 // TODO: Should be the checks resolve context sensitive?
4411 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
4412 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
4418 switch (rtype.BuiltinType) {
4419 case BuiltinTypeSpec.Type.SByte:
4420 case BuiltinTypeSpec.Type.Byte:
4421 case BuiltinTypeSpec.Type.Short:
4422 case BuiltinTypeSpec.Type.UShort:
4423 ec.Emit (OpCodes.Conv_I);
4425 case BuiltinTypeSpec.Type.UInt:
4426 ec.Emit (OpCodes.Conv_U);
4430 if (right_const == null && size != 1){
4432 ec.Emit (OpCodes.Sizeof, element);
4435 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4436 ec.Emit (OpCodes.Conv_I8);
4438 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4441 if (left_const == null) {
4442 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
4443 ec.Emit (OpCodes.Conv_I);
4444 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4445 ec.Emit (OpCodes.Conv_U);
4447 Binary.EmitOperatorOpcode (ec, op, op_type);
4454 // A boolean-expression is an expression that yields a result
4457 public class BooleanExpression : ShimExpression
4459 public BooleanExpression (Expression expr)
4462 this.loc = expr.Location;
4465 public override Expression CreateExpressionTree (ResolveContext ec)
4467 // TODO: We should emit IsTrue (v4) instead of direct user operator
4468 // call but that would break csc compatibility
4469 return base.CreateExpressionTree (ec);
4472 protected override Expression DoResolve (ResolveContext ec)
4474 // A boolean-expression is required to be of a type
4475 // that can be implicitly converted to bool or of
4476 // a type that implements operator true
4478 expr = expr.Resolve (ec);
4482 Assign ass = expr as Assign;
4483 if (ass != null && ass.Source is Constant) {
4484 ec.Report.Warning (665, 3, loc,
4485 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4488 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
4491 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4492 Arguments args = new Arguments (1);
4493 args.Add (new Argument (expr));
4494 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
4497 type = ec.BuiltinTypes.Bool;
4498 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4499 if (converted != null)
4503 // If no implicit conversion to bool exists, try using `operator true'
4505 converted = GetOperatorTrue (ec, expr, loc);
4506 if (converted == null) {
4507 expr.Error_ValueCannotBeConverted (ec, type, false);
4514 public override object Accept (StructuralVisitor visitor)
4516 return visitor.Visit (this);
4520 public class BooleanExpressionFalse : Unary
4522 public BooleanExpressionFalse (Expression expr)
4523 : base (Operator.LogicalNot, expr, expr.Location)
4527 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
4529 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
4534 /// Implements the ternary conditional operator (?:)
4536 public class Conditional : Expression {
4537 Expression expr, true_expr, false_expr;
4539 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
4542 this.true_expr = true_expr;
4543 this.false_expr = false_expr;
4549 public Expression Expr {
4555 public Expression TrueExpr {
4561 public Expression FalseExpr {
4569 public override bool ContainsEmitWithAwait ()
4571 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
4574 public override Expression CreateExpressionTree (ResolveContext ec)
4576 Arguments args = new Arguments (3);
4577 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4578 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4579 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4580 return CreateExpressionFactoryCall (ec, "Condition", args);
4583 protected override Expression DoResolve (ResolveContext ec)
4585 expr = expr.Resolve (ec);
4588 // Unreachable code needs different resolve path. For instance for await
4589 // expression to not generate unreachable resumable statement
4591 Constant c = expr as Constant;
4592 if (c != null && ec.CurrentBranching != null) {
4593 bool unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
4595 if (c.IsDefaultValue) {
4596 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
4597 true_expr = true_expr.Resolve (ec);
4598 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
4600 false_expr = false_expr.Resolve (ec);
4602 true_expr = true_expr.Resolve (ec);
4604 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
4605 false_expr = false_expr.Resolve (ec);
4606 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
4609 true_expr = true_expr.Resolve (ec);
4610 false_expr = false_expr.Resolve (ec);
4613 if (true_expr == null || false_expr == null || expr == null)
4616 eclass = ExprClass.Value;
4617 TypeSpec true_type = true_expr.Type;
4618 TypeSpec false_type = false_expr.Type;
4622 // First, if an implicit conversion exists from true_expr
4623 // to false_expr, then the result type is of type false_expr.Type
4625 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
4626 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4627 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
4629 // Check if both can convert implicitly to each other's type
4633 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
4634 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
4636 // LAMESPEC: There seems to be hardcoded promotition to int type when
4637 // both sides are numeric constants and one side is int constant and
4638 // other side is numeric constant convertible to int.
4640 // var res = condition ? (short)1 : 1;
4642 // Type of res is int even if according to the spec the conversion is
4643 // ambiguous because 1 literal can be converted to short.
4645 if (conv_false_expr != null) {
4646 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
4648 conv_false_expr = null;
4649 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
4650 conv_false_expr = null;
4654 if (conv_false_expr != null) {
4655 ec.Report.Error (172, true_expr.Location,
4656 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
4657 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
4662 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4665 ec.Report.Error (173, true_expr.Location,
4666 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4667 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4673 bool is_false = c.IsDefaultValue;
4676 // Don't issue the warning for constant expressions
4678 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
4679 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location,
4680 "Unreachable expression code detected");
4683 return ReducedExpression.Create (
4684 is_false ? false_expr : true_expr, this,
4685 false_expr is Constant && true_expr is Constant).Resolve (ec);
4691 public override void Emit (EmitContext ec)
4693 Label false_target = ec.DefineLabel ();
4694 Label end_target = ec.DefineLabel ();
4696 expr.EmitBranchable (ec, false_target, false);
4697 true_expr.Emit (ec);
4699 ec.Emit (OpCodes.Br, end_target);
4700 ec.MarkLabel (false_target);
4701 false_expr.Emit (ec);
4702 ec.MarkLabel (end_target);
4705 protected override void CloneTo (CloneContext clonectx, Expression t)
4707 Conditional target = (Conditional) t;
4709 target.expr = expr.Clone (clonectx);
4710 target.true_expr = true_expr.Clone (clonectx);
4711 target.false_expr = false_expr.Clone (clonectx);
4715 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
4717 LocalTemporary temp;
4720 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4721 public abstract void SetHasAddressTaken ();
4722 public abstract void VerifyAssigned (ResolveContext rc);
4724 public abstract bool IsLockedByStatement { get; set; }
4726 public abstract bool IsFixed { get; }
4727 public abstract bool IsRef { get; }
4728 public abstract string Name { get; }
4731 // Variable IL data, it has to be protected to encapsulate hoisted variables
4733 protected abstract ILocalVariable Variable { get; }
4736 // Variable flow-analysis data
4738 public abstract VariableInfo VariableInfo { get; }
4741 public virtual void AddressOf (EmitContext ec, AddressOp mode)
4743 HoistedVariable hv = GetHoistedVariable (ec);
4745 hv.AddressOf (ec, mode);
4749 Variable.EmitAddressOf (ec);
4752 public override bool ContainsEmitWithAwait ()
4757 public override Expression CreateExpressionTree (ResolveContext ec)
4759 HoistedVariable hv = GetHoistedVariable (ec);
4761 return hv.CreateExpressionTree ();
4763 Arguments arg = new Arguments (1);
4764 arg.Add (new Argument (this));
4765 return CreateExpressionFactoryCall (ec, "Constant", arg);
4768 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
4770 if (IsLockedByStatement) {
4771 rc.Report.Warning (728, 2, loc,
4772 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
4779 public override void Emit (EmitContext ec)
4784 public override void EmitSideEffect (EmitContext ec)
4790 // This method is used by parameters that are references, that are
4791 // being passed as references: we only want to pass the pointer (that
4792 // is already stored in the parameter, not the address of the pointer,
4793 // and not the value of the variable).
4795 public void EmitLoad (EmitContext ec)
4800 public void Emit (EmitContext ec, bool leave_copy)
4802 HoistedVariable hv = GetHoistedVariable (ec);
4804 hv.Emit (ec, leave_copy);
4812 // If we are a reference, we loaded on the stack a pointer
4813 // Now lets load the real value
4815 ec.EmitLoadFromPtr (type);
4819 ec.Emit (OpCodes.Dup);
4822 temp = new LocalTemporary (Type);
4828 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4829 bool prepare_for_load)
4831 HoistedVariable hv = GetHoistedVariable (ec);
4833 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4837 New n_source = source as New;
4838 if (n_source != null) {
4839 if (!n_source.Emit (ec, this)) {
4843 ec.EmitLoadFromPtr (type);
4855 ec.Emit (OpCodes.Dup);
4857 temp = new LocalTemporary (Type);
4863 ec.EmitStoreFromPtr (type);
4865 Variable.EmitAssign (ec);
4873 public override Expression EmitToField (EmitContext ec)
4875 HoistedVariable hv = GetHoistedVariable (ec);
4877 return hv.EmitToField (ec);
4880 return base.EmitToField (ec);
4883 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4885 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4888 public HoistedVariable GetHoistedVariable (EmitContext ec)
4890 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4893 public override string GetSignatureForError ()
4898 public bool IsHoisted {
4899 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4904 // Resolved reference to a local variable
4906 public class LocalVariableReference : VariableReference
4908 public LocalVariable local_info;
4910 public LocalVariableReference (LocalVariable li, Location l)
4912 this.local_info = li;
4916 public override VariableInfo VariableInfo {
4917 get { return local_info.VariableInfo; }
4920 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4922 return local_info.HoistedVariant;
4928 // A local variable is always fixed
4930 public override bool IsFixed {
4936 public override bool IsLockedByStatement {
4938 return local_info.IsLocked;
4941 local_info.IsLocked = value;
4945 public override bool IsRef {
4946 get { return false; }
4949 public override string Name {
4950 get { return local_info.Name; }
4955 public override void VerifyAssigned (ResolveContext rc)
4957 VariableInfo variable_info = local_info.VariableInfo;
4958 if (variable_info == null)
4961 if (variable_info.IsAssigned (rc))
4964 rc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
4965 variable_info.SetAssigned (rc);
4968 public override void SetHasAddressTaken ()
4970 local_info.SetHasAddressTaken ();
4973 void DoResolveBase (ResolveContext ec)
4976 // If we are referencing a variable from the external block
4977 // flag it for capturing
4979 if (ec.MustCaptureVariable (local_info)) {
4980 if (local_info.AddressTaken) {
4981 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4982 } else if (local_info.IsFixed) {
4983 ec.Report.Error (1764, loc,
4984 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
4985 GetSignatureForError ());
4988 if (ec.IsVariableCapturingRequired) {
4989 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4990 storey.CaptureLocalVariable (ec, local_info);
4994 eclass = ExprClass.Variable;
4995 type = local_info.Type;
4998 protected override Expression DoResolve (ResolveContext ec)
5000 local_info.SetIsUsed ();
5002 VerifyAssigned (ec);
5008 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5011 // Don't be too pedantic when variable is used as out param or for some broken code
5012 // which uses property/indexer access to run some initialization
5014 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5015 local_info.SetIsUsed ();
5017 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5020 if (rhs == EmptyExpression.OutAccess) {
5021 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5022 } else if (rhs == EmptyExpression.LValueMemberAccess) {
5023 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
5024 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5025 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5026 } else if (rhs == EmptyExpression.UnaryAddress) {
5027 code = 459; msg = "Cannot take the address of {1} `{0}'";
5029 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5031 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5032 } else if (VariableInfo != null) {
5033 VariableInfo.SetAssigned (ec);
5036 if (eclass == ExprClass.Unresolved)
5039 return base.DoResolveLValue (ec, rhs);
5042 public override int GetHashCode ()
5044 return local_info.GetHashCode ();
5047 public override bool Equals (object obj)
5049 LocalVariableReference lvr = obj as LocalVariableReference;
5053 return local_info == lvr.local_info;
5056 protected override ILocalVariable Variable {
5057 get { return local_info; }
5060 public override string ToString ()
5062 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5065 protected override void CloneTo (CloneContext clonectx, Expression t)
5072 /// This represents a reference to a parameter in the intermediate
5075 public class ParameterReference : VariableReference
5077 protected ParametersBlock.ParameterInfo pi;
5079 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5087 public override bool IsLockedByStatement {
5092 pi.IsLocked = value;
5096 public override bool IsRef {
5097 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5100 bool HasOutModifier {
5101 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5104 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5106 return pi.Parameter.HoistedVariant;
5110 // A ref or out parameter is classified as a moveable variable, even
5111 // if the argument given for the parameter is a fixed variable
5113 public override bool IsFixed {
5114 get { return !IsRef; }
5117 public override string Name {
5118 get { return Parameter.Name; }
5121 public Parameter Parameter {
5122 get { return pi.Parameter; }
5125 public override VariableInfo VariableInfo {
5126 get { return pi.VariableInfo; }
5129 protected override ILocalVariable Variable {
5130 get { return Parameter; }
5135 public override void AddressOf (EmitContext ec, AddressOp mode)
5138 // ParameterReferences might already be a reference
5145 base.AddressOf (ec, mode);
5148 public override void SetHasAddressTaken ()
5150 Parameter.HasAddressTaken = true;
5153 void SetAssigned (ResolveContext ec)
5155 if (HasOutModifier && ec.DoFlowAnalysis)
5156 ec.CurrentBranching.SetAssigned (VariableInfo);
5159 bool DoResolveBase (ResolveContext ec)
5161 if (eclass != ExprClass.Unresolved)
5164 type = pi.ParameterType;
5165 eclass = ExprClass.Variable;
5168 // If we are referencing a parameter from the external block
5169 // flag it for capturing
5171 if (ec.MustCaptureVariable (pi)) {
5172 if (Parameter.HasAddressTaken)
5173 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5176 ec.Report.Error (1628, loc,
5177 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5178 Name, ec.CurrentAnonymousMethod.ContainerType);
5181 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5182 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5183 storey.CaptureParameter (ec, pi, this);
5190 public override int GetHashCode ()
5192 return Name.GetHashCode ();
5195 public override bool Equals (object obj)
5197 ParameterReference pr = obj as ParameterReference;
5201 return Name == pr.Name;
5204 protected override void CloneTo (CloneContext clonectx, Expression target)
5210 public override Expression CreateExpressionTree (ResolveContext ec)
5212 HoistedVariable hv = GetHoistedVariable (ec);
5214 return hv.CreateExpressionTree ();
5216 return Parameter.ExpressionTreeVariableReference ();
5220 // Notice that for ref/out parameters, the type exposed is not the
5221 // same type exposed externally.
5224 // externally we expose "int&"
5225 // here we expose "int".
5227 // We record this in "is_ref". This means that the type system can treat
5228 // the type as it is expected, but when we generate the code, we generate
5229 // the alternate kind of code.
5231 protected override Expression DoResolve (ResolveContext ec)
5233 if (!DoResolveBase (ec))
5236 VerifyAssigned (ec);
5240 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5242 if (!DoResolveBase (ec))
5246 return base.DoResolveLValue (ec, right_side);
5249 public override void VerifyAssigned (ResolveContext rc)
5251 // HACK: Variables are not captured in probing mode
5252 if (rc.IsInProbingMode)
5255 if (HasOutModifier && !VariableInfo.IsAssigned (rc)) {
5256 rc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
5262 /// Invocation of methods or delegates.
5264 public class Invocation : ExpressionStatement
5266 protected Arguments arguments;
5267 protected Expression expr;
5268 protected MethodGroupExpr mg;
5270 public Invocation (Expression expr, Arguments arguments)
5273 this.arguments = arguments;
5275 var ma = expr as MemberAccess;
5276 loc = ma != null ? ma.GetLeftExpressionLocation () : expr.Location;
5281 public Arguments Arguments {
5287 public Expression Exp {
5293 public MethodGroupExpr MethodGroup {
5300 protected override void CloneTo (CloneContext clonectx, Expression t)
5302 Invocation target = (Invocation) t;
5304 if (arguments != null)
5305 target.arguments = arguments.Clone (clonectx);
5307 target.expr = expr.Clone (clonectx);
5310 public override bool ContainsEmitWithAwait ()
5312 if (arguments != null && arguments.ContainsEmitWithAwait ())
5315 return mg.ContainsEmitWithAwait ();
5318 public override Expression CreateExpressionTree (ResolveContext ec)
5320 Expression instance = mg.IsInstance ?
5321 mg.InstanceExpression.CreateExpressionTree (ec) :
5322 new NullLiteral (loc);
5324 var args = Arguments.CreateForExpressionTree (ec, arguments,
5326 mg.CreateExpressionTree (ec));
5328 return CreateExpressionFactoryCall (ec, "Call", args);
5331 protected override Expression DoResolve (ResolveContext ec)
5333 Expression member_expr;
5334 var atn = expr as ATypeNameExpression;
5336 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
5337 if (member_expr != null)
5338 member_expr = member_expr.Resolve (ec);
5340 member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5343 if (member_expr == null)
5347 // Next, evaluate all the expressions in the argument list
5349 bool dynamic_arg = false;
5350 if (arguments != null)
5351 arguments.Resolve (ec, out dynamic_arg);
5353 TypeSpec expr_type = member_expr.Type;
5354 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5355 return DoResolveDynamic (ec, member_expr);
5357 mg = member_expr as MethodGroupExpr;
5358 Expression invoke = null;
5361 if (expr_type != null && expr_type.IsDelegate) {
5362 invoke = new DelegateInvocation (member_expr, arguments, loc);
5363 invoke = invoke.Resolve (ec);
5364 if (invoke == null || !dynamic_arg)
5367 if (member_expr is RuntimeValueExpression) {
5368 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
5369 member_expr.Type.GetSignatureForError ()); ;
5373 MemberExpr me = member_expr as MemberExpr;
5375 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5379 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
5380 member_expr.GetSignatureForError ());
5385 if (invoke == null) {
5386 mg = DoResolveOverload (ec);
5392 return DoResolveDynamic (ec, member_expr);
5394 var method = mg.BestCandidate;
5395 type = mg.BestCandidateReturnType;
5397 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
5399 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5401 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5405 IsSpecialMethodInvocation (ec, method, loc);
5407 eclass = ExprClass.Value;
5411 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
5414 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
5416 args = dmb.Arguments;
5417 if (arguments != null)
5418 args.AddRange (arguments);
5419 } else if (mg == null) {
5420 if (arguments == null)
5421 args = new Arguments (1);
5425 args.Insert (0, new Argument (memberExpr));
5429 ec.Report.Error (1971, loc,
5430 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
5435 if (arguments == null)
5436 args = new Arguments (1);
5440 MemberAccess ma = expr as MemberAccess;
5442 var left_type = ma.LeftExpression as TypeExpr;
5443 if (left_type != null) {
5444 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5447 // Any value type has to be pass as by-ref to get back the same
5448 // instance on which the member was called
5450 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
5451 Argument.AType.Ref : Argument.AType.None;
5452 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
5454 } else { // is SimpleName
5456 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5458 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5463 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5466 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5468 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
5471 public override string GetSignatureForError ()
5473 return mg.GetSignatureForError ();
5477 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
5478 // or the type dynamic, then the member is invocable
5480 public static bool IsMemberInvocable (MemberSpec member)
5482 switch (member.Kind) {
5483 case MemberKind.Event:
5485 case MemberKind.Field:
5486 case MemberKind.Property:
5487 var m = member as IInterfaceMemberSpec;
5488 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
5494 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
5496 if (!method.IsReservedMethod)
5499 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
5502 ec.Report.SymbolRelatedToPreviousError (method);
5503 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5504 method.GetSignatureForError ());
5509 public override void Emit (EmitContext ec)
5511 mg.EmitCall (ec, arguments);
5514 public override void EmitStatement (EmitContext ec)
5519 // Pop the return value if there is one
5521 if (type.Kind != MemberKind.Void)
5522 ec.Emit (OpCodes.Pop);
5525 public override SLE.Expression MakeExpression (BuilderContext ctx)
5527 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
5530 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
5533 throw new NotSupportedException ();
5535 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5536 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
5540 public override object Accept (StructuralVisitor visitor)
5542 return visitor.Visit (this);
5547 // Implements simple new expression
5549 public class New : ExpressionStatement, IMemoryLocation
5551 protected Arguments arguments;
5554 // During bootstrap, it contains the RequestedType,
5555 // but if `type' is not null, it *might* contain a NewDelegate
5556 // (because of field multi-initialization)
5558 protected Expression RequestedType;
5560 protected MethodSpec method;
5562 public New (Expression requested_type, Arguments arguments, Location l)
5564 RequestedType = requested_type;
5565 this.arguments = arguments;
5570 public Arguments Arguments {
5577 // Returns true for resolved `new S()'
5579 public bool IsDefaultStruct {
5581 return arguments == null && type.IsStruct && GetType () == typeof (New);
5585 public Expression TypeExpression {
5587 return RequestedType;
5594 /// Converts complex core type syntax like 'new int ()' to simple constant
5596 public static Constant Constantify (TypeSpec t, Location loc)
5598 switch (t.BuiltinType) {
5599 case BuiltinTypeSpec.Type.Int:
5600 return new IntConstant (t, 0, loc);
5601 case BuiltinTypeSpec.Type.UInt:
5602 return new UIntConstant (t, 0, loc);
5603 case BuiltinTypeSpec.Type.Long:
5604 return new LongConstant (t, 0, loc);
5605 case BuiltinTypeSpec.Type.ULong:
5606 return new ULongConstant (t, 0, loc);
5607 case BuiltinTypeSpec.Type.Float:
5608 return new FloatConstant (t, 0, loc);
5609 case BuiltinTypeSpec.Type.Double:
5610 return new DoubleConstant (t, 0, loc);
5611 case BuiltinTypeSpec.Type.Short:
5612 return new ShortConstant (t, 0, loc);
5613 case BuiltinTypeSpec.Type.UShort:
5614 return new UShortConstant (t, 0, loc);
5615 case BuiltinTypeSpec.Type.SByte:
5616 return new SByteConstant (t, 0, loc);
5617 case BuiltinTypeSpec.Type.Byte:
5618 return new ByteConstant (t, 0, loc);
5619 case BuiltinTypeSpec.Type.Char:
5620 return new CharConstant (t, '\0', loc);
5621 case BuiltinTypeSpec.Type.Bool:
5622 return new BoolConstant (t, false, loc);
5623 case BuiltinTypeSpec.Type.Decimal:
5624 return new DecimalConstant (t, 0, loc);
5628 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
5630 if (t.IsNullableType)
5631 return Nullable.LiftedNull.Create (t, loc);
5636 public override bool ContainsEmitWithAwait ()
5638 return arguments != null && arguments.ContainsEmitWithAwait ();
5642 // Checks whether the type is an interface that has the
5643 // [ComImport, CoClass] attributes and must be treated
5646 public Expression CheckComImport (ResolveContext ec)
5648 if (!type.IsInterface)
5652 // Turn the call into:
5653 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5655 var real_class = type.MemberDefinition.GetAttributeCoClass ();
5656 if (real_class == null)
5659 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
5660 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5661 return cast.Resolve (ec);
5664 public override Expression CreateExpressionTree (ResolveContext ec)
5667 if (method == null) {
5668 args = new Arguments (1);
5669 args.Add (new Argument (new TypeOf (type, loc)));
5671 args = Arguments.CreateForExpressionTree (ec,
5672 arguments, new TypeOfMethod (method, loc));
5675 return CreateExpressionFactoryCall (ec, "New", args);
5678 protected override Expression DoResolve (ResolveContext ec)
5680 type = RequestedType.ResolveAsType (ec);
5684 eclass = ExprClass.Value;
5686 if (type.IsPointer) {
5687 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5688 TypeManager.CSharpName (type));
5692 if (arguments == null) {
5693 Constant c = Constantify (type, RequestedType.Location);
5695 return ReducedExpression.Create (c, this);
5698 if (type.IsDelegate) {
5699 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
5702 var tparam = type as TypeParameterSpec;
5703 if (tparam != null) {
5705 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
5706 // where type parameter constraint is inflated to struct
5708 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
5709 ec.Report.Error (304, loc,
5710 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
5711 TypeManager.CSharpName (type));
5714 if ((arguments != null) && (arguments.Count != 0)) {
5715 ec.Report.Error (417, loc,
5716 "`{0}': cannot provide arguments when creating an instance of a variable type",
5717 TypeManager.CSharpName (type));
5723 if (type.IsStatic) {
5724 ec.Report.SymbolRelatedToPreviousError (type);
5725 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5729 if (type.IsInterface || type.IsAbstract){
5730 if (!TypeManager.IsGenericType (type)) {
5731 RequestedType = CheckComImport (ec);
5732 if (RequestedType != null)
5733 return RequestedType;
5736 ec.Report.SymbolRelatedToPreviousError (type);
5737 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5742 // Any struct always defines parameterless constructor
5744 if (type.IsStruct && arguments == null)
5748 if (arguments != null) {
5749 arguments.Resolve (ec, out dynamic);
5754 method = ConstructorLookup (ec, type, ref arguments, loc);
5757 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5758 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
5764 bool DoEmitTypeParameter (EmitContext ec)
5766 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
5770 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
5771 var tparam = (TypeParameterSpec) type;
5773 if (tparam.IsReferenceType) {
5774 ec.Emit (OpCodes.Call, ctor_factory);
5778 // Allow DoEmit() to be called multiple times.
5779 // We need to create a new LocalTemporary each time since
5780 // you can't share LocalBuilders among ILGeneators.
5781 LocalTemporary temp = new LocalTemporary (type);
5783 Label label_activator = ec.DefineLabel ();
5784 Label label_end = ec.DefineLabel ();
5786 temp.AddressOf (ec, AddressOp.Store);
5787 ec.Emit (OpCodes.Initobj, type);
5790 ec.Emit (OpCodes.Box, type);
5791 ec.Emit (OpCodes.Brfalse, label_activator);
5793 temp.AddressOf (ec, AddressOp.Store);
5794 ec.Emit (OpCodes.Initobj, type);
5797 ec.Emit (OpCodes.Br_S, label_end);
5799 ec.MarkLabel (label_activator);
5801 ec.Emit (OpCodes.Call, ctor_factory);
5802 ec.MarkLabel (label_end);
5807 // This Emit can be invoked in two contexts:
5808 // * As a mechanism that will leave a value on the stack (new object)
5809 // * As one that wont (init struct)
5811 // If we are dealing with a ValueType, we have a few
5812 // situations to deal with:
5814 // * The target is a ValueType, and we have been provided
5815 // the instance (this is easy, we are being assigned).
5817 // * The target of New is being passed as an argument,
5818 // to a boxing operation or a function that takes a
5821 // In this case, we need to create a temporary variable
5822 // that is the argument of New.
5824 // Returns whether a value is left on the stack
5826 // *** Implementation note ***
5828 // To benefit from this optimization, each assignable expression
5829 // has to manually cast to New and call this Emit.
5831 // TODO: It's worth to implement it for arrays and fields
5833 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5835 bool is_value_type = TypeSpec.IsValueType (type);
5836 VariableReference vr = target as VariableReference;
5838 if (target != null && is_value_type && (vr != null || method == null)) {
5839 target.AddressOf (ec, AddressOp.Store);
5840 } else if (vr != null && vr.IsRef) {
5844 if (arguments != null) {
5845 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
5846 arguments = arguments.Emit (ec, false, true);
5848 arguments.Emit (ec);
5851 if (is_value_type) {
5852 if (method == null) {
5853 ec.Emit (OpCodes.Initobj, type);
5858 ec.Emit (OpCodes.Call, method);
5863 if (type is TypeParameterSpec)
5864 return DoEmitTypeParameter (ec);
5866 ec.Emit (OpCodes.Newobj, method);
5870 public override void Emit (EmitContext ec)
5872 LocalTemporary v = null;
5873 if (method == null && TypeSpec.IsValueType (type)) {
5874 // TODO: Use temporary variable from pool
5875 v = new LocalTemporary (type);
5882 public override void EmitStatement (EmitContext ec)
5884 LocalTemporary v = null;
5885 if (method == null && TypeSpec.IsValueType (type)) {
5886 // TODO: Use temporary variable from pool
5887 v = new LocalTemporary (type);
5891 ec.Emit (OpCodes.Pop);
5894 public void AddressOf (EmitContext ec, AddressOp mode)
5896 EmitAddressOf (ec, mode);
5899 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5901 LocalTemporary value_target = new LocalTemporary (type);
5903 if (type is TypeParameterSpec) {
5904 DoEmitTypeParameter (ec);
5905 value_target.Store (ec);
5906 value_target.AddressOf (ec, mode);
5907 return value_target;
5910 value_target.AddressOf (ec, AddressOp.Store);
5912 if (method == null) {
5913 ec.Emit (OpCodes.Initobj, type);
5915 if (arguments != null)
5916 arguments.Emit (ec);
5918 ec.Emit (OpCodes.Call, method);
5921 value_target.AddressOf (ec, mode);
5922 return value_target;
5925 protected override void CloneTo (CloneContext clonectx, Expression t)
5927 New target = (New) t;
5929 target.RequestedType = RequestedType.Clone (clonectx);
5930 if (arguments != null){
5931 target.arguments = arguments.Clone (clonectx);
5935 public override SLE.Expression MakeExpression (BuilderContext ctx)
5938 return base.MakeExpression (ctx);
5940 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
5944 public override object Accept (StructuralVisitor visitor)
5946 return visitor.Visit (this);
5951 // Array initializer expression, the expression is allowed in
5952 // variable or field initialization only which makes it tricky as
5953 // the type has to be infered based on the context either from field
5954 // type or variable type (think of multiple declarators)
5956 public class ArrayInitializer : Expression
5958 List<Expression> elements;
5959 BlockVariableDeclaration variable;
5961 public ArrayInitializer (List<Expression> init, Location loc)
5967 public ArrayInitializer (int count, Location loc)
5968 : this (new List<Expression> (count), loc)
5972 public ArrayInitializer (Location loc)
5980 get { return elements.Count; }
5983 public List<Expression> Elements {
5989 public Expression this [int index] {
5991 return elements [index];
5995 public BlockVariableDeclaration VariableDeclaration {
6006 public void Add (Expression expr)
6008 elements.Add (expr);
6011 public override bool ContainsEmitWithAwait ()
6013 throw new NotSupportedException ();
6016 public override Expression CreateExpressionTree (ResolveContext ec)
6018 throw new NotSupportedException ("ET");
6021 protected override void CloneTo (CloneContext clonectx, Expression t)
6023 var target = (ArrayInitializer) t;
6025 target.elements = new List<Expression> (elements.Count);
6026 foreach (var element in elements)
6027 target.elements.Add (element.Clone (clonectx));
6030 protected override Expression DoResolve (ResolveContext rc)
6032 var current_field = rc.CurrentMemberDefinition as FieldBase;
6033 TypeExpression type;
6034 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6035 type = new TypeExpression (current_field.MemberType, current_field.Location);
6036 } else if (variable != null) {
6037 if (variable.TypeExpression is VarExpr) {
6038 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6039 return EmptyExpression.Null;
6042 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6044 throw new NotImplementedException ("Unexpected array initializer context");
6047 return new ArrayCreation (type, this).Resolve (rc);
6050 public override void Emit (EmitContext ec)
6052 throw new InternalErrorException ("Missing Resolve call");
6055 public override object Accept (StructuralVisitor visitor)
6057 return visitor.Visit (this);
6062 /// 14.5.10.2: Represents an array creation expression.
6066 /// There are two possible scenarios here: one is an array creation
6067 /// expression that specifies the dimensions and optionally the
6068 /// initialization data and the other which does not need dimensions
6069 /// specified but where initialization data is mandatory.
6071 public class ArrayCreation : Expression
6073 FullNamedExpression requested_base_type;
6074 ArrayInitializer initializers;
6077 // The list of Argument types.
6078 // This is used to construct the `newarray' or constructor signature
6080 protected List<Expression> arguments;
6082 protected TypeSpec array_element_type;
6083 int num_arguments = 0;
6084 protected int dimensions;
6085 protected readonly ComposedTypeSpecifier rank;
6086 Expression first_emit;
6087 LocalTemporary first_emit_temp;
6089 protected List<Expression> array_data;
6091 Dictionary<int, int> bounds;
6094 // The number of constants in array initializers
6095 int const_initializers_count;
6096 bool only_constant_initializers;
6098 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6099 : this (requested_base_type, rank, initializers, l)
6101 arguments = new List<Expression> (exprs);
6102 num_arguments = arguments.Count;
6106 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6108 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6110 this.requested_base_type = requested_base_type;
6112 this.initializers = initializers;
6116 num_arguments = rank.Dimension;
6120 // For compiler generated single dimensional arrays only
6122 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6123 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6128 // For expressions like int[] foo = { 1, 2, 3 };
6130 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6131 : this (requested_base_type, null, initializers, initializers.Location)
6135 public ComposedTypeSpecifier Rank {
6141 public FullNamedExpression TypeExpression {
6143 return this.requested_base_type;
6147 public ArrayInitializer Initializers {
6149 return this.initializers;
6153 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6155 if (initializers != null && bounds == null) {
6157 // We use this to store all the data values in the order in which we
6158 // will need to store them in the byte blob later
6160 array_data = new List<Expression> (probe.Count);
6161 bounds = new Dictionary<int, int> ();
6164 if (specified_dims) {
6165 Expression a = arguments [idx];
6170 a = ConvertExpressionToArrayIndex (ec, a);
6176 if (initializers != null) {
6177 Constant c = a as Constant;
6178 if (c == null && a is ArrayIndexCast)
6179 c = ((ArrayIndexCast) a).Child as Constant;
6182 ec.Report.Error (150, a.Location, "A constant value is expected");
6188 value = System.Convert.ToInt32 (c.GetValue ());
6190 ec.Report.Error (150, a.Location, "A constant value is expected");
6194 // TODO: probe.Count does not fit ulong in
6195 if (value != probe.Count) {
6196 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6200 bounds[idx] = value;
6204 if (initializers == null)
6207 for (int i = 0; i < probe.Count; ++i) {
6209 if (o is ArrayInitializer) {
6210 var sub_probe = o as ArrayInitializer;
6211 if (idx + 1 >= dimensions){
6212 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6216 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
6217 if (!bounds.ContainsKey(idx + 1))
6218 bounds[idx + 1] = sub_probe.Count;
6220 if (bounds[idx + 1] != sub_probe.Count) {
6221 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
6225 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6228 } else if (child_bounds > 1) {
6229 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6231 Expression element = ResolveArrayElement (ec, o);
6232 if (element == null)
6235 // Initializers with the default values can be ignored
6236 Constant c = element as Constant;
6238 if (!c.IsDefaultInitializer (array_element_type)) {
6239 ++const_initializers_count;
6242 only_constant_initializers = false;
6245 array_data.Add (element);
6252 public override bool ContainsEmitWithAwait ()
6254 foreach (var arg in arguments) {
6255 if (arg.ContainsEmitWithAwait ())
6259 return InitializersContainAwait ();
6262 public override Expression CreateExpressionTree (ResolveContext ec)
6266 if (array_data == null) {
6267 args = new Arguments (arguments.Count + 1);
6268 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6269 foreach (Expression a in arguments)
6270 args.Add (new Argument (a.CreateExpressionTree (ec)));
6272 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6275 if (dimensions > 1) {
6276 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6280 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6281 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6282 if (array_data != null) {
6283 for (int i = 0; i < array_data.Count; ++i) {
6284 Expression e = array_data [i];
6285 args.Add (new Argument (e.CreateExpressionTree (ec)));
6289 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6292 void UpdateIndices (ResolveContext rc)
6295 for (var probe = initializers; probe != null;) {
6296 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
6298 bounds[i++] = probe.Count;
6300 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
6301 probe = (ArrayInitializer) probe[0];
6302 } else if (dimensions > i) {
6310 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
6312 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
6315 bool InitializersContainAwait ()
6317 if (array_data == null)
6320 foreach (var expr in array_data) {
6321 if (expr.ContainsEmitWithAwait ())
6328 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
6330 element = element.Resolve (ec);
6331 if (element == null)
6334 if (element is CompoundAssign.TargetExpression) {
6335 if (first_emit != null)
6336 throw new InternalErrorException ("Can only handle one mutator at a time");
6337 first_emit = element;
6338 element = first_emit_temp = new LocalTemporary (element.Type);
6341 return Convert.ImplicitConversionRequired (
6342 ec, element, array_element_type, loc);
6345 protected bool ResolveInitializers (ResolveContext ec)
6348 only_constant_initializers = true;
6351 if (arguments != null) {
6353 for (int i = 0; i < arguments.Count; ++i) {
6354 res &= CheckIndices (ec, initializers, i, true, dimensions);
6355 if (initializers != null)
6362 arguments = new List<Expression> ();
6364 if (!CheckIndices (ec, initializers, 0, false, dimensions))
6373 // Resolved the type of the array
6375 bool ResolveArrayType (ResolveContext ec)
6380 FullNamedExpression array_type_expr;
6381 if (num_arguments > 0) {
6382 array_type_expr = new ComposedCast (requested_base_type, rank);
6384 array_type_expr = requested_base_type;
6387 type = array_type_expr.ResolveAsType (ec);
6388 if (array_type_expr == null)
6391 var ac = type as ArrayContainer;
6393 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6397 array_element_type = ac.Element;
6398 dimensions = ac.Rank;
6403 protected override Expression DoResolve (ResolveContext ec)
6408 if (!ResolveArrayType (ec))
6412 // validate the initializers and fill in any missing bits
6414 if (!ResolveInitializers (ec))
6417 eclass = ExprClass.Value;
6421 byte [] MakeByteBlob ()
6426 int count = array_data.Count;
6428 TypeSpec element_type = array_element_type;
6429 if (element_type.IsEnum)
6430 element_type = EnumSpec.GetUnderlyingType (element_type);
6432 factor = BuiltinTypeSpec.GetSize (element_type);
6434 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6436 data = new byte [(count * factor + 3) & ~3];
6439 for (int i = 0; i < count; ++i) {
6440 var c = array_data[i] as Constant;
6446 object v = c.GetValue ();
6448 switch (element_type.BuiltinType) {
6449 case BuiltinTypeSpec.Type.Long:
6450 long lval = (long) v;
6452 for (int j = 0; j < factor; ++j) {
6453 data[idx + j] = (byte) (lval & 0xFF);
6457 case BuiltinTypeSpec.Type.ULong:
6458 ulong ulval = (ulong) v;
6460 for (int j = 0; j < factor; ++j) {
6461 data[idx + j] = (byte) (ulval & 0xFF);
6462 ulval = (ulval >> 8);
6465 case BuiltinTypeSpec.Type.Float:
6466 var fval = SingleConverter.SingleToInt32Bits((float) v);
6468 data[idx] = (byte) (fval & 0xff);
6469 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
6470 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
6471 data[idx + 3] = (byte) (fval >> 24);
6473 case BuiltinTypeSpec.Type.Double:
6474 element = BitConverter.GetBytes ((double) v);
6476 for (int j = 0; j < factor; ++j)
6477 data[idx + j] = element[j];
6479 // FIXME: Handle the ARM float format.
6480 if (!BitConverter.IsLittleEndian)
6481 System.Array.Reverse (data, idx, 8);
6483 case BuiltinTypeSpec.Type.Char:
6484 int chval = (int) ((char) v);
6486 data[idx] = (byte) (chval & 0xff);
6487 data[idx + 1] = (byte) (chval >> 8);
6489 case BuiltinTypeSpec.Type.Short:
6490 int sval = (int) ((short) v);
6492 data[idx] = (byte) (sval & 0xff);
6493 data[idx + 1] = (byte) (sval >> 8);
6495 case BuiltinTypeSpec.Type.UShort:
6496 int usval = (int) ((ushort) v);
6498 data[idx] = (byte) (usval & 0xff);
6499 data[idx + 1] = (byte) (usval >> 8);
6501 case BuiltinTypeSpec.Type.Int:
6504 data[idx] = (byte) (val & 0xff);
6505 data[idx + 1] = (byte) ((val >> 8) & 0xff);
6506 data[idx + 2] = (byte) ((val >> 16) & 0xff);
6507 data[idx + 3] = (byte) (val >> 24);
6509 case BuiltinTypeSpec.Type.UInt:
6510 uint uval = (uint) v;
6512 data[idx] = (byte) (uval & 0xff);
6513 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
6514 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
6515 data[idx + 3] = (byte) (uval >> 24);
6517 case BuiltinTypeSpec.Type.SByte:
6518 data[idx] = (byte) (sbyte) v;
6520 case BuiltinTypeSpec.Type.Byte:
6521 data[idx] = (byte) v;
6523 case BuiltinTypeSpec.Type.Bool:
6524 data[idx] = (byte) ((bool) v ? 1 : 0);
6526 case BuiltinTypeSpec.Type.Decimal:
6527 int[] bits = Decimal.GetBits ((decimal) v);
6530 // FIXME: For some reason, this doesn't work on the MS runtime.
6531 int[] nbits = new int[4];
6537 for (int j = 0; j < 4; j++) {
6538 data[p++] = (byte) (nbits[j] & 0xff);
6539 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
6540 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
6541 data[p++] = (byte) (nbits[j] >> 24);
6545 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6554 #if NET_4_0 || MONODROID
6555 public override SLE.Expression MakeExpression (BuilderContext ctx)
6558 return base.MakeExpression (ctx);
6560 var initializers = new SLE.Expression [array_data.Count];
6561 for (var i = 0; i < initializers.Length; i++) {
6562 if (array_data [i] == null)
6563 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
6565 initializers [i] = array_data [i].MakeExpression (ctx);
6568 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
6574 // Emits the initializers for the array
6576 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
6578 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
6583 // First, the static data
6585 byte [] data = MakeByteBlob ();
6586 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
6588 if (stackArray == null) {
6589 ec.Emit (OpCodes.Dup);
6591 stackArray.Emit (ec);
6594 ec.Emit (OpCodes.Ldtoken, fb);
6595 ec.Emit (OpCodes.Call, m);
6600 // Emits pieces of the array that can not be computed at compile
6601 // time (variables and string locations).
6603 // This always expect the top value on the stack to be the array
6605 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
6607 int dims = bounds.Count;
6608 var current_pos = new int [dims];
6610 for (int i = 0; i < array_data.Count; i++){
6612 Expression e = array_data [i];
6613 var c = e as Constant;
6615 // Constant can be initialized via StaticInitializer
6616 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
6620 if (stackArray != null) {
6621 if (e.ContainsEmitWithAwait ()) {
6622 e = e.EmitToField (ec);
6625 stackArray.Emit (ec);
6627 ec.Emit (OpCodes.Dup);
6630 for (int idx = 0; idx < dims; idx++)
6631 ec.EmitInt (current_pos [idx]);
6634 // If we are dealing with a struct, get the
6635 // address of it, so we can store it.
6637 if (dims == 1 && etype.IsStruct) {
6638 switch (etype.BuiltinType) {
6639 case BuiltinTypeSpec.Type.Byte:
6640 case BuiltinTypeSpec.Type.SByte:
6641 case BuiltinTypeSpec.Type.Bool:
6642 case BuiltinTypeSpec.Type.Short:
6643 case BuiltinTypeSpec.Type.UShort:
6644 case BuiltinTypeSpec.Type.Char:
6645 case BuiltinTypeSpec.Type.Int:
6646 case BuiltinTypeSpec.Type.UInt:
6647 case BuiltinTypeSpec.Type.Long:
6648 case BuiltinTypeSpec.Type.ULong:
6649 case BuiltinTypeSpec.Type.Float:
6650 case BuiltinTypeSpec.Type.Double:
6653 ec.Emit (OpCodes.Ldelema, etype);
6660 ec.EmitArrayStore ((ArrayContainer) type);
6666 for (int j = dims - 1; j >= 0; j--){
6668 if (current_pos [j] < bounds [j])
6670 current_pos [j] = 0;
6675 public override void Emit (EmitContext ec)
6677 EmitToFieldSource (ec);
6680 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
6682 if (first_emit != null) {
6683 first_emit.Emit (ec);
6684 first_emit_temp.Store (ec);
6687 FieldExpr await_stack_field;
6688 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
6689 await_stack_field = ec.GetTemporaryField (type);
6692 await_stack_field = null;
6695 EmitExpressionsList (ec, arguments);
6697 ec.EmitArrayNew ((ArrayContainer) type);
6699 if (initializers == null)
6700 return await_stack_field;
6702 if (await_stack_field != null)
6703 await_stack_field.EmitAssignFromStack (ec);
6707 // Emit static initializer for arrays which contain more than 2 items and
6708 // the static initializer will initialize at least 25% of array values or there
6709 // is more than 10 items to be initialized
6711 // NOTE: const_initializers_count does not contain default constant values.
6713 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
6714 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
6715 EmitStaticInitializers (ec, await_stack_field);
6717 if (!only_constant_initializers)
6718 EmitDynamicInitializers (ec, false, await_stack_field);
6722 EmitDynamicInitializers (ec, true, await_stack_field);
6725 if (first_emit_temp != null)
6726 first_emit_temp.Release (ec);
6728 return await_stack_field;
6731 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
6733 // no multi dimensional or jagged arrays
6734 if (arguments.Count != 1 || array_element_type.IsArray) {
6735 base.EncodeAttributeValue (rc, enc, targetType);
6739 // No array covariance, except for array -> object
6740 if (type != targetType) {
6741 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
6742 base.EncodeAttributeValue (rc, enc, targetType);
6746 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
6747 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
6752 // Single dimensional array of 0 size
6753 if (array_data == null) {
6754 IntConstant ic = arguments[0] as IntConstant;
6755 if (ic == null || !ic.IsDefaultValue) {
6756 base.EncodeAttributeValue (rc, enc, targetType);
6764 enc.Encode (array_data.Count);
6765 foreach (var element in array_data) {
6766 element.EncodeAttributeValue (rc, enc, array_element_type);
6770 protected override void CloneTo (CloneContext clonectx, Expression t)
6772 ArrayCreation target = (ArrayCreation) t;
6774 if (requested_base_type != null)
6775 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6777 if (arguments != null){
6778 target.arguments = new List<Expression> (arguments.Count);
6779 foreach (Expression e in arguments)
6780 target.arguments.Add (e.Clone (clonectx));
6783 if (initializers != null)
6784 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
6787 public override object Accept (StructuralVisitor visitor)
6789 return visitor.Visit (this);
6794 // Represents an implicitly typed array epxression
6796 class ImplicitlyTypedArrayCreation : ArrayCreation
6798 TypeInferenceContext best_type_inference;
6800 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6801 : base (null, rank, initializers, loc)
6805 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
6806 : base (null, initializers, loc)
6810 protected override Expression DoResolve (ResolveContext ec)
6815 dimensions = rank.Dimension;
6817 best_type_inference = new TypeInferenceContext ();
6819 if (!ResolveInitializers (ec))
6822 best_type_inference.FixAllTypes (ec);
6823 array_element_type = best_type_inference.InferredTypeArguments[0];
6824 best_type_inference = null;
6826 if (array_element_type == null ||
6827 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
6828 arguments.Count != rank.Dimension) {
6829 ec.Report.Error (826, loc,
6830 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6835 // At this point we found common base type for all initializer elements
6836 // but we have to be sure that all static initializer elements are of
6839 UnifyInitializerElement (ec);
6841 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
6842 eclass = ExprClass.Value;
6847 // Converts static initializer only
6849 void UnifyInitializerElement (ResolveContext ec)
6851 for (int i = 0; i < array_data.Count; ++i) {
6852 Expression e = array_data[i];
6854 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6858 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6860 element = element.Resolve (ec);
6861 if (element != null)
6862 best_type_inference.AddCommonTypeBound (element.Type);
6868 sealed class CompilerGeneratedThis : This
6870 public CompilerGeneratedThis (TypeSpec type, Location loc)
6874 eclass = ExprClass.Variable;
6877 protected override Expression DoResolve (ResolveContext ec)
6882 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6889 /// Represents the `this' construct
6892 public class This : VariableReference
6894 sealed class ThisVariable : ILocalVariable
6896 public static readonly ILocalVariable Instance = new ThisVariable ();
6898 public void Emit (EmitContext ec)
6903 public void EmitAssign (EmitContext ec)
6905 throw new InvalidOperationException ();
6908 public void EmitAddressOf (EmitContext ec)
6914 VariableInfo variable_info;
6916 public This (Location loc)
6923 public override string Name {
6924 get { return "this"; }
6927 public override bool IsLockedByStatement {
6935 public override bool IsRef {
6936 get { return type.IsStruct; }
6939 public override bool IsSideEffectFree {
6945 protected override ILocalVariable Variable {
6946 get { return ThisVariable.Instance; }
6949 public override VariableInfo VariableInfo {
6950 get { return variable_info; }
6953 public override bool IsFixed {
6954 get { return false; }
6959 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
6962 // It's null for all cases when we don't need to check `this'
6963 // definitive assignment
6965 if (variable_info == null)
6968 if (rc.OmitStructFlowAnalysis)
6971 if (!variable_info.IsAssigned (rc)) {
6972 rc.Report.Error (188, loc,
6973 "The `this' object cannot be used before all of its fields are assigned to");
6977 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
6979 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6980 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6981 } else if (ec.CurrentAnonymousMethod != null) {
6982 ec.Report.Error (1673, loc,
6983 "Anonymous methods inside structs cannot access instance members of `this'. " +
6984 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6986 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6990 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6995 AnonymousMethodStorey storey = ae.Storey;
6996 return storey != null ? storey.HoistedThis : null;
6999 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7001 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7004 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7007 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7013 public virtual void ResolveBase (ResolveContext ec)
7015 eclass = ExprClass.Variable;
7016 type = ec.CurrentType;
7018 if (!IsThisAvailable (ec, false)) {
7019 Error_ThisNotAvailable (ec);
7023 var block = ec.CurrentBlock;
7024 if (block != null) {
7025 var top = block.ParametersBlock.TopBlock;
7026 if (top.ThisVariable != null)
7027 variable_info = top.ThisVariable.VariableInfo;
7029 AnonymousExpression am = ec.CurrentAnonymousMethod;
7030 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7032 // Hoisted this is almost like hoisted variable but not exactly. When
7033 // there is no variable hoisted we can simply emit an instance method
7034 // without lifting this into a storey. Unfotunatelly this complicates
7035 // things in other cases because we don't know where this will be hoisted
7036 // until top-level block is fully resolved
7038 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7039 am.SetHasThisAccess ();
7044 protected override Expression DoResolve (ResolveContext ec)
7048 CheckStructThisDefiniteAssignment (ec);
7053 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7055 if (eclass == ExprClass.Unresolved)
7058 if (variable_info != null)
7059 variable_info.SetAssigned (ec);
7062 if (right_side == EmptyExpression.UnaryAddress)
7063 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7064 else if (right_side == EmptyExpression.OutAccess)
7065 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7067 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7073 public override int GetHashCode()
7075 throw new NotImplementedException ();
7078 public override bool Equals (object obj)
7080 This t = obj as This;
7087 protected override void CloneTo (CloneContext clonectx, Expression t)
7092 public override void SetHasAddressTaken ()
7097 public override void VerifyAssigned (ResolveContext rc)
7101 public override object Accept (StructuralVisitor visitor)
7103 return visitor.Visit (this);
7108 /// Represents the `__arglist' construct
7110 public class ArglistAccess : Expression
7112 public ArglistAccess (Location loc)
7117 protected override void CloneTo (CloneContext clonectx, Expression target)
7122 public override bool ContainsEmitWithAwait ()
7127 public override Expression CreateExpressionTree (ResolveContext ec)
7129 throw new NotSupportedException ("ET");
7132 protected override Expression DoResolve (ResolveContext ec)
7134 eclass = ExprClass.Variable;
7135 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
7137 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7138 ec.Report.Error (190, loc,
7139 "The __arglist construct is valid only within a variable argument method");
7145 public override void Emit (EmitContext ec)
7147 ec.Emit (OpCodes.Arglist);
7150 public override object Accept (StructuralVisitor visitor)
7152 return visitor.Visit (this);
7157 /// Represents the `__arglist (....)' construct
7159 public class Arglist : Expression
7161 Arguments arguments;
7163 public Arglist (Location loc)
7168 public Arglist (Arguments args, Location l)
7174 public Arguments Arguments {
7180 public MetaType[] ArgumentTypes {
7182 if (arguments == null)
7183 return MetaType.EmptyTypes;
7185 var retval = new MetaType[arguments.Count];
7186 for (int i = 0; i < retval.Length; i++)
7187 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
7193 public override bool ContainsEmitWithAwait ()
7195 throw new NotImplementedException ();
7198 public override Expression CreateExpressionTree (ResolveContext ec)
7200 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7204 protected override Expression DoResolve (ResolveContext ec)
7206 eclass = ExprClass.Variable;
7207 type = InternalType.Arglist;
7208 if (arguments != null) {
7209 bool dynamic; // Can be ignored as there is always only 1 overload
7210 arguments.Resolve (ec, out dynamic);
7216 public override void Emit (EmitContext ec)
7218 if (arguments != null)
7219 arguments.Emit (ec);
7222 protected override void CloneTo (CloneContext clonectx, Expression t)
7224 Arglist target = (Arglist) t;
7226 if (arguments != null)
7227 target.arguments = arguments.Clone (clonectx);
7230 public override object Accept (StructuralVisitor visitor)
7232 return visitor.Visit (this);
7236 public class RefValueExpr : ShimExpression, IAssignMethod
7238 FullNamedExpression texpr;
7240 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7247 public FullNamedExpression TypeExpression {
7253 public override bool ContainsEmitWithAwait ()
7258 protected override Expression DoResolve (ResolveContext rc)
7260 expr = expr.Resolve (rc);
7261 type = texpr.ResolveAsType (rc);
7262 if (expr == null || type == null)
7265 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7266 eclass = ExprClass.Value;
7270 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7272 return DoResolve (rc);
7275 public override void Emit (EmitContext ec)
7278 ec.Emit (OpCodes.Refanyval, type);
7279 ec.EmitLoadFromPtr (type);
7282 public void Emit (EmitContext ec, bool leave_copy)
7284 throw new NotImplementedException ();
7287 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7290 ec.Emit (OpCodes.Refanyval, type);
7293 LocalTemporary temporary = null;
7295 ec.Emit (OpCodes.Dup);
7296 temporary = new LocalTemporary (source.Type);
7297 temporary.Store (ec);
7300 ec.EmitStoreFromPtr (type);
7302 if (temporary != null) {
7303 temporary.Emit (ec);
7304 temporary.Release (ec);
7308 public override object Accept (StructuralVisitor visitor)
7310 return visitor.Visit (this);
7314 public class RefTypeExpr : ShimExpression
7316 public RefTypeExpr (Expression expr, Location loc)
7322 protected override Expression DoResolve (ResolveContext rc)
7324 expr = expr.Resolve (rc);
7328 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7332 type = rc.BuiltinTypes.Type;
7333 eclass = ExprClass.Value;
7337 public override void Emit (EmitContext ec)
7340 ec.Emit (OpCodes.Refanytype);
7341 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7343 ec.Emit (OpCodes.Call, m);
7346 public override object Accept (StructuralVisitor visitor)
7348 return visitor.Visit (this);
7352 public class MakeRefExpr : ShimExpression
7354 public MakeRefExpr (Expression expr, Location loc)
7360 public override bool ContainsEmitWithAwait ()
7362 throw new NotImplementedException ();
7365 protected override Expression DoResolve (ResolveContext rc)
7367 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
7368 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
7369 eclass = ExprClass.Value;
7373 public override void Emit (EmitContext ec)
7375 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
7376 ec.Emit (OpCodes.Mkrefany, expr.Type);
7379 public override object Accept (StructuralVisitor visitor)
7381 return visitor.Visit (this);
7386 /// Implements the typeof operator
7388 public class TypeOf : Expression {
7389 FullNamedExpression QueriedType;
7392 public TypeOf (FullNamedExpression queried_type, Location l)
7394 QueriedType = queried_type;
7399 // Use this constructor for any compiler generated typeof expression
7401 public TypeOf (TypeSpec type, Location loc)
7403 this.typearg = type;
7409 public override bool IsSideEffectFree {
7415 public TypeSpec TypeArgument {
7421 public FullNamedExpression TypeExpression {
7430 protected override void CloneTo (CloneContext clonectx, Expression t)
7432 TypeOf target = (TypeOf) t;
7433 if (QueriedType != null)
7434 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
7437 public override bool ContainsEmitWithAwait ()
7442 public override Expression CreateExpressionTree (ResolveContext ec)
7444 Arguments args = new Arguments (2);
7445 args.Add (new Argument (this));
7446 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7447 return CreateExpressionFactoryCall (ec, "Constant", args);
7450 protected override Expression DoResolve (ResolveContext ec)
7452 if (eclass != ExprClass.Unresolved)
7455 if (typearg == null) {
7457 // Pointer types are allowed without explicit unsafe, they are just tokens
7459 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
7460 typearg = QueriedType.ResolveAsType (ec);
7463 if (typearg == null)
7466 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7467 ec.Report.Error (1962, QueriedType.Location,
7468 "The typeof operator cannot be used on the dynamic type");
7472 type = ec.BuiltinTypes.Type;
7474 // Even though what is returned is a type object, it's treated as a value by the compiler.
7475 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7476 eclass = ExprClass.Value;
7480 static bool ContainsDynamicType (TypeSpec type)
7482 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7485 var element_container = type as ElementTypeSpec;
7486 if (element_container != null)
7487 return ContainsDynamicType (element_container.Element);
7489 foreach (var t in type.TypeArguments) {
7490 if (ContainsDynamicType (t)) {
7498 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7500 // Target type is not System.Type therefore must be object
7501 // and we need to use different encoding sequence
7502 if (targetType != type)
7505 if (typearg is InflatedTypeSpec) {
7508 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
7509 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7510 typearg.GetSignatureForError ());
7514 gt = gt.DeclaringType;
7515 } while (gt != null);
7518 if (ContainsDynamicType (typearg)) {
7519 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7523 enc.EncodeTypeName (typearg);
7526 public override void Emit (EmitContext ec)
7528 ec.Emit (OpCodes.Ldtoken, typearg);
7529 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7531 ec.Emit (OpCodes.Call, m);
7534 public override object Accept (StructuralVisitor visitor)
7536 return visitor.Visit (this);
7540 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
7542 public TypeOfMethod (MethodSpec method, Location loc)
7543 : base (method, loc)
7547 protected override Expression DoResolve (ResolveContext ec)
7549 if (member.IsConstructor) {
7550 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
7552 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
7558 return base.DoResolve (ec);
7561 public override void Emit (EmitContext ec)
7563 ec.Emit (OpCodes.Ldtoken, member);
7566 ec.Emit (OpCodes.Castclass, type);
7569 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7571 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
7574 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7576 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
7580 abstract class TypeOfMember<T> : Expression where T : MemberSpec
7582 protected readonly T member;
7584 protected TypeOfMember (T member, Location loc)
7586 this.member = member;
7590 public override bool IsSideEffectFree {
7596 public override bool ContainsEmitWithAwait ()
7601 public override Expression CreateExpressionTree (ResolveContext ec)
7603 Arguments args = new Arguments (2);
7604 args.Add (new Argument (this));
7605 args.Add (new Argument (new TypeOf (type, loc)));
7606 return CreateExpressionFactoryCall (ec, "Constant", args);
7609 protected override Expression DoResolve (ResolveContext ec)
7611 eclass = ExprClass.Value;
7615 public override void Emit (EmitContext ec)
7617 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
7618 PredefinedMember<MethodSpec> p;
7620 p = GetTypeFromHandleGeneric (ec);
7621 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
7623 p = GetTypeFromHandle (ec);
7626 var mi = p.Resolve (loc);
7628 ec.Emit (OpCodes.Call, mi);
7631 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
7632 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
7635 sealed class TypeOfField : TypeOfMember<FieldSpec>
7637 public TypeOfField (FieldSpec field, Location loc)
7642 protected override Expression DoResolve (ResolveContext ec)
7644 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
7648 return base.DoResolve (ec);
7651 public override void Emit (EmitContext ec)
7653 ec.Emit (OpCodes.Ldtoken, member);
7657 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7659 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
7662 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7664 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
7669 /// Implements the sizeof expression
7671 public class SizeOf : Expression {
7672 readonly Expression texpr;
7673 TypeSpec type_queried;
7675 public SizeOf (Expression queried_type, Location l)
7677 this.texpr = queried_type;
7681 public override bool IsSideEffectFree {
7687 public Expression TypeExpression {
7693 public override bool ContainsEmitWithAwait ()
7698 public override Expression CreateExpressionTree (ResolveContext ec)
7700 Error_PointerInsideExpressionTree (ec);
7704 protected override Expression DoResolve (ResolveContext ec)
7706 type_queried = texpr.ResolveAsType (ec);
7707 if (type_queried == null)
7710 if (type_queried.IsEnum)
7711 type_queried = EnumSpec.GetUnderlyingType (type_queried);
7713 int size_of = BuiltinTypeSpec.GetSize (type_queried);
7715 return new IntConstant (ec.BuiltinTypes, size_of, loc);
7718 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
7723 ec.Report.Error (233, loc,
7724 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7725 TypeManager.CSharpName (type_queried));
7728 type = ec.BuiltinTypes.Int;
7729 eclass = ExprClass.Value;
7733 public override void Emit (EmitContext ec)
7735 ec.Emit (OpCodes.Sizeof, type_queried);
7738 protected override void CloneTo (CloneContext clonectx, Expression t)
7742 public override object Accept (StructuralVisitor visitor)
7744 return visitor.Visit (this);
7749 /// Implements the qualified-alias-member (::) expression.
7751 public class QualifiedAliasMember : MemberAccess
7753 readonly string alias;
7754 public static readonly string GlobalAlias = "global";
7756 public QualifiedAliasMember (string alias, string identifier, Location l)
7757 : base (null, identifier, l)
7762 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7763 : base (null, identifier, targs, l)
7768 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
7769 : base (null, identifier, arity, l)
7774 public string Alias {
7780 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
7782 if (alias == GlobalAlias) {
7783 expr = ec.Module.GlobalRootNamespace;
7784 return base.ResolveAsTypeOrNamespace (ec);
7787 int errors = ec.Module.Compiler.Report.Errors;
7788 expr = ec.LookupNamespaceAlias (alias);
7790 if (errors == ec.Module.Compiler.Report.Errors)
7791 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7795 return base.ResolveAsTypeOrNamespace (ec);
7798 protected override Expression DoResolve (ResolveContext ec)
7800 return ResolveAsTypeOrNamespace (ec);
7803 public override string GetSignatureForError ()
7806 if (targs != null) {
7807 name = Name + "<" + targs.GetSignatureForError () + ">";
7810 return alias + "::" + name;
7813 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7815 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
7816 rc.Module.Compiler.Report.Error (687, loc,
7817 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
7818 GetSignatureForError ());
7823 return DoResolve (rc);
7826 protected override void CloneTo (CloneContext clonectx, Expression t)
7831 public override object Accept (StructuralVisitor visitor)
7833 return visitor.Visit (this);
7838 /// Implements the member access expression
7840 public class MemberAccess : ATypeNameExpression
7842 protected Expression expr;
7844 public MemberAccess (Expression expr, string id)
7845 : base (id, expr.Location)
7850 public MemberAccess (Expression expr, string identifier, Location loc)
7851 : base (identifier, loc)
7856 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7857 : base (identifier, args, loc)
7862 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
7863 : base (identifier, arity, loc)
7868 public Expression LeftExpression {
7874 protected override Expression DoResolve (ResolveContext rc)
7876 var e = DoResolveName (rc, null);
7878 if (!rc.OmitStructFlowAnalysis) {
7879 var fe = e as FieldExpr;
7881 fe.VerifyAssignedStructField (rc, null);
7888 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
7890 var e = DoResolveName (rc, rhs);
7892 if (!rc.OmitStructFlowAnalysis) {
7893 var fe = e as FieldExpr;
7894 if (fe != null && fe.InstanceExpression is FieldExpr) {
7895 fe = (FieldExpr) fe.InstanceExpression;
7896 fe.VerifyAssignedStructField (rc, rhs);
7903 Expression DoResolveName (ResolveContext rc, Expression right_side)
7905 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
7909 if (right_side != null) {
7910 if (e is TypeExpr) {
7911 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
7915 e = e.ResolveLValue (rc, right_side);
7917 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
7923 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
7925 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
7926 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
7928 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
7931 public Location GetLeftExpressionLocation ()
7933 Expression expr = LeftExpression;
7934 MemberAccess ma = expr as MemberAccess;
7935 while (ma != null && ma.LeftExpression != null) {
7936 expr = ma.LeftExpression;
7937 ma = expr as MemberAccess;
7940 return expr == null ? Location : expr.Location;
7943 public static bool IsValidDotExpression (TypeSpec type)
7945 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
7946 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
7948 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7951 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7953 var sn = expr as SimpleName;
7954 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
7957 // Resolve the expression with flow analysis turned off, we'll do the definite
7958 // assignment checks later. This is because we don't know yet what the expression
7959 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7960 // definite assignment check on the actual field and not on the whole struct.
7962 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
7964 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
7967 // Resolve expression which does have type set as we need expression type
7968 // with disable flow analysis as we don't know whether left side expression
7969 // is used as variable or type
7971 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
7972 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
7973 expr = expr.Resolve (rc);
7975 } else if (expr is TypeParameterExpr) {
7976 expr.Error_UnexpectedKind (rc, flags, sn.Location);
7980 expr = expr.Resolve (rc, flags);
7987 Namespace ns = expr as Namespace;
7989 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
7991 if (retval == null) {
7992 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
7996 if (HasTypeArguments)
7997 return new GenericTypeExpr (retval.Type, targs, loc);
8003 TypeSpec expr_type = expr.Type;
8004 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8005 me = expr as MemberExpr;
8007 me.ResolveInstanceExpression (rc, null);
8010 // Run defined assigned checks on expressions resolved with
8011 // disabled flow-analysis
8014 var vr = expr as VariableReference;
8016 vr.VerifyAssigned (rc);
8019 Arguments args = new Arguments (1);
8020 args.Add (new Argument (expr));
8021 return new DynamicMemberBinder (Name, args, loc);
8024 if (!IsValidDotExpression (expr_type)) {
8025 Error_OperatorCannotBeApplied (rc, expr_type);
8029 var lookup_arity = Arity;
8030 bool errorMode = false;
8031 Expression member_lookup;
8033 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8034 if (member_lookup == null) {
8036 // Try to look for extension method when member lookup failed
8038 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8039 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8040 if (methods != null) {
8041 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8042 if (HasTypeArguments) {
8043 if (!targs.Resolve (rc))
8046 emg.SetTypeArguments (rc, targs);
8050 // Run defined assigned checks on expressions resolved with
8051 // disabled flow-analysis
8053 if (sn != null && !errorMode) {
8054 var vr = expr as VariableReference;
8056 vr.VerifyAssigned (rc);
8059 // TODO: it should really skip the checks bellow
8060 return emg.Resolve (rc);
8066 if (member_lookup == null) {
8067 var dep = expr_type.GetMissingDependencies ();
8069 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8070 } else if (expr is TypeExpr) {
8071 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8073 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8079 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8080 // Leave it to overload resolution to report correct error
8081 } else if (!(member_lookup is TypeExpr)) {
8082 // TODO: rc.SymbolRelatedToPreviousError
8083 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8088 if (member_lookup != null)
8092 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8096 TypeExpr texpr = member_lookup as TypeExpr;
8097 if (texpr != null) {
8098 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8099 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8100 Name, texpr.GetSignatureForError ());
8103 if (!texpr.Type.IsAccessible (rc)) {
8104 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8105 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8109 if (HasTypeArguments) {
8110 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8113 return member_lookup;
8116 me = member_lookup as MemberExpr;
8118 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8122 me = me.ResolveMemberAccess (rc, expr, sn);
8125 if (!targs.Resolve (rc))
8128 me.SetTypeArguments (rc, targs);
8132 // Run defined assigned checks on expressions resolved with
8133 // disabled flow-analysis
8135 if (sn != null && !(me is FieldExpr && TypeSpec.IsValueType (expr_type))) {
8136 var vr = expr as VariableReference;
8138 vr.VerifyAssigned (rc);
8144 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8146 FullNamedExpression fexpr = expr as FullNamedExpression;
8147 if (fexpr == null) {
8148 expr.ResolveAsType (rc);
8152 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8154 if (expr_resolved == null)
8157 Namespace ns = expr_resolved as Namespace;
8159 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8161 if (retval == null) {
8162 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8163 } else if (HasTypeArguments) {
8164 retval = new GenericTypeExpr (retval.Type, targs, loc);
8165 if (retval.ResolveAsType (rc) == null)
8172 var tnew_expr = expr_resolved.ResolveAsType (rc);
8173 if (tnew_expr == null)
8176 TypeSpec expr_type = tnew_expr;
8177 if (TypeManager.IsGenericParameter (expr_type)) {
8178 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8179 tnew_expr.GetSignatureForError ());
8183 var qam = this as QualifiedAliasMember;
8185 rc.Module.Compiler.Report.Error (431, loc,
8186 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8191 TypeSpec nested = null;
8192 while (expr_type != null) {
8193 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8194 if (nested == null) {
8195 if (expr_type == tnew_expr) {
8196 Error_IdentifierNotFound (rc, expr_type, Name);
8200 expr_type = tnew_expr;
8201 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8202 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
8206 if (nested.IsAccessible (rc))
8210 // Keep looking after inaccessible candidate but only if
8211 // we are not in same context as the definition itself
8213 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
8216 expr_type = expr_type.BaseType;
8221 if (HasTypeArguments) {
8222 texpr = new GenericTypeExpr (nested, targs, loc);
8224 texpr = new GenericOpenTypeExpr (nested, loc);
8227 texpr = new TypeExpression (nested, loc);
8230 if (texpr.ResolveAsType (rc) == null)
8236 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
8238 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
8240 if (nested != null) {
8241 Error_TypeArgumentsCannotBeUsed (rc, nested, Arity, expr.Location);
8245 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
8246 if (any_other_member != null) {
8247 any_other_member.Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
8251 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
8252 Name, expr_type.GetSignatureForError ());
8255 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
8257 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
8260 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
8262 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8263 ec.Report.SymbolRelatedToPreviousError (type);
8265 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, type, name, Arity);
8267 // a using directive or an assembly reference
8269 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
8271 missing = "an assembly reference";
8274 ec.Report.Error (1061, loc,
8275 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
8276 type.GetSignatureForError (), name, missing);
8280 base.Error_TypeDoesNotContainDefinition (ec, type, name);
8283 public override string GetSignatureForError ()
8285 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
8288 protected override void CloneTo (CloneContext clonectx, Expression t)
8290 MemberAccess target = (MemberAccess) t;
8292 target.expr = expr.Clone (clonectx);
8295 public override object Accept (StructuralVisitor visitor)
8297 return visitor.Visit (this);
8302 /// Implements checked expressions
8304 public class CheckedExpr : Expression {
8306 public Expression Expr;
8308 public CheckedExpr (Expression e, Location l)
8314 public override bool ContainsEmitWithAwait ()
8316 return Expr.ContainsEmitWithAwait ();
8319 public override Expression CreateExpressionTree (ResolveContext ec)
8321 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
8322 return Expr.CreateExpressionTree (ec);
8325 protected override Expression DoResolve (ResolveContext ec)
8327 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
8328 Expr = Expr.Resolve (ec);
8333 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8336 eclass = Expr.eclass;
8341 public override void Emit (EmitContext ec)
8343 using (ec.With (EmitContext.Options.CheckedScope, true))
8347 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8349 using (ec.With (EmitContext.Options.CheckedScope, true))
8350 Expr.EmitBranchable (ec, target, on_true);
8353 public override SLE.Expression MakeExpression (BuilderContext ctx)
8355 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
8356 return Expr.MakeExpression (ctx);
8360 protected override void CloneTo (CloneContext clonectx, Expression t)
8362 CheckedExpr target = (CheckedExpr) t;
8364 target.Expr = Expr.Clone (clonectx);
8367 public override object Accept (StructuralVisitor visitor)
8369 return visitor.Visit (this);
8374 /// Implements the unchecked expression
8376 public class UnCheckedExpr : Expression {
8378 public Expression Expr;
8380 public UnCheckedExpr (Expression e, Location l)
8386 public override bool ContainsEmitWithAwait ()
8388 return Expr.ContainsEmitWithAwait ();
8391 public override Expression CreateExpressionTree (ResolveContext ec)
8393 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8394 return Expr.CreateExpressionTree (ec);
8397 protected override Expression DoResolve (ResolveContext ec)
8399 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8400 Expr = Expr.Resolve (ec);
8405 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8408 eclass = Expr.eclass;
8413 public override void Emit (EmitContext ec)
8415 using (ec.With (EmitContext.Options.CheckedScope, false))
8419 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8421 using (ec.With (EmitContext.Options.CheckedScope, false))
8422 Expr.EmitBranchable (ec, target, on_true);
8425 protected override void CloneTo (CloneContext clonectx, Expression t)
8427 UnCheckedExpr target = (UnCheckedExpr) t;
8429 target.Expr = Expr.Clone (clonectx);
8432 public override object Accept (StructuralVisitor visitor)
8434 return visitor.Visit (this);
8439 /// An Element Access expression.
8441 /// During semantic analysis these are transformed into
8442 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
8444 public class ElementAccess : Expression
8446 public Arguments Arguments;
8447 public Expression Expr;
8449 public ElementAccess (Expression e, Arguments args, Location loc)
8453 this.Arguments = args;
8456 public override bool ContainsEmitWithAwait ()
8458 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
8462 // We perform some simple tests, and then to "split" the emit and store
8463 // code we create an instance of a different class, and return that.
8465 Expression CreateAccessExpression (ResolveContext ec)
8468 return (new ArrayAccess (this, loc));
8471 return MakePointerAccess (ec, type);
8473 FieldExpr fe = Expr as FieldExpr;
8475 var ff = fe.Spec as FixedFieldSpec;
8477 return MakePointerAccess (ec, ff.ElementType);
8481 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
8482 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8483 return new IndexerExpr (indexers, type, this);
8486 if (type != InternalType.ErrorType) {
8487 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8488 type.GetSignatureForError ());
8494 public override Expression CreateExpressionTree (ResolveContext ec)
8496 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
8497 Expr.CreateExpressionTree (ec));
8499 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
8502 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
8504 if (Arguments.Count != 1){
8505 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
8509 if (Arguments [0] is NamedArgument)
8510 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
8512 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
8513 return new Indirection (p, loc);
8516 protected override Expression DoResolve (ResolveContext ec)
8518 Expr = Expr.Resolve (ec);
8524 // TODO: Create 1 result for Resolve and ResolveLValue ?
8525 var res = CreateAccessExpression (ec);
8529 return res.Resolve (ec);
8532 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
8534 Expr = Expr.Resolve (ec);
8540 var res = CreateAccessExpression (ec);
8544 return res.ResolveLValue (ec, rhs);
8547 public override void Emit (EmitContext ec)
8549 throw new Exception ("Should never be reached");
8552 public static void Error_NamedArgument (NamedArgument na, Report Report)
8554 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
8557 public override string GetSignatureForError ()
8559 return Expr.GetSignatureForError ();
8562 protected override void CloneTo (CloneContext clonectx, Expression t)
8564 ElementAccess target = (ElementAccess) t;
8566 target.Expr = Expr.Clone (clonectx);
8567 if (Arguments != null)
8568 target.Arguments = Arguments.Clone (clonectx);
8571 public override object Accept (StructuralVisitor visitor)
8573 return visitor.Visit (this);
8578 /// Implements array access
8580 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
8582 // Points to our "data" repository
8586 LocalTemporary temp;
8588 bool? has_await_args;
8590 public ArrayAccess (ElementAccess ea_data, Location l)
8596 public void AddressOf (EmitContext ec, AddressOp mode)
8598 var ac = (ArrayContainer) ea.Expr.Type;
8600 LoadInstanceAndArguments (ec, false, false);
8602 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
8603 ec.Emit (OpCodes.Readonly);
8605 ec.EmitArrayAddress (ac);
8608 public override Expression CreateExpressionTree (ResolveContext ec)
8610 return ea.CreateExpressionTree (ec);
8613 public override bool ContainsEmitWithAwait ()
8615 return ea.ContainsEmitWithAwait ();
8618 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8620 return DoResolve (ec);
8623 protected override Expression DoResolve (ResolveContext ec)
8625 // dynamic is used per argument in ConvertExpressionToArrayIndex case
8627 ea.Arguments.Resolve (ec, out dynamic);
8629 var ac = ea.Expr.Type as ArrayContainer;
8630 int rank = ea.Arguments.Count;
8631 if (ac.Rank != rank) {
8632 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8633 rank.ToString (), ac.Rank.ToString ());
8638 if (type.IsPointer && !ec.IsUnsafe) {
8639 UnsafeError (ec, ea.Location);
8642 foreach (Argument a in ea.Arguments) {
8643 if (a is NamedArgument)
8644 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
8646 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
8649 eclass = ExprClass.Variable;
8654 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8656 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8660 // Load the array arguments into the stack.
8662 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
8665 ea.Expr = ea.Expr.EmitToField (ec);
8666 } else if (duplicateArguments) {
8668 ec.Emit (OpCodes.Dup);
8670 var copy = new LocalTemporary (ea.Expr.Type);
8677 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
8678 if (dup_args != null)
8679 ea.Arguments = dup_args;
8682 public void Emit (EmitContext ec, bool leave_copy)
8684 var ac = ea.Expr.Type as ArrayContainer;
8687 ec.EmitLoadFromPtr (type);
8689 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
8690 LoadInstanceAndArguments (ec, false, true);
8693 LoadInstanceAndArguments (ec, false, false);
8694 ec.EmitArrayLoad (ac);
8698 ec.Emit (OpCodes.Dup);
8699 temp = new LocalTemporary (this.type);
8704 public override void Emit (EmitContext ec)
8709 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8711 var ac = (ArrayContainer) ea.Expr.Type;
8712 TypeSpec t = source.Type;
8714 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
8717 // When we are dealing with a struct, get the address of it to avoid value copy
8718 // Same cannot be done for reference type because array covariance and the
8719 // check in ldelema requires to specify the type of array element stored at the index
8721 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
8722 LoadInstanceAndArguments (ec, false, has_await_args.Value);
8724 if (has_await_args.Value) {
8725 if (source.ContainsEmitWithAwait ()) {
8726 source = source.EmitToField (ec);
8731 LoadInstanceAndArguments (ec, isCompound, false);
8736 ec.EmitArrayAddress (ac);
8739 ec.Emit (OpCodes.Dup);
8743 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
8745 if (has_await_args.Value) {
8746 if (source.ContainsEmitWithAwait ())
8747 source = source.EmitToField (ec);
8749 LoadInstanceAndArguments (ec, false, false);
8756 var lt = ea.Expr as LocalTemporary;
8762 ec.Emit (OpCodes.Dup);
8763 temp = new LocalTemporary (this.type);
8768 ec.EmitStoreFromPtr (t);
8770 ec.EmitArrayStore (ac);
8779 public override Expression EmitToField (EmitContext ec)
8782 // Have to be specialized for arrays to get access to
8783 // underlying element. Instead of another result copy we
8784 // need direct access to element
8788 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
8790 ea.Expr = ea.Expr.EmitToField (ec);
8794 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8796 #if NET_4_0 || MONODROID
8797 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8799 throw new NotImplementedException ();
8803 public override SLE.Expression MakeExpression (BuilderContext ctx)
8805 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8808 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
8810 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
8811 return Arguments.MakeExpression (ea.Arguments, ctx);
8817 // Indexer access expression
8819 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
8821 IList<MemberSpec> indexers;
8822 Arguments arguments;
8823 TypeSpec queried_type;
8825 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
8826 : base (ea.Location)
8828 this.indexers = indexers;
8829 this.queried_type = queriedType;
8830 this.InstanceExpression = ea.Expr;
8831 this.arguments = ea.Arguments;
8836 protected override Arguments Arguments {
8845 protected override TypeSpec DeclaringType {
8847 return best_candidate.DeclaringType;
8851 public override bool IsInstance {
8857 public override bool IsStatic {
8863 public override string KindName {
8864 get { return "indexer"; }
8867 public override string Name {
8875 public override bool ContainsEmitWithAwait ()
8877 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
8880 public override Expression CreateExpressionTree (ResolveContext ec)
8882 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8883 InstanceExpression.CreateExpressionTree (ec),
8884 new TypeOfMethod (Getter, loc));
8886 return CreateExpressionFactoryCall (ec, "Call", args);
8889 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8891 LocalTemporary await_source_arg = null;
8894 emitting_compound_assignment = true;
8895 if (source is DynamicExpressionStatement) {
8900 emitting_compound_assignment = false;
8902 if (has_await_arguments) {
8903 await_source_arg = new LocalTemporary (Type);
8904 await_source_arg.Store (ec);
8906 arguments.Add (new Argument (await_source_arg));
8909 temp = await_source_arg;
8912 has_await_arguments = false;
8917 ec.Emit (OpCodes.Dup);
8918 temp = new LocalTemporary (Type);
8924 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
8925 source = source.EmitToField (ec);
8927 temp = new LocalTemporary (Type);
8934 arguments.Add (new Argument (source));
8937 var call = new CallEmitter ();
8938 call.InstanceExpression = InstanceExpression;
8939 if (arguments == null)
8940 call.InstanceExpressionOnStack = true;
8942 call.Emit (ec, Setter, arguments, loc);
8947 } else if (leave_copy) {
8951 if (await_source_arg != null) {
8952 await_source_arg.Release (ec);
8956 public override string GetSignatureForError ()
8958 return best_candidate.GetSignatureForError ();
8961 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8964 throw new NotSupportedException ();
8966 var value = new[] { source.MakeExpression (ctx) };
8967 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
8968 #if NET_4_0 || MONODROID
8969 return SLE.Expression.Block (
8970 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
8973 return args.First ();
8978 public override SLE.Expression MakeExpression (BuilderContext ctx)
8981 return base.MakeExpression (ctx);
8983 var args = Arguments.MakeExpression (arguments, ctx);
8984 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
8988 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
8990 if (best_candidate != null)
8993 eclass = ExprClass.IndexerAccess;
8996 arguments.Resolve (rc, out dynamic);
8998 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9001 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9002 res.BaseMembersProvider = this;
9003 res.InstanceQualifier = this;
9005 // TODO: Do I need 2 argument sets?
9006 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9007 if (best_candidate != null)
9008 type = res.BestCandidateReturnType;
9009 else if (!res.BestCandidateIsDynamic)
9014 // It has dynamic arguments
9017 Arguments args = new Arguments (arguments.Count + 1);
9019 rc.Report.Error (1972, loc,
9020 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9022 args.Add (new Argument (InstanceExpression));
9024 args.AddRange (arguments);
9026 best_candidate = null;
9027 return new DynamicIndexBinder (args, loc);
9031 // Try to avoid resolving left expression again
9033 if (right_side != null)
9034 ResolveInstanceExpression (rc, right_side);
9039 protected override void CloneTo (CloneContext clonectx, Expression t)
9041 IndexerExpr target = (IndexerExpr) t;
9043 if (arguments != null)
9044 target.arguments = arguments.Clone (clonectx);
9047 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9049 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9052 #region IBaseMembersProvider Members
9054 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9056 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9059 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9061 if (queried_type == member.DeclaringType)
9064 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9065 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9068 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9077 // A base access expression
9079 public class BaseThis : This
9081 public BaseThis (Location loc)
9086 public BaseThis (TypeSpec type, Location loc)
9090 eclass = ExprClass.Variable;
9095 public override string Name {
9103 public override Expression CreateExpressionTree (ResolveContext ec)
9105 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9106 return base.CreateExpressionTree (ec);
9109 public override void Emit (EmitContext ec)
9113 var context_type = ec.CurrentType;
9114 if (context_type.IsStruct) {
9115 ec.Emit (OpCodes.Ldobj, context_type);
9116 ec.Emit (OpCodes.Box, context_type);
9120 protected override void Error_ThisNotAvailable (ResolveContext ec)
9123 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9125 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9129 public override void ResolveBase (ResolveContext ec)
9131 base.ResolveBase (ec);
9132 type = ec.CurrentType.BaseType;
9135 public override object Accept (StructuralVisitor visitor)
9137 return visitor.Visit (this);
9142 /// This class exists solely to pass the Type around and to be a dummy
9143 /// that can be passed to the conversion functions (this is used by
9144 /// foreach implementation to typecast the object return value from
9145 /// get_Current into the proper type. All code has been generated and
9146 /// we only care about the side effect conversions to be performed
9148 /// This is also now used as a placeholder where a no-action expression
9149 /// is needed (the `New' class).
9151 public class EmptyExpression : Expression
9153 sealed class OutAccessExpression : EmptyExpression
9155 public OutAccessExpression (TypeSpec t)
9160 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9162 rc.Report.Error (206, right_side.Location,
9163 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
9169 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
9170 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
9171 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
9172 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
9173 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
9174 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
9175 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
9176 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
9178 public EmptyExpression (TypeSpec t)
9181 eclass = ExprClass.Value;
9182 loc = Location.Null;
9185 public override bool ContainsEmitWithAwait ()
9190 public override Expression CreateExpressionTree (ResolveContext ec)
9192 throw new NotSupportedException ("ET");
9195 protected override Expression DoResolve (ResolveContext ec)
9200 public override void Emit (EmitContext ec)
9202 // nothing, as we only exist to not do anything.
9205 public override void EmitSideEffect (EmitContext ec)
9209 public override object Accept (StructuralVisitor visitor)
9211 return visitor.Visit (this);
9215 sealed class EmptyAwaitExpression : EmptyExpression
9217 public EmptyAwaitExpression (TypeSpec type)
9222 public override bool ContainsEmitWithAwait ()
9229 // Empty statement expression
9231 public sealed class EmptyExpressionStatement : ExpressionStatement
9233 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
9235 private EmptyExpressionStatement ()
9237 loc = Location.Null;
9240 public override bool ContainsEmitWithAwait ()
9245 public override Expression CreateExpressionTree (ResolveContext ec)
9250 public override void EmitStatement (EmitContext ec)
9255 protected override Expression DoResolve (ResolveContext ec)
9257 eclass = ExprClass.Value;
9258 type = ec.BuiltinTypes.Object;
9262 public override void Emit (EmitContext ec)
9267 public override object Accept (StructuralVisitor visitor)
9269 return visitor.Visit (this);
9273 public class ErrorExpression : EmptyExpression
9275 public static readonly ErrorExpression Instance = new ErrorExpression ();
9277 private ErrorExpression ()
9278 : base (InternalType.ErrorType)
9282 public override Expression CreateExpressionTree (ResolveContext ec)
9287 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9292 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
9296 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
9300 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
9304 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
9308 public override object Accept (StructuralVisitor visitor)
9310 return visitor.Visit (this);
9314 public class UserCast : Expression {
9318 public UserCast (MethodSpec method, Expression source, Location l)
9321 throw new ArgumentNullException ("source");
9323 this.method = method;
9324 this.source = source;
9325 type = method.ReturnType;
9329 public Expression Source {
9335 public override bool ContainsEmitWithAwait ()
9337 return source.ContainsEmitWithAwait ();
9340 public override Expression CreateExpressionTree (ResolveContext ec)
9342 Arguments args = new Arguments (3);
9343 args.Add (new Argument (source.CreateExpressionTree (ec)));
9344 args.Add (new Argument (new TypeOf (type, loc)));
9345 args.Add (new Argument (new TypeOfMethod (method, loc)));
9346 return CreateExpressionFactoryCall (ec, "Convert", args);
9349 protected override Expression DoResolve (ResolveContext ec)
9351 ObsoleteAttribute oa = method.GetAttributeObsolete ();
9353 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
9355 eclass = ExprClass.Value;
9359 public override void Emit (EmitContext ec)
9362 ec.Emit (OpCodes.Call, method);
9365 public override string GetSignatureForError ()
9367 return TypeManager.CSharpSignature (method);
9370 public override SLE.Expression MakeExpression (BuilderContext ctx)
9373 return base.MakeExpression (ctx);
9375 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
9381 // Holds additional type specifiers like ?, *, []
9383 public class ComposedTypeSpecifier
9385 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
9387 public readonly int Dimension;
9388 public readonly Location Location;
9390 public ComposedTypeSpecifier (int specifier, Location loc)
9392 this.Dimension = specifier;
9393 this.Location = loc;
9397 public bool IsNullable {
9399 return Dimension == -1;
9403 public bool IsPointer {
9405 return Dimension == -2;
9409 public ComposedTypeSpecifier Next { get; set; }
9413 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
9415 return new ComposedTypeSpecifier (dimension, loc);
9418 public static ComposedTypeSpecifier CreateNullable (Location loc)
9420 return new ComposedTypeSpecifier (-1, loc);
9423 public static ComposedTypeSpecifier CreatePointer (Location loc)
9425 return new ComposedTypeSpecifier (-2, loc);
9428 public string GetSignatureForError ()
9433 ArrayContainer.GetPostfixSignature (Dimension);
9435 return Next != null ? s + Next.GetSignatureForError () : s;
9440 // This class is used to "construct" the type during a typecast
9441 // operation. Since the Type.GetType class in .NET can parse
9442 // the type specification, we just use this to construct the type
9443 // one bit at a time.
9445 public class ComposedCast : TypeExpr {
9446 FullNamedExpression left;
9447 ComposedTypeSpecifier spec;
9449 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
9452 throw new ArgumentNullException ("spec");
9456 this.loc = left.Location;
9459 public override TypeSpec ResolveAsType (IMemberContext ec)
9461 type = left.ResolveAsType (ec);
9465 eclass = ExprClass.Type;
9467 var single_spec = spec;
9469 if (single_spec.IsNullable) {
9470 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
9474 single_spec = single_spec.Next;
9475 } else if (single_spec.IsPointer) {
9476 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
9480 UnsafeError (ec.Module.Compiler.Report, loc);
9484 type = PointerContainer.MakeType (ec.Module, type);
9485 single_spec = single_spec.Next;
9486 } while (single_spec != null && single_spec.IsPointer);
9489 if (single_spec != null && single_spec.Dimension > 0) {
9490 if (type.IsSpecialRuntimeType) {
9491 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
9492 } else if (type.IsStatic) {
9493 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
9494 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9495 type.GetSignatureForError ());
9497 MakeArray (ec.Module, single_spec);
9504 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
9506 if (spec.Next != null)
9507 MakeArray (module, spec.Next);
9509 type = ArrayContainer.MakeType (module, type, spec.Dimension);
9512 public override string GetSignatureForError ()
9514 return left.GetSignatureForError () + spec.GetSignatureForError ();
9517 public override object Accept (StructuralVisitor visitor)
9519 return visitor.Visit (this);
9523 class FixedBufferPtr : Expression
9525 readonly Expression array;
9527 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
9529 this.type = array_type;
9534 public override bool ContainsEmitWithAwait ()
9536 throw new NotImplementedException ();
9539 public override Expression CreateExpressionTree (ResolveContext ec)
9541 Error_PointerInsideExpressionTree (ec);
9545 public override void Emit(EmitContext ec)
9550 protected override Expression DoResolve (ResolveContext ec)
9552 type = PointerContainer.MakeType (ec.Module, type);
9553 eclass = ExprClass.Value;
9560 // This class is used to represent the address of an array, used
9561 // only by the Fixed statement, this generates "&a [0]" construct
9562 // for fixed (char *pa = a)
9564 class ArrayPtr : FixedBufferPtr
9566 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
9567 base (array, array_type, l)
9571 public override void Emit (EmitContext ec)
9576 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
9581 // Encapsulates a conversion rules required for array indexes
9583 public class ArrayIndexCast : TypeCast
9585 public ArrayIndexCast (Expression expr, TypeSpec returnType)
9586 : base (expr, returnType)
9588 if (expr.Type == returnType) // int -> int
9589 throw new ArgumentException ("unnecessary array index conversion");
9592 public override Expression CreateExpressionTree (ResolveContext ec)
9594 using (ec.Set (ResolveContext.Options.CheckedScope)) {
9595 return base.CreateExpressionTree (ec);
9599 public override void Emit (EmitContext ec)
9603 switch (child.Type.BuiltinType) {
9604 case BuiltinTypeSpec.Type.UInt:
9605 ec.Emit (OpCodes.Conv_U);
9607 case BuiltinTypeSpec.Type.Long:
9608 ec.Emit (OpCodes.Conv_Ovf_I);
9610 case BuiltinTypeSpec.Type.ULong:
9611 ec.Emit (OpCodes.Conv_Ovf_I_Un);
9614 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9620 // Implements the `stackalloc' keyword
9622 public class StackAlloc : Expression {
9627 public StackAlloc (Expression type, Expression count, Location l)
9634 public Expression TypeExpression {
9640 public Expression CountExpression {
9646 public override bool ContainsEmitWithAwait ()
9651 public override Expression CreateExpressionTree (ResolveContext ec)
9653 throw new NotSupportedException ("ET");
9656 protected override Expression DoResolve (ResolveContext ec)
9658 count = count.Resolve (ec);
9662 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
9663 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
9668 Constant c = count as Constant;
9669 if (c != null && c.IsNegative) {
9670 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9673 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9674 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9677 otype = t.ResolveAsType (ec);
9681 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
9684 type = PointerContainer.MakeType (ec.Module, otype);
9685 eclass = ExprClass.Value;
9690 public override void Emit (EmitContext ec)
9692 int size = BuiltinTypeSpec.GetSize (otype);
9697 ec.Emit (OpCodes.Sizeof, otype);
9701 ec.Emit (OpCodes.Mul_Ovf_Un);
9702 ec.Emit (OpCodes.Localloc);
9705 protected override void CloneTo (CloneContext clonectx, Expression t)
9707 StackAlloc target = (StackAlloc) t;
9708 target.count = count.Clone (clonectx);
9709 target.t = t.Clone (clonectx);
9712 public override object Accept (StructuralVisitor visitor)
9714 return visitor.Visit (this);
9719 // An object initializer expression
9721 public class ElementInitializer : Assign
9723 public readonly string Name;
9725 public ElementInitializer (string name, Expression initializer, Location loc)
9726 : base (null, initializer, loc)
9731 protected override void CloneTo (CloneContext clonectx, Expression t)
9733 ElementInitializer target = (ElementInitializer) t;
9734 target.source = source.Clone (clonectx);
9737 public override Expression CreateExpressionTree (ResolveContext ec)
9739 Arguments args = new Arguments (2);
9740 FieldExpr fe = target as FieldExpr;
9742 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9744 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
9747 Expression arg_expr;
9748 var cinit = source as CollectionOrObjectInitializers;
9749 if (cinit == null) {
9751 arg_expr = source.CreateExpressionTree (ec);
9753 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
9754 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
9757 args.Add (new Argument (arg_expr));
9758 return CreateExpressionFactoryCall (ec, mname, args);
9761 protected override Expression DoResolve (ResolveContext ec)
9764 return EmptyExpressionStatement.Instance;
9766 var t = ec.CurrentInitializerVariable.Type;
9767 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9768 Arguments args = new Arguments (1);
9769 args.Add (new Argument (ec.CurrentInitializerVariable));
9770 target = new DynamicMemberBinder (Name, args, loc);
9773 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9774 if (member == null) {
9775 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9777 if (member != null) {
9778 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
9779 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
9784 if (member == null) {
9785 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
9789 if (!(member is PropertyExpr || member is FieldExpr)) {
9790 ec.Report.Error (1913, loc,
9791 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
9792 member.GetSignatureForError ());
9797 var me = member as MemberExpr;
9799 ec.Report.Error (1914, loc,
9800 "Static field or property `{0}' cannot be assigned in an object initializer",
9801 me.GetSignatureForError ());
9805 me.InstanceExpression = ec.CurrentInitializerVariable;
9808 if (source is CollectionOrObjectInitializers) {
9809 Expression previous = ec.CurrentInitializerVariable;
9810 ec.CurrentInitializerVariable = target;
9811 source = source.Resolve (ec);
9812 ec.CurrentInitializerVariable = previous;
9816 eclass = source.eclass;
9821 return base.DoResolve (ec);
9824 public override void EmitStatement (EmitContext ec)
9826 if (source is CollectionOrObjectInitializers)
9829 base.EmitStatement (ec);
9834 // A collection initializer expression
9836 class CollectionElementInitializer : Invocation
9838 public class ElementInitializerArgument : Argument
9840 public ElementInitializerArgument (Expression e)
9846 sealed class AddMemberAccess : MemberAccess
9848 public AddMemberAccess (Expression expr, Location loc)
9849 : base (expr, "Add", loc)
9853 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9855 if (TypeManager.HasElementType (type))
9858 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9862 public CollectionElementInitializer (Expression argument)
9863 : base (null, new Arguments (1))
9865 base.arguments.Add (new ElementInitializerArgument (argument));
9866 this.loc = argument.Location;
9869 public CollectionElementInitializer (List<Expression> arguments, Location loc)
9870 : base (null, new Arguments (arguments.Count))
9872 foreach (Expression e in arguments)
9873 base.arguments.Add (new ElementInitializerArgument (e));
9878 public override Expression CreateExpressionTree (ResolveContext ec)
9880 Arguments args = new Arguments (2);
9881 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9883 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
9884 foreach (Argument a in arguments)
9885 expr_initializers.Add (a.CreateExpressionTree (ec));
9887 args.Add (new Argument (new ArrayCreation (
9888 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
9889 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9892 protected override void CloneTo (CloneContext clonectx, Expression t)
9894 CollectionElementInitializer target = (CollectionElementInitializer) t;
9895 if (arguments != null)
9896 target.arguments = arguments.Clone (clonectx);
9899 protected override Expression DoResolve (ResolveContext ec)
9901 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9903 return base.DoResolve (ec);
9908 // A block of object or collection initializers
9910 public class CollectionOrObjectInitializers : ExpressionStatement
9912 IList<Expression> initializers;
9913 bool is_collection_initialization;
9915 public CollectionOrObjectInitializers (Location loc)
9916 : this (new Expression[0], loc)
9920 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
9922 this.initializers = initializers;
9926 public IList<Expression> Initializers {
9928 return initializers;
9932 public bool IsEmpty {
9934 return initializers.Count == 0;
9938 public bool IsCollectionInitializer {
9940 return is_collection_initialization;
9944 protected override void CloneTo (CloneContext clonectx, Expression target)
9946 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9948 t.initializers = new List<Expression> (initializers.Count);
9949 foreach (var e in initializers)
9950 t.initializers.Add (e.Clone (clonectx));
9953 public override bool ContainsEmitWithAwait ()
9955 foreach (var e in initializers) {
9956 if (e.ContainsEmitWithAwait ())
9963 public override Expression CreateExpressionTree (ResolveContext ec)
9965 return CreateExpressionTree (ec, false);
9968 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
9970 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
9971 foreach (Expression e in initializers) {
9972 Expression expr = e.CreateExpressionTree (ec);
9974 expr_initializers.Add (expr);
9978 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
9980 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
9983 protected override Expression DoResolve (ResolveContext ec)
9985 List<string> element_names = null;
9986 for (int i = 0; i < initializers.Count; ++i) {
9987 Expression initializer = initializers [i];
9988 ElementInitializer element_initializer = initializer as ElementInitializer;
9991 if (element_initializer != null) {
9992 element_names = new List<string> (initializers.Count);
9993 element_names.Add (element_initializer.Name);
9994 } else if (initializer is CompletingExpression){
9995 initializer.Resolve (ec);
9996 throw new InternalErrorException ("This line should never be reached");
9998 var t = ec.CurrentInitializerVariable.Type;
9999 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10000 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10001 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10002 "object initializer because type `{1}' does not implement `{2}' interface",
10003 ec.CurrentInitializerVariable.GetSignatureForError (),
10004 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
10005 TypeManager.CSharpName (ec.BuiltinTypes.IEnumerable));
10008 is_collection_initialization = true;
10011 if (is_collection_initialization != (element_initializer == null)) {
10012 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10013 is_collection_initialization ? "collection initializer" : "object initializer");
10017 if (!is_collection_initialization) {
10018 if (element_names.Contains (element_initializer.Name)) {
10019 ec.Report.Error (1912, element_initializer.Location,
10020 "An object initializer includes more than one member `{0}' initialization",
10021 element_initializer.Name);
10023 element_names.Add (element_initializer.Name);
10028 Expression e = initializer.Resolve (ec);
10029 if (e == EmptyExpressionStatement.Instance)
10030 initializers.RemoveAt (i--);
10032 initializers [i] = e;
10035 type = ec.CurrentInitializerVariable.Type;
10036 if (is_collection_initialization) {
10037 if (TypeManager.HasElementType (type)) {
10038 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10039 TypeManager.CSharpName (type));
10043 eclass = ExprClass.Variable;
10047 public override void Emit (EmitContext ec)
10049 EmitStatement (ec);
10052 public override void EmitStatement (EmitContext ec)
10054 foreach (ExpressionStatement e in initializers) {
10055 // TODO: need location region
10056 ec.Mark (e.Location);
10057 e.EmitStatement (ec);
10063 // New expression with element/object initializers
10065 public class NewInitialize : New
10068 // This class serves as a proxy for variable initializer target instances.
10069 // A real variable is assigned later when we resolve left side of an
10072 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10074 NewInitialize new_instance;
10076 public InitializerTargetExpression (NewInitialize newInstance)
10078 this.type = newInstance.type;
10079 this.loc = newInstance.loc;
10080 this.eclass = newInstance.eclass;
10081 this.new_instance = newInstance;
10084 public override bool ContainsEmitWithAwait ()
10089 public override Expression CreateExpressionTree (ResolveContext ec)
10091 // Should not be reached
10092 throw new NotSupportedException ("ET");
10095 protected override Expression DoResolve (ResolveContext ec)
10100 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10105 public override void Emit (EmitContext ec)
10107 Expression e = (Expression) new_instance.instance;
10111 public override Expression EmitToField (EmitContext ec)
10113 return (Expression) new_instance.instance;
10116 #region IMemoryLocation Members
10118 public void AddressOf (EmitContext ec, AddressOp mode)
10120 new_instance.instance.AddressOf (ec, mode);
10126 CollectionOrObjectInitializers initializers;
10127 IMemoryLocation instance;
10128 DynamicExpressionStatement dynamic;
10130 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10131 : base (requested_type, arguments, l)
10133 this.initializers = initializers;
10136 public CollectionOrObjectInitializers Initializers {
10138 return initializers;
10142 protected override void CloneTo (CloneContext clonectx, Expression t)
10144 base.CloneTo (clonectx, t);
10146 NewInitialize target = (NewInitialize) t;
10147 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
10150 public override bool ContainsEmitWithAwait ()
10152 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
10155 public override Expression CreateExpressionTree (ResolveContext ec)
10157 Arguments args = new Arguments (2);
10158 args.Add (new Argument (base.CreateExpressionTree (ec)));
10159 if (!initializers.IsEmpty)
10160 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
10162 return CreateExpressionFactoryCall (ec,
10163 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
10167 protected override Expression DoResolve (ResolveContext ec)
10169 Expression e = base.DoResolve (ec);
10173 if (type.IsDelegate) {
10174 ec.Report.Error (1958, Initializers.Location,
10175 "Object and collection initializers cannot be used to instantiate a delegate");
10178 Expression previous = ec.CurrentInitializerVariable;
10179 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
10180 initializers.Resolve (ec);
10181 ec.CurrentInitializerVariable = previous;
10183 dynamic = e as DynamicExpressionStatement;
10184 if (dynamic != null)
10190 public override bool Emit (EmitContext ec, IMemoryLocation target)
10192 bool left_on_stack;
10193 if (dynamic != null) {
10195 left_on_stack = true;
10197 left_on_stack = base.Emit (ec, target);
10200 if (initializers.IsEmpty)
10201 return left_on_stack;
10203 LocalTemporary temp = null;
10205 instance = target as LocalTemporary;
10207 if (instance == null) {
10208 if (!left_on_stack) {
10209 VariableReference vr = target as VariableReference;
10211 // FIXME: This still does not work correctly for pre-set variables
10212 if (vr != null && vr.IsRef)
10213 target.AddressOf (ec, AddressOp.Load);
10215 ((Expression) target).Emit (ec);
10216 left_on_stack = true;
10219 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
10220 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
10222 temp = new LocalTemporary (type);
10227 if (left_on_stack && temp != null)
10230 initializers.Emit (ec);
10232 if (left_on_stack) {
10233 if (temp != null) {
10237 ((Expression) instance).Emit (ec);
10241 return left_on_stack;
10244 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
10246 instance = base.EmitAddressOf (ec, Mode);
10248 if (!initializers.IsEmpty)
10249 initializers.Emit (ec);
10254 public override object Accept (StructuralVisitor visitor)
10256 return visitor.Visit (this);
10260 public class NewAnonymousType : New
10262 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
10264 List<AnonymousTypeParameter> parameters;
10265 readonly TypeContainer parent;
10266 AnonymousTypeClass anonymous_type;
10268 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
10269 : base (null, null, loc)
10271 this.parameters = parameters;
10272 this.parent = parent;
10275 public List<AnonymousTypeParameter> Parameters {
10277 return this.parameters;
10281 protected override void CloneTo (CloneContext clonectx, Expression target)
10283 if (parameters == null)
10286 NewAnonymousType t = (NewAnonymousType) target;
10287 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
10288 foreach (AnonymousTypeParameter atp in parameters)
10289 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
10292 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
10294 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
10298 type = AnonymousTypeClass.Create (parent, parameters, loc);
10302 int errors = ec.Report.Errors;
10303 type.CreateContainer ();
10304 type.DefineContainer ();
10306 if ((ec.Report.Errors - errors) == 0) {
10307 parent.Module.AddAnonymousType (type);
10313 public override Expression CreateExpressionTree (ResolveContext ec)
10315 if (parameters == null)
10316 return base.CreateExpressionTree (ec);
10318 var init = new ArrayInitializer (parameters.Count, loc);
10319 foreach (var m in anonymous_type.Members) {
10320 var p = m as Property;
10322 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
10325 var ctor_args = new ArrayInitializer (arguments.Count, loc);
10326 foreach (Argument a in arguments)
10327 ctor_args.Add (a.CreateExpressionTree (ec));
10329 Arguments args = new Arguments (3);
10330 args.Add (new Argument (new TypeOfMethod (method, loc)));
10331 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
10332 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
10334 return CreateExpressionFactoryCall (ec, "New", args);
10337 protected override Expression DoResolve (ResolveContext ec)
10339 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
10340 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
10344 if (parameters == null) {
10345 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
10346 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
10347 return base.DoResolve (ec);
10350 bool error = false;
10351 arguments = new Arguments (parameters.Count);
10352 var t_args = new TypeSpec [parameters.Count];
10353 for (int i = 0; i < parameters.Count; ++i) {
10354 Expression e = parameters [i].Resolve (ec);
10360 arguments.Add (new Argument (e));
10361 t_args [i] = e.Type;
10367 anonymous_type = CreateAnonymousType (ec, parameters);
10368 if (anonymous_type == null)
10371 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
10372 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
10373 eclass = ExprClass.Value;
10377 public override void EmitStatement (EmitContext ec)
10379 base.EmitStatement (ec);
10382 public override object Accept (StructuralVisitor visitor)
10384 return visitor.Visit (this);
10388 public class AnonymousTypeParameter : ShimExpression
10390 public readonly string Name;
10392 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
10393 : base (initializer)
10399 public AnonymousTypeParameter (Parameter parameter)
10400 : base (new SimpleName (parameter.Name, parameter.Location))
10402 this.Name = parameter.Name;
10403 this.loc = parameter.Location;
10406 public override bool Equals (object o)
10408 AnonymousTypeParameter other = o as AnonymousTypeParameter;
10409 return other != null && Name == other.Name;
10412 public override int GetHashCode ()
10414 return Name.GetHashCode ();
10417 protected override Expression DoResolve (ResolveContext ec)
10419 Expression e = expr.Resolve (ec);
10423 if (e.eclass == ExprClass.MethodGroup) {
10424 Error_InvalidInitializer (ec, e.ExprClassName);
10429 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
10430 Error_InvalidInitializer (ec, type.GetSignatureForError ());
10437 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
10439 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
10440 Name, initializer);