2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
19 using MetaType = IKVM.Reflection.Type;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
23 using MetaType = System.Type;
24 using System.Reflection;
25 using System.Reflection.Emit;
31 // This is an user operator expression, automatically created during
34 public class UserOperatorCall : Expression {
35 protected readonly Arguments arguments;
36 protected readonly MethodSpec oper;
37 readonly Func<ResolveContext, Expression, Expression> expr_tree;
39 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
42 this.arguments = args;
43 this.expr_tree = expr_tree;
45 type = oper.ReturnType;
46 eclass = ExprClass.Value;
50 public override bool ContainsEmitWithAwait ()
52 return arguments.ContainsEmitWithAwait ();
55 public override Expression CreateExpressionTree (ResolveContext ec)
57 if (expr_tree != null)
58 return expr_tree (ec, new TypeOfMethod (oper, loc));
60 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
61 new NullLiteral (loc),
62 new TypeOfMethod (oper, loc));
64 return CreateExpressionFactoryCall (ec, "Call", args);
67 protected override void CloneTo (CloneContext context, Expression target)
72 protected override Expression DoResolve (ResolveContext ec)
75 // We are born fully resolved
80 public override void Emit (EmitContext ec)
82 var call = new CallEmitter ();
83 call.EmitPredefined (ec, oper, arguments);
86 public override SLE.Expression MakeExpression (BuilderContext ctx)
89 return base.MakeExpression (ctx);
91 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
96 public class ParenthesizedExpression : ShimExpression
98 public ParenthesizedExpression (Expression expr, Location loc)
104 protected override Expression DoResolve (ResolveContext ec)
106 var res = expr.Resolve (ec);
107 var constant = res as Constant;
108 if (constant != null && constant.IsLiteral)
109 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
114 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
116 return expr.DoResolveLValue (ec, right_side);
119 public override object Accept (StructuralVisitor visitor)
121 return visitor.Visit (this);
126 // Unary implements unary expressions.
128 public class Unary : Expression
130 public enum Operator : byte {
131 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
135 public readonly Operator Oper;
136 public Expression Expr;
137 Expression enum_conversion;
139 public Unary (Operator op, Expression expr, Location loc)
147 // This routine will attempt to simplify the unary expression when the
148 // argument is a constant.
150 Constant TryReduceConstant (ResolveContext ec, Constant constant)
154 while (e is EmptyConstantCast)
155 e = ((EmptyConstantCast) e).child;
157 if (e is SideEffectConstant) {
158 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
159 return r == null ? null : new SideEffectConstant (r, e, r.Location);
162 TypeSpec expr_type = e.Type;
165 case Operator.UnaryPlus:
166 // Unary numeric promotions
167 switch (expr_type.BuiltinType) {
168 case BuiltinTypeSpec.Type.Byte:
169 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
170 case BuiltinTypeSpec.Type.SByte:
171 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
172 case BuiltinTypeSpec.Type.Short:
173 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
174 case BuiltinTypeSpec.Type.UShort:
175 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
176 case BuiltinTypeSpec.Type.Char:
177 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
179 // Predefined operators
180 case BuiltinTypeSpec.Type.Int:
181 case BuiltinTypeSpec.Type.UInt:
182 case BuiltinTypeSpec.Type.Long:
183 case BuiltinTypeSpec.Type.ULong:
184 case BuiltinTypeSpec.Type.Float:
185 case BuiltinTypeSpec.Type.Double:
186 case BuiltinTypeSpec.Type.Decimal:
192 case Operator.UnaryNegation:
193 // Unary numeric promotions
194 switch (expr_type.BuiltinType) {
195 case BuiltinTypeSpec.Type.Byte:
196 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
197 case BuiltinTypeSpec.Type.SByte:
198 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
199 case BuiltinTypeSpec.Type.Short:
200 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
201 case BuiltinTypeSpec.Type.UShort:
202 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
203 case BuiltinTypeSpec.Type.Char:
204 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
206 // Predefined operators
207 case BuiltinTypeSpec.Type.Int:
208 int ivalue = ((IntConstant) e).Value;
209 if (ivalue == int.MinValue) {
210 if (ec.ConstantCheckState) {
211 ConstantFold.Error_CompileTimeOverflow (ec, loc);
216 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
218 case BuiltinTypeSpec.Type.Long:
219 long lvalue = ((LongConstant) e).Value;
220 if (lvalue == long.MinValue) {
221 if (ec.ConstantCheckState) {
222 ConstantFold.Error_CompileTimeOverflow (ec, loc);
227 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
229 case BuiltinTypeSpec.Type.UInt:
230 UIntLiteral uil = constant as UIntLiteral;
232 if (uil.Value == int.MaxValue + (uint) 1)
233 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
234 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
236 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
239 case BuiltinTypeSpec.Type.ULong:
240 ULongLiteral ull = constant as ULongLiteral;
241 if (ull != null && ull.Value == 9223372036854775808)
242 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
245 case BuiltinTypeSpec.Type.Float:
246 FloatLiteral fl = constant as FloatLiteral;
247 // For better error reporting
249 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
251 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
253 case BuiltinTypeSpec.Type.Double:
254 DoubleLiteral dl = constant as DoubleLiteral;
255 // For better error reporting
257 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
259 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
261 case BuiltinTypeSpec.Type.Decimal:
262 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
267 case Operator.LogicalNot:
268 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
271 bool b = (bool)e.GetValue ();
272 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
274 case Operator.OnesComplement:
275 // Unary numeric promotions
276 switch (expr_type.BuiltinType) {
277 case BuiltinTypeSpec.Type.Byte:
278 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
279 case BuiltinTypeSpec.Type.SByte:
280 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
281 case BuiltinTypeSpec.Type.Short:
282 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
283 case BuiltinTypeSpec.Type.UShort:
284 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
285 case BuiltinTypeSpec.Type.Char:
286 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
288 // Predefined operators
289 case BuiltinTypeSpec.Type.Int:
290 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
291 case BuiltinTypeSpec.Type.UInt:
292 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
293 case BuiltinTypeSpec.Type.Long:
294 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
295 case BuiltinTypeSpec.Type.ULong:
296 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
298 if (e is EnumConstant) {
299 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
301 e = new EnumConstant (e, expr_type);
306 throw new Exception ("Can not constant fold: " + Oper.ToString());
309 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
311 eclass = ExprClass.Value;
313 TypeSpec expr_type = expr.Type;
314 Expression best_expr;
316 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
319 // Primitive types first
321 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
322 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
323 if (best_expr == null)
326 type = best_expr.Type;
332 // E operator ~(E x);
334 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
335 return ResolveEnumOperator (ec, expr, predefined);
337 return ResolveUserType (ec, expr, predefined);
340 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
342 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
343 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
344 if (best_expr == null)
348 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (best_expr.Type), underlying_type);
350 return EmptyCast.Create (this, type);
353 public override bool ContainsEmitWithAwait ()
355 return Expr.ContainsEmitWithAwait ();
358 public override Expression CreateExpressionTree (ResolveContext ec)
360 return CreateExpressionTree (ec, null);
363 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
367 case Operator.AddressOf:
368 Error_PointerInsideExpressionTree (ec);
370 case Operator.UnaryNegation:
371 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
372 method_name = "NegateChecked";
374 method_name = "Negate";
376 case Operator.OnesComplement:
377 case Operator.LogicalNot:
380 case Operator.UnaryPlus:
381 method_name = "UnaryPlus";
384 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
387 Arguments args = new Arguments (2);
388 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
390 args.Add (new Argument (user_op));
392 return CreateExpressionFactoryCall (ec, method_name, args);
395 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
397 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
400 // 7.6.1 Unary plus operator
402 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
403 types.Int, types.UInt,
404 types.Long, types.ULong,
405 types.Float, types.Double,
410 // 7.6.2 Unary minus operator
412 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
413 types.Int, types.Long,
414 types.Float, types.Double,
419 // 7.6.3 Logical negation operator
421 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
426 // 7.6.4 Bitwise complement operator
428 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
429 types.Int, types.UInt,
430 types.Long, types.ULong
433 return predefined_operators;
437 // Unary numeric promotions
439 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
441 TypeSpec expr_type = expr.Type;
442 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
443 switch (expr_type.BuiltinType) {
444 case BuiltinTypeSpec.Type.Byte:
445 case BuiltinTypeSpec.Type.SByte:
446 case BuiltinTypeSpec.Type.Short:
447 case BuiltinTypeSpec.Type.UShort:
448 case BuiltinTypeSpec.Type.Char:
449 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
453 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
454 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
459 protected override Expression DoResolve (ResolveContext ec)
461 if (Oper == Operator.AddressOf) {
462 return ResolveAddressOf (ec);
465 Expr = Expr.Resolve (ec);
469 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
470 Arguments args = new Arguments (1);
471 args.Add (new Argument (Expr));
472 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
475 if (Expr.Type.IsNullableType)
476 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
479 // Attempt to use a constant folding operation.
481 Constant cexpr = Expr as Constant;
483 cexpr = TryReduceConstant (ec, cexpr);
488 Expression expr = ResolveOperator (ec, Expr);
490 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
493 // Reduce unary operator on predefined types
495 if (expr == this && Oper == Operator.UnaryPlus)
501 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
506 public override void Emit (EmitContext ec)
508 EmitOperator (ec, type);
511 protected void EmitOperator (EmitContext ec, TypeSpec type)
514 case Operator.UnaryPlus:
518 case Operator.UnaryNegation:
519 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
520 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
521 Expr = Expr.EmitToField (ec);
524 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
525 ec.Emit (OpCodes.Conv_U8);
527 ec.Emit (OpCodes.Sub_Ovf);
530 ec.Emit (OpCodes.Neg);
535 case Operator.LogicalNot:
538 ec.Emit (OpCodes.Ceq);
541 case Operator.OnesComplement:
543 ec.Emit (OpCodes.Not);
546 case Operator.AddressOf:
547 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
551 throw new Exception ("This should not happen: Operator = "
556 // Same trick as in Binary expression
558 if (enum_conversion != null)
559 enum_conversion.Emit (ec);
562 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
564 if (Oper == Operator.LogicalNot)
565 Expr.EmitBranchable (ec, target, !on_true);
567 base.EmitBranchable (ec, target, on_true);
570 public override void EmitSideEffect (EmitContext ec)
572 Expr.EmitSideEffect (ec);
576 // Converts operator to System.Linq.Expressions.ExpressionType enum name
578 string GetOperatorExpressionTypeName ()
581 case Operator.OnesComplement:
582 return "OnesComplement";
583 case Operator.LogicalNot:
585 case Operator.UnaryNegation:
587 case Operator.UnaryPlus:
590 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
594 static bool IsFloat (TypeSpec t)
596 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
600 // Returns a stringified representation of the Operator
602 public static string OperName (Operator oper)
605 case Operator.UnaryPlus:
607 case Operator.UnaryNegation:
609 case Operator.LogicalNot:
611 case Operator.OnesComplement:
613 case Operator.AddressOf:
617 throw new NotImplementedException (oper.ToString ());
620 public override SLE.Expression MakeExpression (BuilderContext ctx)
622 var expr = Expr.MakeExpression (ctx);
623 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
626 case Operator.UnaryNegation:
627 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
628 case Operator.LogicalNot:
629 return SLE.Expression.Not (expr);
630 #if NET_4_0 || MONODROID
631 case Operator.OnesComplement:
632 return SLE.Expression.OnesComplement (expr);
635 throw new NotImplementedException (Oper.ToString ());
639 Expression ResolveAddressOf (ResolveContext ec)
642 UnsafeError (ec, loc);
644 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
645 if (Expr == null || Expr.eclass != ExprClass.Variable) {
646 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
650 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
654 IVariableReference vr = Expr as IVariableReference;
657 is_fixed = vr.IsFixed;
658 vr.SetHasAddressTaken ();
661 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
664 IFixedExpression fe = Expr as IFixedExpression;
665 is_fixed = fe != null && fe.IsFixed;
668 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
669 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
672 type = PointerContainer.MakeType (ec.Module, Expr.Type);
673 eclass = ExprClass.Value;
677 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
679 expr = DoNumericPromotion (rc, Oper, expr);
680 TypeSpec expr_type = expr.Type;
681 foreach (TypeSpec t in predefined) {
689 // Perform user-operator overload resolution
691 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
693 CSharp.Operator.OpType op_type;
695 case Operator.LogicalNot:
696 op_type = CSharp.Operator.OpType.LogicalNot; break;
697 case Operator.OnesComplement:
698 op_type = CSharp.Operator.OpType.OnesComplement; break;
699 case Operator.UnaryNegation:
700 op_type = CSharp.Operator.OpType.UnaryNegation; break;
701 case Operator.UnaryPlus:
702 op_type = CSharp.Operator.OpType.UnaryPlus; break;
704 throw new InternalErrorException (Oper.ToString ());
707 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
711 Arguments args = new Arguments (1);
712 args.Add (new Argument (expr));
714 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
715 var oper = res.ResolveOperator (ec, ref args);
720 Expr = args [0].Expr;
721 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
725 // Unary user type overload resolution
727 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
729 Expression best_expr = ResolveUserOperator (ec, expr);
730 if (best_expr != null)
733 foreach (TypeSpec t in predefined) {
734 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
735 if (oper_expr == null)
738 if (oper_expr == ErrorExpression.Instance)
742 // decimal type is predefined but has user-operators
744 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
745 oper_expr = ResolveUserType (ec, oper_expr, predefined);
747 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
749 if (oper_expr == null)
752 if (best_expr == null) {
753 best_expr = oper_expr;
757 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
759 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
760 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
761 OperName (Oper), expr.Type.GetSignatureForError ());
763 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
770 best_expr = oper_expr;
773 if (best_expr == null)
777 // HACK: Decimal user-operator is included in standard operators
779 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
783 type = best_expr.Type;
787 protected override void CloneTo (CloneContext clonectx, Expression t)
789 Unary target = (Unary) t;
791 target.Expr = Expr.Clone (clonectx);
794 public override object Accept (StructuralVisitor visitor)
796 return visitor.Visit (this);
802 // Unary operators are turned into Indirection expressions
803 // after semantic analysis (this is so we can take the address
804 // of an indirection).
806 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
808 LocalTemporary temporary;
811 public Indirection (Expression expr, Location l)
817 public Expression Expr {
823 public bool IsFixed {
827 public override Location StartLocation {
829 return expr.StartLocation;
833 protected override void CloneTo (CloneContext clonectx, Expression t)
835 Indirection target = (Indirection) t;
836 target.expr = expr.Clone (clonectx);
839 public override bool ContainsEmitWithAwait ()
841 throw new NotImplementedException ();
844 public override Expression CreateExpressionTree (ResolveContext ec)
846 Error_PointerInsideExpressionTree (ec);
850 public override void Emit (EmitContext ec)
855 ec.EmitLoadFromPtr (Type);
858 public void Emit (EmitContext ec, bool leave_copy)
862 ec.Emit (OpCodes.Dup);
863 temporary = new LocalTemporary (expr.Type);
864 temporary.Store (ec);
868 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
870 prepared = isCompound;
875 ec.Emit (OpCodes.Dup);
879 ec.Emit (OpCodes.Dup);
880 temporary = new LocalTemporary (source.Type);
881 temporary.Store (ec);
884 ec.EmitStoreFromPtr (type);
886 if (temporary != null) {
888 temporary.Release (ec);
892 public void AddressOf (EmitContext ec, AddressOp Mode)
897 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
899 return DoResolve (ec);
902 protected override Expression DoResolve (ResolveContext ec)
904 expr = expr.Resolve (ec);
909 UnsafeError (ec, loc);
911 var pc = expr.Type as PointerContainer;
914 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
920 if (type.Kind == MemberKind.Void) {
921 Error_VoidPointerOperation (ec);
925 eclass = ExprClass.Variable;
929 public override object Accept (StructuralVisitor visitor)
931 return visitor.Visit (this);
936 /// Unary Mutator expressions (pre and post ++ and --)
940 /// UnaryMutator implements ++ and -- expressions. It derives from
941 /// ExpressionStatement becuase the pre/post increment/decrement
942 /// operators can be used in a statement context.
944 /// FIXME: Idea, we could split this up in two classes, one simpler
945 /// for the common case, and one with the extra fields for more complex
946 /// classes (indexers require temporary access; overloaded require method)
949 public class UnaryMutator : ExpressionStatement
951 class DynamicPostMutator : Expression, IAssignMethod
956 public DynamicPostMutator (Expression expr)
959 this.type = expr.Type;
960 this.loc = expr.Location;
963 public override Expression CreateExpressionTree (ResolveContext ec)
965 throw new NotImplementedException ("ET");
968 protected override Expression DoResolve (ResolveContext rc)
970 eclass = expr.eclass;
974 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
976 expr.DoResolveLValue (ec, right_side);
977 return DoResolve (ec);
980 public override void Emit (EmitContext ec)
985 public void Emit (EmitContext ec, bool leave_copy)
987 throw new NotImplementedException ();
991 // Emits target assignment using unmodified source value
993 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
996 // Allocate temporary variable to keep original value before it's modified
998 temp = new LocalTemporary (type);
1002 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1013 public enum Mode : byte {
1020 PreDecrement = IsDecrement,
1021 PostIncrement = IsPost,
1022 PostDecrement = IsPost | IsDecrement
1026 bool is_expr, recurse;
1028 protected Expression expr;
1030 // Holds the real operation
1031 Expression operation;
1033 public UnaryMutator (Mode m, Expression e, Location loc)
1040 public Mode UnaryMutatorMode {
1046 public Expression Expr {
1052 public override Location StartLocation {
1054 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1058 public override bool ContainsEmitWithAwait ()
1060 return expr.ContainsEmitWithAwait ();
1063 public override Expression CreateExpressionTree (ResolveContext ec)
1065 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1068 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1071 // Predefined ++ and -- operators exist for the following types:
1072 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1074 return new TypeSpec[] {
1090 protected override Expression DoResolve (ResolveContext ec)
1092 expr = expr.Resolve (ec);
1097 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1099 // Handle postfix unary operators using local
1100 // temporary variable
1102 if ((mode & Mode.IsPost) != 0)
1103 expr = new DynamicPostMutator (expr);
1105 Arguments args = new Arguments (1);
1106 args.Add (new Argument (expr));
1107 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1110 if (expr.Type.IsNullableType)
1111 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1113 return DoResolveOperation (ec);
1116 protected Expression DoResolveOperation (ResolveContext ec)
1118 eclass = ExprClass.Value;
1121 if (expr is RuntimeValueExpression) {
1124 // Use itself at the top of the stack
1125 operation = new EmptyExpression (type);
1129 // The operand of the prefix/postfix increment decrement operators
1130 // should be an expression that is classified as a variable,
1131 // a property access or an indexer access
1133 // TODO: Move to parser, expr is ATypeNameExpression
1134 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1135 expr = expr.ResolveLValue (ec, expr);
1137 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1141 // Step 1: Try to find a user operator, it has priority over predefined ones
1143 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1144 var methods = MemberCache.GetUserOperator (type, user_op, false);
1146 if (methods != null) {
1147 Arguments args = new Arguments (1);
1148 args.Add (new Argument (expr));
1150 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1151 var method = res.ResolveOperator (ec, ref args);
1155 args[0].Expr = operation;
1156 operation = new UserOperatorCall (method, args, null, loc);
1157 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1162 // Step 2: Try predefined types
1165 Expression source = null;
1166 bool primitive_type;
1169 // Predefined without user conversion first for speed-up
1171 // Predefined ++ and -- operators exist for the following types:
1172 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1174 switch (type.BuiltinType) {
1175 case BuiltinTypeSpec.Type.Byte:
1176 case BuiltinTypeSpec.Type.SByte:
1177 case BuiltinTypeSpec.Type.Short:
1178 case BuiltinTypeSpec.Type.UShort:
1179 case BuiltinTypeSpec.Type.Int:
1180 case BuiltinTypeSpec.Type.UInt:
1181 case BuiltinTypeSpec.Type.Long:
1182 case BuiltinTypeSpec.Type.ULong:
1183 case BuiltinTypeSpec.Type.Char:
1184 case BuiltinTypeSpec.Type.Float:
1185 case BuiltinTypeSpec.Type.Double:
1186 case BuiltinTypeSpec.Type.Decimal:
1188 primitive_type = true;
1191 primitive_type = false;
1193 // ++/-- on pointer variables of all types except void*
1194 if (type.IsPointer) {
1195 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1196 Error_VoidPointerOperation (ec);
1202 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1203 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1205 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1206 if (source != null) {
1212 // ++/-- on enum types
1213 if (source == null && type.IsEnum)
1216 if (source == null) {
1217 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1224 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1225 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1226 operation = new Binary (op, source, one);
1227 operation = operation.Resolve (ec);
1228 if (operation == null)
1229 throw new NotImplementedException ("should not be reached");
1231 if (operation.Type != type) {
1233 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1235 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1241 void EmitCode (EmitContext ec, bool is_expr)
1244 this.is_expr = is_expr;
1245 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1248 public override void Emit (EmitContext ec)
1251 // We use recurse to allow ourselfs to be the source
1252 // of an assignment. This little hack prevents us from
1253 // having to allocate another expression
1256 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1264 EmitCode (ec, true);
1267 protected virtual void EmitOperation (EmitContext ec)
1269 operation.Emit (ec);
1272 public override void EmitStatement (EmitContext ec)
1274 EmitCode (ec, false);
1278 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1280 string GetOperatorExpressionTypeName ()
1282 return IsDecrement ? "Decrement" : "Increment";
1286 get { return (mode & Mode.IsDecrement) != 0; }
1290 #if NET_4_0 || MONODROID
1291 public override SLE.Expression MakeExpression (BuilderContext ctx)
1293 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1294 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1295 return SLE.Expression.Assign (target, source);
1299 protected override void CloneTo (CloneContext clonectx, Expression t)
1301 UnaryMutator target = (UnaryMutator) t;
1303 target.expr = expr.Clone (clonectx);
1306 public override object Accept (StructuralVisitor visitor)
1308 return visitor.Visit (this);
1314 // Base class for the `is' and `as' operators
1316 public abstract class Probe : Expression
1318 public Expression ProbeType;
1319 protected Expression expr;
1320 protected TypeSpec probe_type_expr;
1322 public Probe (Expression expr, Expression probe_type, Location l)
1324 ProbeType = probe_type;
1329 public Expression Expr {
1335 public override bool ContainsEmitWithAwait ()
1337 return expr.ContainsEmitWithAwait ();
1340 protected override Expression DoResolve (ResolveContext ec)
1342 probe_type_expr = ProbeType.ResolveAsType (ec);
1343 if (probe_type_expr == null)
1346 expr = expr.Resolve (ec);
1350 if (probe_type_expr.IsStatic) {
1351 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1355 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1356 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1361 if (expr.Type == InternalType.AnonymousMethod) {
1362 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1370 protected abstract string OperatorName { get; }
1372 protected override void CloneTo (CloneContext clonectx, Expression t)
1374 Probe target = (Probe) t;
1376 target.expr = expr.Clone (clonectx);
1377 target.ProbeType = ProbeType.Clone (clonectx);
1383 /// Implementation of the `is' operator.
1385 public class Is : Probe
1387 Nullable.Unwrap expr_unwrap;
1389 public Is (Expression expr, Expression probe_type, Location l)
1390 : base (expr, probe_type, l)
1394 protected override string OperatorName {
1395 get { return "is"; }
1398 public override Expression CreateExpressionTree (ResolveContext ec)
1400 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1401 expr.CreateExpressionTree (ec),
1402 new TypeOf (probe_type_expr, loc));
1404 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1407 public override void Emit (EmitContext ec)
1409 if (expr_unwrap != null) {
1410 expr_unwrap.EmitCheck (ec);
1416 // Only to make verifier happy
1417 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1418 ec.Emit (OpCodes.Box, expr.Type);
1420 ec.Emit (OpCodes.Isinst, probe_type_expr);
1422 ec.Emit (OpCodes.Cgt_Un);
1425 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1427 if (expr_unwrap != null) {
1428 expr_unwrap.EmitCheck (ec);
1431 ec.Emit (OpCodes.Isinst, probe_type_expr);
1433 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1436 Expression CreateConstantResult (ResolveContext ec, bool result)
1439 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1440 probe_type_expr.GetSignatureForError ());
1442 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1443 probe_type_expr.GetSignatureForError ());
1445 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, result, loc), this);
1448 protected override Expression DoResolve (ResolveContext ec)
1450 if (base.DoResolve (ec) == null)
1453 TypeSpec d = expr.Type;
1454 bool d_is_nullable = false;
1457 // If E is a method group or the null literal, or if the type of E is a reference
1458 // type or a nullable type and the value of E is null, the result is false
1460 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1461 return CreateConstantResult (ec, false);
1463 if (d.IsNullableType) {
1464 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1465 if (!ut.IsGenericParameter) {
1467 d_is_nullable = true;
1471 type = ec.BuiltinTypes.Bool;
1472 eclass = ExprClass.Value;
1473 TypeSpec t = probe_type_expr;
1474 bool t_is_nullable = false;
1475 if (t.IsNullableType) {
1476 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1477 if (!ut.IsGenericParameter) {
1479 t_is_nullable = true;
1486 // D and T are the same value types but D can be null
1488 if (d_is_nullable && !t_is_nullable) {
1489 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1494 // The result is true if D and T are the same value types
1496 return CreateConstantResult (ec, true);
1499 var tp = d as TypeParameterSpec;
1501 return ResolveGenericParameter (ec, t, tp);
1504 // An unboxing conversion exists
1506 if (Convert.ExplicitReferenceConversionExists (d, t))
1509 if (TypeManager.IsGenericParameter (t))
1510 return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
1512 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1513 ec.Report.Warning (1981, 3, loc,
1514 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1515 OperatorName, t.GetSignatureForError ());
1518 if (TypeManager.IsGenericParameter (d))
1519 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1521 if (TypeSpec.IsValueType (d)) {
1522 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1523 if (d_is_nullable && !t_is_nullable) {
1524 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1528 return CreateConstantResult (ec, true);
1531 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1533 // Do not optimize for imported type
1535 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None)
1539 // Turn is check into simple null check for implicitly convertible reference types
1541 return ReducedExpression.Create (
1542 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1546 if (Convert.ExplicitReferenceConversionExists (d, t)) {
1552 return CreateConstantResult (ec, false);
1555 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1557 if (t.IsReferenceType) {
1559 return CreateConstantResult (ec, false);
1562 if (TypeManager.IsGenericParameter (expr.Type)) {
1563 if (expr.Type == d && TypeSpec.IsValueType (t))
1564 return CreateConstantResult (ec, true);
1566 expr = new BoxedCast (expr, d);
1572 public override object Accept (StructuralVisitor visitor)
1574 return visitor.Visit (this);
1579 /// Implementation of the `as' operator.
1581 public class As : Probe {
1582 Expression resolved_type;
1584 public As (Expression expr, Expression probe_type, Location l)
1585 : base (expr, probe_type, l)
1589 protected override string OperatorName {
1590 get { return "as"; }
1593 public override Expression CreateExpressionTree (ResolveContext ec)
1595 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1596 expr.CreateExpressionTree (ec),
1597 new TypeOf (probe_type_expr, loc));
1599 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1602 public override void Emit (EmitContext ec)
1606 ec.Emit (OpCodes.Isinst, type);
1608 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1609 ec.Emit (OpCodes.Unbox_Any, type);
1612 protected override Expression DoResolve (ResolveContext ec)
1614 if (resolved_type == null) {
1615 resolved_type = base.DoResolve (ec);
1617 if (resolved_type == null)
1621 type = probe_type_expr;
1622 eclass = ExprClass.Value;
1623 TypeSpec etype = expr.Type;
1625 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1626 if (TypeManager.IsGenericParameter (type)) {
1627 ec.Report.Error (413, loc,
1628 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1629 probe_type_expr.GetSignatureForError ());
1631 ec.Report.Error (77, loc,
1632 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1633 type.GetSignatureForError ());
1638 if (expr.IsNull && type.IsNullableType) {
1639 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1642 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1643 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1647 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1649 e = EmptyCast.Create (e, type);
1650 return ReducedExpression.Create (e, this).Resolve (ec);
1653 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1654 if (TypeManager.IsGenericParameter (etype))
1655 expr = new BoxedCast (expr, etype);
1660 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1661 expr = new BoxedCast (expr, etype);
1665 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1666 etype.GetSignatureForError (), type.GetSignatureForError ());
1671 public override object Accept (StructuralVisitor visitor)
1673 return visitor.Visit (this);
1678 // This represents a typecast in the source language.
1680 public class Cast : ShimExpression {
1681 Expression target_type;
1683 public Cast (Expression cast_type, Expression expr, Location loc)
1686 this.target_type = cast_type;
1690 public Expression TargetType {
1691 get { return target_type; }
1694 protected override Expression DoResolve (ResolveContext ec)
1696 expr = expr.Resolve (ec);
1700 type = target_type.ResolveAsType (ec);
1704 if (type.IsStatic) {
1705 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
1709 if (type.IsPointer && !ec.IsUnsafe) {
1710 UnsafeError (ec, loc);
1713 eclass = ExprClass.Value;
1715 Constant c = expr as Constant;
1717 c = c.Reduce (ec, type);
1722 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1724 return EmptyCast.Create (res, type);
1729 protected override void CloneTo (CloneContext clonectx, Expression t)
1731 Cast target = (Cast) t;
1733 target.target_type = target_type.Clone (clonectx);
1734 target.expr = expr.Clone (clonectx);
1737 public override object Accept (StructuralVisitor visitor)
1739 return visitor.Visit (this);
1743 public class ImplicitCast : ShimExpression
1747 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1750 this.loc = expr.Location;
1752 this.arrayAccess = arrayAccess;
1755 protected override Expression DoResolve (ResolveContext ec)
1757 expr = expr.Resolve (ec);
1762 expr = ConvertExpressionToArrayIndex (ec, expr);
1764 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1771 // C# 2.0 Default value expression
1773 public class DefaultValueExpression : Expression
1777 public DefaultValueExpression (Expression expr, Location loc)
1783 public Expression Expr {
1789 public override bool IsSideEffectFree {
1795 public override bool ContainsEmitWithAwait ()
1800 public override Expression CreateExpressionTree (ResolveContext ec)
1802 Arguments args = new Arguments (2);
1803 args.Add (new Argument (this));
1804 args.Add (new Argument (new TypeOf (type, loc)));
1805 return CreateExpressionFactoryCall (ec, "Constant", args);
1808 protected override Expression DoResolve (ResolveContext ec)
1810 type = expr.ResolveAsType (ec);
1814 if (type.IsStatic) {
1815 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1819 return new NullLiteral (Location).ConvertImplicitly (type);
1821 if (TypeSpec.IsReferenceType (type))
1822 return new NullConstant (type, loc);
1824 Constant c = New.Constantify (type, expr.Location);
1828 eclass = ExprClass.Variable;
1832 public override void Emit (EmitContext ec)
1834 LocalTemporary temp_storage = new LocalTemporary(type);
1836 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1837 ec.Emit(OpCodes.Initobj, type);
1838 temp_storage.Emit(ec);
1839 temp_storage.Release (ec);
1842 #if (NET_4_0 || MONODROID) && !STATIC
1843 public override SLE.Expression MakeExpression (BuilderContext ctx)
1845 return SLE.Expression.Default (type.GetMetaInfo ());
1849 protected override void CloneTo (CloneContext clonectx, Expression t)
1851 DefaultValueExpression target = (DefaultValueExpression) t;
1853 target.expr = expr.Clone (clonectx);
1856 public override object Accept (StructuralVisitor visitor)
1858 return visitor.Visit (this);
1863 /// Binary operators
1865 public class Binary : Expression, IDynamicBinder
1867 public class PredefinedOperator
1869 protected readonly TypeSpec left;
1870 protected readonly TypeSpec right;
1871 protected readonly TypeSpec left_unwrap;
1872 protected readonly TypeSpec right_unwrap;
1873 public readonly Operator OperatorsMask;
1874 public TypeSpec ReturnType;
1876 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1877 : this (ltype, rtype, op_mask, ltype)
1881 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1882 : this (type, type, op_mask, return_type)
1886 public PredefinedOperator (TypeSpec type, Operator op_mask)
1887 : this (type, type, op_mask, type)
1891 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1893 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1894 throw new InternalErrorException ("Only masked values can be used");
1896 if ((op_mask & Operator.NullableMask) != 0) {
1897 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
1898 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
1900 left_unwrap = ltype;
1901 right_unwrap = rtype;
1906 this.OperatorsMask = op_mask;
1907 this.ReturnType = return_type;
1910 public bool IsLifted {
1912 return (OperatorsMask & Operator.NullableMask) != 0;
1916 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
1920 var left_expr = b.left;
1921 var right_expr = b.right;
1923 b.type = ReturnType;
1926 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
1927 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1928 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1931 if (right_expr.IsNull) {
1932 if ((b.oper & Operator.EqualityMask) != 0) {
1933 if (!left_expr.Type.IsNullableType && left_expr.Type == left_unwrap)
1934 return b.CreateLiftedValueTypeResult (rc, left_unwrap);
1935 } else if ((b.oper & Operator.BitwiseMask) != 0) {
1936 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
1937 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1939 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1940 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1942 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
1943 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1945 return b.CreateLiftedValueTypeResult (rc, left);
1947 } else if (left_expr.IsNull) {
1948 if ((b.oper & Operator.EqualityMask) != 0) {
1949 if (!right_expr.Type.IsNullableType && right_expr.Type == right_unwrap)
1950 return b.CreateLiftedValueTypeResult (rc, right_unwrap);
1951 } else if ((b.oper & Operator.BitwiseMask) != 0) {
1952 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
1953 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1955 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1956 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1958 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
1959 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1961 return b.CreateLiftedValueTypeResult (rc, right);
1967 // A user operators does not support multiple user conversions, but decimal type
1968 // is considered to be predefined type therefore we apply predefined operators rules
1969 // and then look for decimal user-operator implementation
1971 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
1972 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1973 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1975 return b.ResolveUserOperator (rc, b.left, b.right);
1978 c = right_expr as Constant;
1980 if (c.IsDefaultValue) {
1984 // (expr + 0) to expr
1985 // (expr - 0) to expr
1986 // (bool? | false) to bool?
1988 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
1989 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
1990 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1991 return ReducedExpression.Create (b.left, b).Resolve (rc);
1997 // (bool? & true) to bool?
1999 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2000 return ReducedExpression.Create (b.left, b).Resolve (rc);
2004 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2005 return ReducedExpression.Create (b.left, b).Resolve (rc);
2007 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2008 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2012 c = b.left as Constant;
2014 if (c.IsDefaultValue) {
2018 // (0 + expr) to expr
2019 // (false | bool?) to bool?
2021 if (b.oper == Operator.Addition ||
2022 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2023 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2024 return ReducedExpression.Create (b.right, b).Resolve (rc);
2030 // (true & bool?) to bool?
2032 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2033 return ReducedExpression.Create (b.right, b).Resolve (rc);
2037 if (b.oper == Operator.Multiply && c.IsOneInteger)
2038 return ReducedExpression.Create (b.right, b).Resolve (rc);
2042 var lifted = new Nullable.LiftedBinaryOperator (b);
2044 TypeSpec ltype, rtype;
2045 if (b.left.Type.IsNullableType) {
2046 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2047 ltype = left_unwrap;
2052 if (b.right.Type.IsNullableType) {
2053 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2054 rtype = right_unwrap;
2059 lifted.Left = b.left.IsNull ?
2061 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2063 lifted.Right = b.right.IsNull ?
2065 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2067 return lifted.Resolve (rc);
2070 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2071 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2076 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2079 // We are dealing with primitive types only
2081 return left == ltype && ltype == rtype;
2084 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2087 if (left == lexpr.Type && right == rexpr.Type)
2090 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2091 Convert.ImplicitConversionExists (ec, rexpr, right);
2094 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2096 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2097 return best_operator;
2099 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2103 if (left != null && best_operator.left != null) {
2104 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2108 // When second argument is same as the first one, the result is same
2110 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2111 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2114 if (result == 0 || result > 2)
2117 return result == 1 ? best_operator : this;
2121 sealed class PredefinedStringOperator : PredefinedOperator
2123 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2124 : base (type, type, op_mask, retType)
2128 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2129 : base (ltype, rtype, op_mask, retType)
2133 public override Expression ConvertResult (ResolveContext ec, Binary b)
2136 // Use original expression for nullable arguments
2138 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2140 b.left = unwrap.Original;
2142 unwrap = b.right as Nullable.Unwrap;
2144 b.right = unwrap.Original;
2146 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2147 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2150 // Start a new concat expression using converted expression
2152 return StringConcat.Create (ec, b.left, b.right, b.loc);
2156 sealed class PredefinedEqualityOperator : PredefinedOperator
2158 MethodSpec equal_method, inequal_method;
2160 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
2161 : base (arg, arg, Operator.EqualityMask, retType)
2165 public override Expression ConvertResult (ResolveContext ec, Binary b)
2167 b.type = ReturnType;
2169 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2170 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2172 Arguments args = new Arguments (2);
2173 args.Add (new Argument (b.left));
2174 args.Add (new Argument (b.right));
2177 if (b.oper == Operator.Equality) {
2178 if (equal_method == null) {
2179 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2180 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2181 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2182 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2184 throw new NotImplementedException (left.GetSignatureForError ());
2187 method = equal_method;
2189 if (inequal_method == null) {
2190 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2191 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2192 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2193 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2195 throw new NotImplementedException (left.GetSignatureForError ());
2198 method = inequal_method;
2201 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2205 class PredefinedPointerOperator : PredefinedOperator
2207 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2208 : base (ltype, rtype, op_mask)
2212 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2213 : base (ltype, rtype, op_mask, retType)
2217 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2218 : base (type, op_mask, return_type)
2222 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2225 if (!lexpr.Type.IsPointer)
2228 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2232 if (right == null) {
2233 if (!rexpr.Type.IsPointer)
2236 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2243 public override Expression ConvertResult (ResolveContext ec, Binary b)
2246 b.left = EmptyCast.Create (b.left, left);
2247 } else if (right != null) {
2248 b.right = EmptyCast.Create (b.right, right);
2251 TypeSpec r_type = ReturnType;
2252 Expression left_arg, right_arg;
2253 if (r_type == null) {
2256 right_arg = b.right;
2257 r_type = b.left.Type;
2261 r_type = b.right.Type;
2265 right_arg = b.right;
2268 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2273 public enum Operator {
2274 Multiply = 0 | ArithmeticMask,
2275 Division = 1 | ArithmeticMask,
2276 Modulus = 2 | ArithmeticMask,
2277 Addition = 3 | ArithmeticMask | AdditionMask,
2278 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2280 LeftShift = 5 | ShiftMask,
2281 RightShift = 6 | ShiftMask,
2283 LessThan = 7 | ComparisonMask | RelationalMask,
2284 GreaterThan = 8 | ComparisonMask | RelationalMask,
2285 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2286 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2287 Equality = 11 | ComparisonMask | EqualityMask,
2288 Inequality = 12 | ComparisonMask | EqualityMask,
2290 BitwiseAnd = 13 | BitwiseMask,
2291 ExclusiveOr = 14 | BitwiseMask,
2292 BitwiseOr = 15 | BitwiseMask,
2294 LogicalAnd = 16 | LogicalMask,
2295 LogicalOr = 17 | LogicalMask,
2300 ValuesOnlyMask = ArithmeticMask - 1,
2301 ArithmeticMask = 1 << 5,
2303 ComparisonMask = 1 << 7,
2304 EqualityMask = 1 << 8,
2305 BitwiseMask = 1 << 9,
2306 LogicalMask = 1 << 10,
2307 AdditionMask = 1 << 11,
2308 SubtractionMask = 1 << 12,
2309 RelationalMask = 1 << 13,
2311 DecomposedMask = 1 << 19,
2312 NullableMask = 1 << 20,
2321 readonly Operator oper;
2322 Expression left, right;
2324 ConvCast.Mode enum_conversion;
2326 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
2327 : this (oper, left, right)
2330 state |= State.Compound;
2333 public Binary (Operator oper, Expression left, Expression right)
2338 this.loc = left.Location;
2343 public bool IsCompound {
2345 return (state & State.Compound) != 0;
2349 public Operator Oper {
2355 public Expression Left {
2361 public Expression Right {
2367 public override Location StartLocation {
2369 return left.StartLocation;
2376 /// Returns a stringified representation of the Operator
2378 string OperName (Operator oper)
2382 case Operator.Multiply:
2385 case Operator.Division:
2388 case Operator.Modulus:
2391 case Operator.Addition:
2394 case Operator.Subtraction:
2397 case Operator.LeftShift:
2400 case Operator.RightShift:
2403 case Operator.LessThan:
2406 case Operator.GreaterThan:
2409 case Operator.LessThanOrEqual:
2412 case Operator.GreaterThanOrEqual:
2415 case Operator.Equality:
2418 case Operator.Inequality:
2421 case Operator.BitwiseAnd:
2424 case Operator.BitwiseOr:
2427 case Operator.ExclusiveOr:
2430 case Operator.LogicalOr:
2433 case Operator.LogicalAnd:
2437 s = oper.ToString ();
2447 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2449 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2452 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2454 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
2458 l = left.Type.GetSignatureForError ();
2459 r = right.Type.GetSignatureForError ();
2461 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2465 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2467 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2471 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2473 string GetOperatorExpressionTypeName ()
2476 case Operator.Addition:
2477 return IsCompound ? "AddAssign" : "Add";
2478 case Operator.BitwiseAnd:
2479 return IsCompound ? "AndAssign" : "And";
2480 case Operator.BitwiseOr:
2481 return IsCompound ? "OrAssign" : "Or";
2482 case Operator.Division:
2483 return IsCompound ? "DivideAssign" : "Divide";
2484 case Operator.ExclusiveOr:
2485 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2486 case Operator.Equality:
2488 case Operator.GreaterThan:
2489 return "GreaterThan";
2490 case Operator.GreaterThanOrEqual:
2491 return "GreaterThanOrEqual";
2492 case Operator.Inequality:
2494 case Operator.LeftShift:
2495 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2496 case Operator.LessThan:
2498 case Operator.LessThanOrEqual:
2499 return "LessThanOrEqual";
2500 case Operator.LogicalAnd:
2502 case Operator.LogicalOr:
2504 case Operator.Modulus:
2505 return IsCompound ? "ModuloAssign" : "Modulo";
2506 case Operator.Multiply:
2507 return IsCompound ? "MultiplyAssign" : "Multiply";
2508 case Operator.RightShift:
2509 return IsCompound ? "RightShiftAssign" : "RightShift";
2510 case Operator.Subtraction:
2511 return IsCompound ? "SubtractAssign" : "Subtract";
2513 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2517 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2520 case Operator.Addition:
2521 return CSharp.Operator.OpType.Addition;
2522 case Operator.BitwiseAnd:
2523 case Operator.LogicalAnd:
2524 return CSharp.Operator.OpType.BitwiseAnd;
2525 case Operator.BitwiseOr:
2526 case Operator.LogicalOr:
2527 return CSharp.Operator.OpType.BitwiseOr;
2528 case Operator.Division:
2529 return CSharp.Operator.OpType.Division;
2530 case Operator.Equality:
2531 return CSharp.Operator.OpType.Equality;
2532 case Operator.ExclusiveOr:
2533 return CSharp.Operator.OpType.ExclusiveOr;
2534 case Operator.GreaterThan:
2535 return CSharp.Operator.OpType.GreaterThan;
2536 case Operator.GreaterThanOrEqual:
2537 return CSharp.Operator.OpType.GreaterThanOrEqual;
2538 case Operator.Inequality:
2539 return CSharp.Operator.OpType.Inequality;
2540 case Operator.LeftShift:
2541 return CSharp.Operator.OpType.LeftShift;
2542 case Operator.LessThan:
2543 return CSharp.Operator.OpType.LessThan;
2544 case Operator.LessThanOrEqual:
2545 return CSharp.Operator.OpType.LessThanOrEqual;
2546 case Operator.Modulus:
2547 return CSharp.Operator.OpType.Modulus;
2548 case Operator.Multiply:
2549 return CSharp.Operator.OpType.Multiply;
2550 case Operator.RightShift:
2551 return CSharp.Operator.OpType.RightShift;
2552 case Operator.Subtraction:
2553 return CSharp.Operator.OpType.Subtraction;
2555 throw new InternalErrorException (op.ToString ());
2559 public override bool ContainsEmitWithAwait ()
2561 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2564 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
2569 case Operator.Multiply:
2570 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2571 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2572 opcode = OpCodes.Mul_Ovf;
2573 else if (!IsFloat (l))
2574 opcode = OpCodes.Mul_Ovf_Un;
2576 opcode = OpCodes.Mul;
2578 opcode = OpCodes.Mul;
2582 case Operator.Division:
2584 opcode = OpCodes.Div_Un;
2586 opcode = OpCodes.Div;
2589 case Operator.Modulus:
2591 opcode = OpCodes.Rem_Un;
2593 opcode = OpCodes.Rem;
2596 case Operator.Addition:
2597 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2598 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2599 opcode = OpCodes.Add_Ovf;
2600 else if (!IsFloat (l))
2601 opcode = OpCodes.Add_Ovf_Un;
2603 opcode = OpCodes.Add;
2605 opcode = OpCodes.Add;
2608 case Operator.Subtraction:
2609 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2610 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2611 opcode = OpCodes.Sub_Ovf;
2612 else if (!IsFloat (l))
2613 opcode = OpCodes.Sub_Ovf_Un;
2615 opcode = OpCodes.Sub;
2617 opcode = OpCodes.Sub;
2620 case Operator.RightShift:
2621 if (!(right is IntConstant)) {
2622 ec.EmitInt (GetShiftMask (l));
2623 ec.Emit (OpCodes.And);
2627 opcode = OpCodes.Shr_Un;
2629 opcode = OpCodes.Shr;
2632 case Operator.LeftShift:
2633 if (!(right is IntConstant)) {
2634 ec.EmitInt (GetShiftMask (l));
2635 ec.Emit (OpCodes.And);
2638 opcode = OpCodes.Shl;
2641 case Operator.Equality:
2642 opcode = OpCodes.Ceq;
2645 case Operator.Inequality:
2646 ec.Emit (OpCodes.Ceq);
2649 opcode = OpCodes.Ceq;
2652 case Operator.LessThan:
2654 opcode = OpCodes.Clt_Un;
2656 opcode = OpCodes.Clt;
2659 case Operator.GreaterThan:
2661 opcode = OpCodes.Cgt_Un;
2663 opcode = OpCodes.Cgt;
2666 case Operator.LessThanOrEqual:
2667 if (IsUnsigned (l) || IsFloat (l))
2668 ec.Emit (OpCodes.Cgt_Un);
2670 ec.Emit (OpCodes.Cgt);
2673 opcode = OpCodes.Ceq;
2676 case Operator.GreaterThanOrEqual:
2677 if (IsUnsigned (l) || IsFloat (l))
2678 ec.Emit (OpCodes.Clt_Un);
2680 ec.Emit (OpCodes.Clt);
2684 opcode = OpCodes.Ceq;
2687 case Operator.BitwiseOr:
2688 opcode = OpCodes.Or;
2691 case Operator.BitwiseAnd:
2692 opcode = OpCodes.And;
2695 case Operator.ExclusiveOr:
2696 opcode = OpCodes.Xor;
2700 throw new InternalErrorException (oper.ToString ());
2706 static int GetShiftMask (TypeSpec type)
2708 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
2711 static bool IsUnsigned (TypeSpec t)
2713 switch (t.BuiltinType) {
2714 case BuiltinTypeSpec.Type.Char:
2715 case BuiltinTypeSpec.Type.UInt:
2716 case BuiltinTypeSpec.Type.ULong:
2717 case BuiltinTypeSpec.Type.UShort:
2718 case BuiltinTypeSpec.Type.Byte:
2725 static bool IsFloat (TypeSpec t)
2727 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2730 public Expression ResolveOperator (ResolveContext rc)
2732 eclass = ExprClass.Value;
2734 TypeSpec l = left.Type;
2735 TypeSpec r = right.Type;
2737 bool primitives_only = false;
2740 // Handles predefined primitive types
2742 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
2743 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
2744 if ((oper & Operator.ShiftMask) == 0) {
2745 if (!DoBinaryOperatorPromotion (rc))
2748 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
2752 if (l.IsPointer || r.IsPointer)
2753 return ResolveOperatorPointer (rc, l, r);
2755 bool lenum = l.IsEnum;
2756 bool renum = r.IsEnum;
2757 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2761 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2762 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
2767 if ((oper & Operator.BitwiseMask) != 0) {
2768 expr = EmptyCast.Create (expr, type);
2769 AddEnumResultCast (type);
2771 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
2772 expr = OptimizeAndOperation (expr);
2776 left = ConvertEnumOperandToUnderlyingType (rc, left);
2777 right = ConvertEnumOperandToUnderlyingType (rc, right);
2780 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
2781 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2785 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
2788 // We cannot break here there is also Enum + String possible match
2789 // which is not ambiguous with predefined enum operators
2792 left = ConvertEnumOperandToUnderlyingType (rc, left);
2793 right = ConvertEnumOperandToUnderlyingType (rc, right);
2797 } else if (l.IsDelegate || r.IsDelegate) {
2801 expr = ResolveOperatorDelegate (rc, l, r);
2803 // TODO: Can this be ambiguous
2810 expr = ResolveUserOperator (rc, left, right);
2816 // Equality operators are more complicated
2818 if ((oper & Operator.EqualityMask) != 0) {
2819 return ResolveEquality (rc, l, r, primitives_only);
2822 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
2826 if (primitives_only)
2830 // Lifted operators have lower priority
2832 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
2835 static bool IsEnumOrNullableEnum (TypeSpec type)
2837 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
2841 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2842 // if 'left' is not an enumeration constant, create one from the type of 'right'
2843 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2846 case Operator.BitwiseOr:
2847 case Operator.BitwiseAnd:
2848 case Operator.ExclusiveOr:
2849 case Operator.Equality:
2850 case Operator.Inequality:
2851 case Operator.LessThan:
2852 case Operator.LessThanOrEqual:
2853 case Operator.GreaterThan:
2854 case Operator.GreaterThanOrEqual:
2855 if (left.Type.IsEnum)
2858 if (left.IsZeroInteger)
2859 return left.Reduce (ec, right.Type);
2863 case Operator.Addition:
2864 case Operator.Subtraction:
2867 case Operator.Multiply:
2868 case Operator.Division:
2869 case Operator.Modulus:
2870 case Operator.LeftShift:
2871 case Operator.RightShift:
2872 if (right.Type.IsEnum || left.Type.IsEnum)
2881 // The `|' operator used on types which were extended is dangerous
2883 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2885 OpcodeCast lcast = left as OpcodeCast;
2886 if (lcast != null) {
2887 if (IsUnsigned (lcast.UnderlyingType))
2891 OpcodeCast rcast = right as OpcodeCast;
2892 if (rcast != null) {
2893 if (IsUnsigned (rcast.UnderlyingType))
2897 if (lcast == null && rcast == null)
2900 // FIXME: consider constants
2902 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
2903 ec.Report.Warning (675, 3, loc,
2904 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2905 ltype.GetSignatureForError ());
2908 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
2910 return new PredefinedOperator[] {
2912 // Pointer arithmetic:
2914 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2915 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2916 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2917 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2919 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
2920 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
2921 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
2922 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
2925 // T* operator + (int y, T* x);
2926 // T* operator + (uint y, T *x);
2927 // T* operator + (long y, T *x);
2928 // T* operator + (ulong y, T *x);
2930 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
2931 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
2932 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
2933 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
2936 // long operator - (T* x, T *y)
2938 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
2942 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
2944 TypeSpec bool_type = types.Bool;
2947 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
2948 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
2949 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
2950 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
2951 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
2952 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
2953 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
2955 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
2956 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
2957 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
2958 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
2959 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
2960 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
2961 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
2963 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
2964 // Remaining string operators are in lifted tables
2966 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
2968 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
2969 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
2970 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
2974 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
2976 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
2977 if (nullable == null)
2978 return new PredefinedOperator [0];
2980 var types = module.Compiler.BuiltinTypes;
2981 var bool_type = types.Bool;
2983 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
2984 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
2985 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
2986 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
2987 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
2988 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
2989 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
2990 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
2993 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
2994 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
2995 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
2996 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
2997 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
2998 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
2999 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3001 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3002 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3003 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3004 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3005 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3006 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3007 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3009 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3011 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3012 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3013 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3016 // Not strictly lifted but need to be in second group otherwise expressions like
3017 // int + null would resolve to +(object, string) instead of +(int?, int?)
3019 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3020 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3025 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3027 TypeSpec bool_type = types.Bool;
3030 new PredefinedEqualityOperator (types.String, bool_type),
3031 new PredefinedEqualityOperator (types.Delegate, bool_type),
3032 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3033 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3034 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3035 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3036 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3037 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3038 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3039 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3043 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3045 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3047 if (nullable == null)
3048 return new PredefinedOperator [0];
3050 var types = module.Compiler.BuiltinTypes;
3051 var bool_type = types.Bool;
3052 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3053 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3054 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3055 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3056 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3057 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3058 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3059 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3062 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3063 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3064 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3065 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3066 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3067 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3068 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3069 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3074 // 7.2.6.2 Binary numeric promotions
3076 bool DoBinaryOperatorPromotion (ResolveContext rc)
3078 TypeSpec ltype = left.Type;
3079 if (ltype.IsNullableType) {
3080 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
3084 // This is numeric promotion code only
3086 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
3089 TypeSpec rtype = right.Type;
3090 if (rtype.IsNullableType) {
3091 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
3094 var lb = ltype.BuiltinType;
3095 var rb = rtype.BuiltinType;
3099 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
3100 type = rc.BuiltinTypes.Decimal;
3101 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
3102 type = rc.BuiltinTypes.Double;
3103 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
3104 type = rc.BuiltinTypes.Float;
3105 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
3106 type = rc.BuiltinTypes.ULong;
3108 if (IsSignedType (lb)) {
3109 expr = ConvertSignedConstant (left, type);
3113 } else if (IsSignedType (rb)) {
3114 expr = ConvertSignedConstant (right, type);
3120 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
3121 type = rc.BuiltinTypes.Long;
3122 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
3123 type = rc.BuiltinTypes.UInt;
3125 if (IsSignedType (lb)) {
3126 expr = ConvertSignedConstant (left, type);
3128 type = rc.BuiltinTypes.Long;
3129 } else if (IsSignedType (rb)) {
3130 expr = ConvertSignedConstant (right, type);
3132 type = rc.BuiltinTypes.Long;
3135 type = rc.BuiltinTypes.Int;
3138 if (ltype != type) {
3139 expr = PromoteExpression (rc, left, type);
3146 if (rtype != type) {
3147 expr = PromoteExpression (rc, right, type);
3157 static bool IsSignedType (BuiltinTypeSpec.Type type)
3160 case BuiltinTypeSpec.Type.Int:
3161 case BuiltinTypeSpec.Type.Short:
3162 case BuiltinTypeSpec.Type.SByte:
3163 case BuiltinTypeSpec.Type.Long:
3170 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
3172 var c = expr as Constant;
3176 return c.ConvertImplicitly (type);
3179 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
3181 if (expr.Type.IsNullableType) {
3182 return Convert.ImplicitConversionStandard (rc, expr,
3183 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
3186 var c = expr as Constant;
3188 return c.ConvertImplicitly (type);
3190 return Convert.ImplicitNumericConversion (expr, type);
3193 protected override Expression DoResolve (ResolveContext ec)
3198 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
3199 left = ((ParenthesizedExpression) left).Expr;
3200 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
3204 if (left.eclass == ExprClass.Type) {
3205 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
3209 left = left.Resolve (ec);
3214 Constant lc = left as Constant;
3216 if (lc != null && lc.Type.BuiltinType == BuiltinTypeSpec.Type.Bool &&
3217 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
3218 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
3220 // FIXME: resolve right expression as unreachable
3221 // right.Resolve (ec);
3223 ec.Report.Warning (429, 4, right.StartLocation, "Unreachable expression code detected");
3227 right = right.Resolve (ec);
3231 Constant rc = right as Constant;
3233 // The conversion rules are ignored in enum context but why
3234 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
3235 lc = EnumLiftUp (ec, lc, rc, loc);
3237 rc = EnumLiftUp (ec, rc, lc, loc);
3240 if (rc != null && lc != null) {
3241 int prev_e = ec.Report.Errors;
3242 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
3243 if (e != null || ec.Report.Errors != prev_e)
3247 // Comparison warnings
3248 if ((oper & Operator.ComparisonMask) != 0) {
3249 if (left.Equals (right)) {
3250 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
3252 CheckOutOfRangeComparison (ec, lc, right.Type);
3253 CheckOutOfRangeComparison (ec, rc, left.Type);
3256 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3258 var rt = right.Type;
3259 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
3260 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
3261 Error_OperatorCannotBeApplied (ec, left, right);
3268 // Special handling for logical boolean operators which require rhs not to be
3269 // evaluated based on lhs value
3271 if ((oper & Operator.LogicalMask) != 0) {
3272 Expression cond_left, cond_right, expr;
3274 args = new Arguments (2);
3276 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3277 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, ec.CurrentBlock, loc);
3279 var cond_args = new Arguments (1);
3280 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left).Resolve (ec)));
3283 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
3284 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
3286 left = temp.CreateReferenceExpression (ec, loc);
3287 if (oper == Operator.LogicalAnd) {
3288 expr = DynamicUnaryConversion.CreateIsFalse (ec, cond_args, loc);
3291 expr = DynamicUnaryConversion.CreateIsTrue (ec, cond_args, loc);
3295 args.Add (new Argument (left));
3296 args.Add (new Argument (right));
3297 cond_right = new DynamicExpressionStatement (this, args, loc);
3299 LocalVariable temp = LocalVariable.CreateCompilerGenerated (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
3301 args.Add (new Argument (temp.CreateReferenceExpression (ec, loc).Resolve (ec)));
3302 args.Add (new Argument (right));
3303 right = new DynamicExpressionStatement (this, args, loc);
3306 // bool && dynamic => (temp = left) ? temp && right : temp;
3307 // bool || dynamic => (temp = left) ? temp : temp || right;
3309 if (oper == Operator.LogicalAnd) {
3311 cond_right = temp.CreateReferenceExpression (ec, loc);
3313 cond_left = temp.CreateReferenceExpression (ec, loc);
3317 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left));
3320 return new Conditional (expr, cond_left, cond_right, loc).Resolve (ec);
3323 args = new Arguments (2);
3324 args.Add (new Argument (left));
3325 args.Add (new Argument (right));
3326 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
3329 return DoResolveCore (ec, left, right);
3332 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3334 Expression expr = ResolveOperator (ec);
3336 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3338 if (left == null || right == null)
3339 throw new InternalErrorException ("Invalid conversion");
3341 if (oper == Operator.BitwiseOr)
3342 CheckBitwiseOrOnSignExtended (ec);
3347 public override SLE.Expression MakeExpression (BuilderContext ctx)
3349 return MakeExpression (ctx, left, right);
3352 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
3354 Console.WriteLine ("{0} x {1}", left.Type.GetSignatureForError (), right.Type.GetSignatureForError ());
3356 var le = left.MakeExpression (ctx);
3357 var re = right.MakeExpression (ctx);
3358 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3361 case Operator.Addition:
3362 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3363 case Operator.BitwiseAnd:
3364 return SLE.Expression.And (le, re);
3365 case Operator.BitwiseOr:
3366 return SLE.Expression.Or (le, re);
3367 case Operator.Division:
3368 return SLE.Expression.Divide (le, re);
3369 case Operator.Equality:
3370 return SLE.Expression.Equal (le, re);
3371 case Operator.ExclusiveOr:
3372 return SLE.Expression.ExclusiveOr (le, re);
3373 case Operator.GreaterThan:
3374 return SLE.Expression.GreaterThan (le, re);
3375 case Operator.GreaterThanOrEqual:
3376 return SLE.Expression.GreaterThanOrEqual (le, re);
3377 case Operator.Inequality:
3378 return SLE.Expression.NotEqual (le, re);
3379 case Operator.LeftShift:
3380 return SLE.Expression.LeftShift (le, re);
3381 case Operator.LessThan:
3382 return SLE.Expression.LessThan (le, re);
3383 case Operator.LessThanOrEqual:
3384 return SLE.Expression.LessThanOrEqual (le, re);
3385 case Operator.LogicalAnd:
3386 return SLE.Expression.AndAlso (le, re);
3387 case Operator.LogicalOr:
3388 return SLE.Expression.OrElse (le, re);
3389 case Operator.Modulus:
3390 return SLE.Expression.Modulo (le, re);
3391 case Operator.Multiply:
3392 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3393 case Operator.RightShift:
3394 return SLE.Expression.RightShift (le, re);
3395 case Operator.Subtraction:
3396 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3398 throw new NotImplementedException (oper.ToString ());
3403 // D operator + (D x, D y)
3404 // D operator - (D x, D y)
3406 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3408 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3410 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3411 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3416 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3417 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3427 MethodSpec method = null;
3428 Arguments args = new Arguments (2);
3429 args.Add (new Argument (left));
3430 args.Add (new Argument (right));
3432 if (oper == Operator.Addition) {
3433 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3434 } else if (oper == Operator.Subtraction) {
3435 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3439 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3441 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
3442 return new ClassCast (expr, l);
3446 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
3448 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3451 // bool operator == (E x, E y);
3452 // bool operator != (E x, E y);
3453 // bool operator < (E x, E y);
3454 // bool operator > (E x, E y);
3455 // bool operator <= (E x, E y);
3456 // bool operator >= (E x, E y);
3458 // E operator & (E x, E y);
3459 // E operator | (E x, E y);
3460 // E operator ^ (E x, E y);
3463 if ((oper & Operator.ComparisonMask) != 0) {
3464 type = rc.BuiltinTypes.Bool;
3470 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3476 if (ltype == rtype) {
3480 var lifted = new Nullable.LiftedBinaryOperator (this);
3482 lifted.Right = right;
3483 return lifted.Resolve (rc);
3486 if (renum && !ltype.IsNullableType) {
3487 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
3492 } else if (lenum && !rtype.IsNullableType) {
3493 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
3501 // Now try lifted version of predefined operator
3503 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
3504 if (nullable_type != null) {
3505 if (renum && !ltype.IsNullableType) {
3506 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
3508 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3511 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3514 if ((oper & Operator.BitwiseMask) != 0)
3518 if ((oper & Operator.BitwiseMask) != 0)
3519 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3521 return CreateLiftedValueTypeResult (rc, rtype);
3525 var lifted = new Nullable.LiftedBinaryOperator (this);
3527 lifted.Right = right;
3528 return lifted.Resolve (rc);
3530 } else if (lenum && !rtype.IsNullableType) {
3531 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
3533 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3536 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3539 if ((oper & Operator.BitwiseMask) != 0)
3543 if ((oper & Operator.BitwiseMask) != 0)
3544 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3546 return CreateLiftedValueTypeResult (rc, ltype);
3550 var lifted = new Nullable.LiftedBinaryOperator (this);
3552 lifted.Right = expr;
3553 return lifted.Resolve (rc);
3555 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
3557 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3558 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
3560 if ((oper & Operator.RelationalMask) != 0)
3561 return CreateLiftedValueTypeResult (rc, rtype);
3563 if ((oper & Operator.BitwiseMask) != 0)
3564 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3566 // Equality operators are valid between E? and null
3569 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
3575 var lifted = new Nullable.LiftedBinaryOperator (this);
3577 lifted.Right = right;
3578 return lifted.Resolve (rc);
3580 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
3582 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3583 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
3585 if ((oper & Operator.RelationalMask) != 0)
3586 return CreateLiftedValueTypeResult (rc, ltype);
3588 if ((oper & Operator.BitwiseMask) != 0)
3589 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3591 // Equality operators are valid between E? and null
3594 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
3600 var lifted = new Nullable.LiftedBinaryOperator (this);
3602 lifted.Right = expr;
3603 return lifted.Resolve (rc);
3611 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr)
3613 TypeSpec underlying_type;
3614 if (expr.Type.IsNullableType) {
3615 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
3617 underlying_type = EnumSpec.GetUnderlyingType (nt);
3619 underlying_type = nt;
3620 } else if (expr.Type.IsEnum) {
3621 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
3623 underlying_type = expr.Type;
3626 switch (underlying_type.BuiltinType) {
3627 case BuiltinTypeSpec.Type.SByte:
3628 case BuiltinTypeSpec.Type.Byte:
3629 case BuiltinTypeSpec.Type.Short:
3630 case BuiltinTypeSpec.Type.UShort:
3631 underlying_type = rc.BuiltinTypes.Int;
3635 if (expr.Type.IsNullableType)
3636 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
3638 if (expr.Type == underlying_type)
3641 return EmptyCast.Create (expr, underlying_type);
3644 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3647 // U operator - (E e, E f)
3648 // E operator - (E e, U x) // Internal decomposition operator
3649 // E operator - (U x, E e) // Internal decomposition operator
3651 // E operator + (E e, U x)
3652 // E operator + (U x, E e)
3661 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3667 if (!enum_type.IsNullableType) {
3668 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
3670 if (oper == Operator.Subtraction)
3671 expr = ConvertEnumSubtractionResult (rc, expr);
3673 expr = ConvertEnumAdditionalResult (expr, enum_type);
3675 AddEnumResultCast (expr.Type);
3680 enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
3683 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
3685 if (oper == Operator.Subtraction)
3686 expr = ConvertEnumSubtractionResult (rc, expr);
3688 expr = ConvertEnumAdditionalResult (expr, enum_type);
3690 AddEnumResultCast (expr.Type);
3696 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
3698 return EmptyCast.Create (expr, enumType);
3701 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
3704 // Enumeration subtraction has different result type based on
3707 TypeSpec result_type;
3708 if (left.Type == right.Type) {
3709 var c = right as EnumConstant;
3710 if (c != null && c.IsZeroInteger) {
3712 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
3713 // E which is not what expressions E - 1 or 0 - E return
3715 result_type = left.Type;
3717 result_type = left.Type.IsNullableType ?
3718 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
3719 EnumSpec.GetUnderlyingType (left.Type);
3721 } else if (IsEnumOrNullableEnum (left.Type)) {
3722 result_type = left.Type;
3724 result_type = right.Type;
3727 return EmptyCast.Create (expr, result_type);
3730 void AddEnumResultCast (TypeSpec type)
3732 if (type.IsNullableType)
3733 type = Nullable.NullableInfo.GetUnderlyingType (type);
3736 type = EnumSpec.GetUnderlyingType (type);
3738 switch (type.BuiltinType) {
3739 case BuiltinTypeSpec.Type.SByte:
3740 enum_conversion = ConvCast.Mode.I4_I1;
3742 case BuiltinTypeSpec.Type.Byte:
3743 enum_conversion = ConvCast.Mode.I4_U1;
3745 case BuiltinTypeSpec.Type.Short:
3746 enum_conversion = ConvCast.Mode.I4_I2;
3748 case BuiltinTypeSpec.Type.UShort:
3749 enum_conversion = ConvCast.Mode.I4_U2;
3755 // Equality operators rules
3757 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
3760 type = ec.BuiltinTypes.Bool;
3761 bool no_arg_conv = false;
3763 if (!primitives_only) {
3766 // a, Both operands are reference-type values or the value null
3767 // b, One operand is a value of type T where T is a type-parameter and
3768 // the other operand is the value null. Furthermore T does not have the
3769 // value type constraint
3771 // LAMESPEC: Very confusing details in the specification, basically any
3772 // reference like type-parameter is allowed
3774 var tparam_l = l as TypeParameterSpec;
3775 var tparam_r = r as TypeParameterSpec;
3776 if (tparam_l != null) {
3777 if (right is NullLiteral) {
3778 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3781 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3785 if (!tparam_l.IsReferenceType)
3788 l = tparam_l.GetEffectiveBase ();
3789 left = new BoxedCast (left, l);
3790 } else if (left is NullLiteral && tparam_r == null) {
3791 if (TypeSpec.IsReferenceType (r))
3794 if (r.Kind == MemberKind.InternalCompilerType)
3798 if (tparam_r != null) {
3799 if (left is NullLiteral) {
3800 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3803 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3807 if (!tparam_r.IsReferenceType)
3810 r = tparam_r.GetEffectiveBase ();
3811 right = new BoxedCast (right, r);
3812 } else if (right is NullLiteral) {
3813 if (TypeSpec.IsReferenceType (l))
3816 if (l.Kind == MemberKind.InternalCompilerType)
3821 // LAMESPEC: method groups can be compared when they convert to other side delegate
3824 if (right.eclass == ExprClass.MethodGroup) {
3825 result = Convert.ImplicitConversion (ec, right, l, loc);
3831 } else if (r.IsDelegate && l != r) {
3834 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3835 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3842 no_arg_conv = l == r && !l.IsStruct;
3847 // bool operator != (string a, string b)
3848 // bool operator == (string a, string b)
3850 // bool operator != (Delegate a, Delegate b)
3851 // bool operator == (Delegate a, Delegate b)
3853 // bool operator != (bool a, bool b)
3854 // bool operator == (bool a, bool b)
3856 // LAMESPEC: Reference equality comparison can apply to value/reference types when
3857 // they implement an implicit conversion to any of types above. This does
3858 // not apply when both operands are of same reference type
3860 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3861 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
3866 // Now try lifted version of predefined operators
3868 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
3873 // The == and != operators permit one operand to be a value of a nullable
3874 // type and the other to be the null literal, even if no predefined or user-defined
3875 // operator (in unlifted or lifted form) exists for the operation.
3877 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
3878 var lifted = new Nullable.LiftedBinaryOperator (this);
3880 lifted.Right = right;
3881 return lifted.Resolve (ec);
3886 // bool operator != (object a, object b)
3887 // bool operator == (object a, object b)
3889 // An explicit reference conversion exists from the
3890 // type of either operand to the type of the other operand.
3893 // Optimize common path
3895 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3898 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3899 !Convert.ExplicitReferenceConversionExists (r, l))
3902 // Reject allowed explicit conversions like int->object
3903 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
3906 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3907 ec.Report.Warning (253, 2, loc,
3908 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3909 l.GetSignatureForError ());
3911 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3912 ec.Report.Warning (252, 2, loc,
3913 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3914 r.GetSignatureForError ());
3920 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3923 // bool operator == (void* x, void* y);
3924 // bool operator != (void* x, void* y);
3925 // bool operator < (void* x, void* y);
3926 // bool operator > (void* x, void* y);
3927 // bool operator <= (void* x, void* y);
3928 // bool operator >= (void* x, void* y);
3930 if ((oper & Operator.ComparisonMask) != 0) {
3933 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3940 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3946 type = ec.BuiltinTypes.Bool;
3950 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
3954 // Build-in operators method overloading
3956 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
3958 PredefinedOperator best_operator = null;
3959 TypeSpec l = left.Type;
3960 TypeSpec r = right.Type;
3961 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3963 foreach (PredefinedOperator po in operators) {
3964 if ((po.OperatorsMask & oper_mask) == 0)
3967 if (primitives_only) {
3968 if (!po.IsPrimitiveApplicable (l, r))
3971 if (!po.IsApplicable (ec, left, right))
3975 if (best_operator == null) {
3977 if (primitives_only)
3983 best_operator = po.ResolveBetterOperator (ec, best_operator);
3985 if (best_operator == null) {
3986 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3987 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
3994 if (best_operator == null)
3997 var expr = best_operator.ConvertResult (ec, this);
3999 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) && !best_operator.IsLifted) {
4000 expr = OptimizeAndOperation (expr);
4007 // Optimize &/&& constant expressions with 0 value
4009 Expression OptimizeAndOperation (Expression expr)
4011 Constant rc = right as Constant;
4012 Constant lc = left as Constant;
4013 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4015 // The result is a constant with side-effect
4017 Constant side_effect = rc == null ?
4018 new SideEffectConstant (lc, right, loc) :
4019 new SideEffectConstant (rc, left, loc);
4021 return ReducedExpression.Create (side_effect, expr);
4028 // Value types can be compared with the null literal because of the lifting
4029 // language rules. However the result is always true or false.
4031 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4033 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4034 type = rc.BuiltinTypes.Bool;
4038 // FIXME: Handle side effect constants
4039 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4041 if ((Oper & Operator.EqualityMask) != 0) {
4042 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4043 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4045 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4046 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4053 // Performs user-operator overloading
4055 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4057 Expression oper_expr;
4059 var op = ConvertBinaryToUserOperator (oper);
4061 if (l.IsNullableType)
4062 l = Nullable.NullableInfo.GetUnderlyingType (l);
4064 if (r.IsNullableType)
4065 r = Nullable.NullableInfo.GetUnderlyingType (r);
4067 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
4068 IList<MemberSpec> right_operators = null;
4071 right_operators = MemberCache.GetUserOperator (r, op, false);
4072 if (right_operators == null && left_operators == null)
4074 } else if (left_operators == null) {
4078 Arguments args = new Arguments (2);
4079 Argument larg = new Argument (left);
4081 Argument rarg = new Argument (right);
4085 // User-defined operator implementations always take precedence
4086 // over predefined operator implementations
4088 if (left_operators != null && right_operators != null) {
4089 left_operators = CombineUserOperators (left_operators, right_operators);
4090 } else if (right_operators != null) {
4091 left_operators = right_operators;
4094 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
4095 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
4097 var res = new OverloadResolver (left_operators, restr, loc);
4099 var oper_method = res.ResolveOperator (rc, ref args);
4100 if (oper_method == null) {
4102 // Logical && and || cannot be lifted
4104 if ((oper & Operator.LogicalMask) != 0)
4108 // Apply lifted user operators only for liftable types. Implicit conversion
4109 // to nullable types is not allowed
4111 if (!IsLiftedOperatorApplicable ())
4114 // TODO: Cache the result in module container
4115 var lifted_methods = CreateLiftedOperators (rc, left_operators);
4116 if (lifted_methods == null)
4119 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
4121 oper_method = res.ResolveOperator (rc, ref args);
4122 if (oper_method == null)
4125 MethodSpec best_original = null;
4126 foreach (MethodSpec ms in left_operators) {
4127 if (ms.MemberDefinition == oper_method.MemberDefinition) {
4133 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4135 // Expression trees use lifted notation in this case
4137 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
4138 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
4141 var ptypes = best_original.Parameters.Types;
4143 if (left.IsNull || right.IsNull) {
4145 // The lifted operator produces the value false if one or both operands are null for
4146 // relational operators.
4148 if ((oper & Operator.ComparisonMask) != 0) {
4150 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
4151 // because return type is actually bool
4153 // For some reason CSC does not report this warning for equality operators
4155 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
4158 // The lifted operator produces a null value if one or both operands are null
4160 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
4161 type = oper_method.ReturnType;
4162 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4166 type = oper_method.ReturnType;
4167 var lifted = new Nullable.LiftedBinaryOperator (this);
4168 lifted.UserOperator = best_original;
4170 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
4171 lifted.UnwrapLeft = new Nullable.Unwrap (left);
4174 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
4175 lifted.UnwrapRight = new Nullable.Unwrap (right);
4178 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
4179 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
4181 return lifted.Resolve (rc);
4184 if ((oper & Operator.LogicalMask) != 0) {
4185 // TODO: CreateExpressionTree is allocated every time
4186 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
4187 oper == Operator.LogicalAnd, loc).Resolve (rc);
4189 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
4192 this.left = larg.Expr;
4193 this.right = rarg.Expr;
4198 bool IsLiftedOperatorApplicable ()
4200 if (left.Type.IsNullableType) {
4201 if ((oper & Operator.EqualityMask) != 0)
4202 return !right.IsNull;
4207 if (right.Type.IsNullableType) {
4208 if ((oper & Operator.EqualityMask) != 0)
4209 return !left.IsNull;
4214 if (TypeSpec.IsValueType (left.Type))
4215 return right.IsNull;
4217 if (TypeSpec.IsValueType (right.Type))
4223 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
4225 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4226 if (nullable_type == null)
4230 // Lifted operators permit predefined and user-defined operators that operate
4231 // on non-nullable value types to also be used with nullable forms of those types.
4232 // Lifted operators are constructed from predefined and user-defined operators
4233 // that meet certain requirements
4235 List<MemberSpec> lifted = null;
4236 foreach (MethodSpec oper in operators) {
4238 if ((Oper & Operator.ComparisonMask) != 0) {
4240 // Result type must be of type bool for lifted comparison operators
4242 rt = oper.ReturnType;
4243 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
4246 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
4252 var ptypes = oper.Parameters.Types;
4253 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
4257 // LAMESPEC: I am not sure why but for equality operators to be lifted
4258 // both types have to match
4260 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
4264 lifted = new List<MemberSpec> ();
4267 // The lifted form is constructed by adding a single ? modifier to each operand and
4268 // result type except for comparison operators where return type is bool
4271 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
4273 var parameters = ParametersCompiled.CreateFullyResolved (
4274 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
4275 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
4277 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
4278 rt, parameters, oper.Modifiers);
4280 lifted.Add (lifted_op);
4287 // Merge two sets of user operators into one, they are mostly distinguish
4288 // except when they share base type and it contains an operator
4290 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
4292 var combined = new List<MemberSpec> (left.Count + right.Count);
4293 combined.AddRange (left);
4294 foreach (var r in right) {
4296 foreach (var l in left) {
4297 if (l.DeclaringType == r.DeclaringType) {
4310 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
4312 if (c is IntegralConstant || c is CharConstant) {
4314 c.ConvertExplicitly (true, type);
4315 } catch (OverflowException) {
4316 ec.Report.Warning (652, 2, loc,
4317 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
4318 type.GetSignatureForError ());
4324 /// EmitBranchable is called from Statement.EmitBoolExpression in the
4325 /// context of a conditional bool expression. This function will return
4326 /// false if it is was possible to use EmitBranchable, or true if it was.
4328 /// The expression's code is generated, and we will generate a branch to `target'
4329 /// if the resulting expression value is equal to isTrue
4331 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
4334 // This is more complicated than it looks, but its just to avoid
4335 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
4336 // but on top of that we want for == and != to use a special path
4337 // if we are comparing against null
4339 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
4340 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
4343 // put the constant on the rhs, for simplicity
4345 if (left is Constant) {
4346 Expression swap = right;
4352 // brtrue/brfalse works with native int only
4354 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
4355 left.EmitBranchable (ec, target, my_on_true);
4358 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
4359 // right is a boolean, and it's not 'false' => it is 'true'
4360 left.EmitBranchable (ec, target, !my_on_true);
4364 } else if (oper == Operator.LogicalAnd) {
4367 Label tests_end = ec.DefineLabel ();
4369 left.EmitBranchable (ec, tests_end, false);
4370 right.EmitBranchable (ec, target, true);
4371 ec.MarkLabel (tests_end);
4374 // This optimizes code like this
4375 // if (true && i > 4)
4377 if (!(left is Constant))
4378 left.EmitBranchable (ec, target, false);
4380 if (!(right is Constant))
4381 right.EmitBranchable (ec, target, false);
4386 } else if (oper == Operator.LogicalOr){
4388 left.EmitBranchable (ec, target, true);
4389 right.EmitBranchable (ec, target, true);
4392 Label tests_end = ec.DefineLabel ();
4393 left.EmitBranchable (ec, tests_end, true);
4394 right.EmitBranchable (ec, target, false);
4395 ec.MarkLabel (tests_end);
4400 } else if ((oper & Operator.ComparisonMask) == 0) {
4401 base.EmitBranchable (ec, target, on_true);
4408 TypeSpec t = left.Type;
4409 bool is_float = IsFloat (t);
4410 bool is_unsigned = is_float || IsUnsigned (t);
4413 case Operator.Equality:
4415 ec.Emit (OpCodes.Beq, target);
4417 ec.Emit (OpCodes.Bne_Un, target);
4420 case Operator.Inequality:
4422 ec.Emit (OpCodes.Bne_Un, target);
4424 ec.Emit (OpCodes.Beq, target);
4427 case Operator.LessThan:
4429 if (is_unsigned && !is_float)
4430 ec.Emit (OpCodes.Blt_Un, target);
4432 ec.Emit (OpCodes.Blt, target);
4435 ec.Emit (OpCodes.Bge_Un, target);
4437 ec.Emit (OpCodes.Bge, target);
4440 case Operator.GreaterThan:
4442 if (is_unsigned && !is_float)
4443 ec.Emit (OpCodes.Bgt_Un, target);
4445 ec.Emit (OpCodes.Bgt, target);
4448 ec.Emit (OpCodes.Ble_Un, target);
4450 ec.Emit (OpCodes.Ble, target);
4453 case Operator.LessThanOrEqual:
4455 if (is_unsigned && !is_float)
4456 ec.Emit (OpCodes.Ble_Un, target);
4458 ec.Emit (OpCodes.Ble, target);
4461 ec.Emit (OpCodes.Bgt_Un, target);
4463 ec.Emit (OpCodes.Bgt, target);
4467 case Operator.GreaterThanOrEqual:
4469 if (is_unsigned && !is_float)
4470 ec.Emit (OpCodes.Bge_Un, target);
4472 ec.Emit (OpCodes.Bge, target);
4475 ec.Emit (OpCodes.Blt_Un, target);
4477 ec.Emit (OpCodes.Blt, target);
4480 throw new InternalErrorException (oper.ToString ());
4484 public override void Emit (EmitContext ec)
4486 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4487 left = left.EmitToField (ec);
4489 if ((oper & Operator.LogicalMask) == 0) {
4490 right = right.EmitToField (ec);
4495 // Handle short-circuit operators differently
4498 if ((oper & Operator.LogicalMask) != 0) {
4499 Label load_result = ec.DefineLabel ();
4500 Label end = ec.DefineLabel ();
4502 bool is_or = oper == Operator.LogicalOr;
4503 left.EmitBranchable (ec, load_result, is_or);
4505 ec.Emit (OpCodes.Br_S, end);
4507 ec.MarkLabel (load_result);
4508 ec.EmitInt (is_or ? 1 : 0);
4514 // Optimize zero-based operations which cannot be optimized at expression level
4516 if (oper == Operator.Subtraction) {
4517 var lc = left as IntegralConstant;
4518 if (lc != null && lc.IsDefaultValue) {
4520 ec.Emit (OpCodes.Neg);
4525 EmitOperator (ec, left, right);
4528 public void EmitOperator (EmitContext ec, Expression left, Expression right)
4533 EmitOperatorOpcode (ec, oper, left.Type, right);
4536 // Emit result enumerable conversion this way because it's quite complicated get it
4537 // to resolved tree because expression tree cannot see it.
4539 if (enum_conversion != 0)
4540 ConvCast.Emit (ec, enum_conversion);
4543 public override void EmitSideEffect (EmitContext ec)
4545 if ((oper & Operator.LogicalMask) != 0 ||
4546 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
4547 base.EmitSideEffect (ec);
4549 left.EmitSideEffect (ec);
4550 right.EmitSideEffect (ec);
4554 public override Expression EmitToField (EmitContext ec)
4556 if ((oper & Operator.LogicalMask) == 0) {
4557 var await_expr = left as Await;
4558 if (await_expr != null && right.IsSideEffectFree) {
4559 await_expr.Statement.EmitPrologue (ec);
4560 left = await_expr.Statement.GetResultExpression (ec);
4564 await_expr = right as Await;
4565 if (await_expr != null && left.IsSideEffectFree) {
4566 await_expr.Statement.EmitPrologue (ec);
4567 right = await_expr.Statement.GetResultExpression (ec);
4572 return base.EmitToField (ec);
4575 protected override void CloneTo (CloneContext clonectx, Expression t)
4577 Binary target = (Binary) t;
4579 target.left = left.Clone (clonectx);
4580 target.right = right.Clone (clonectx);
4583 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
4585 Arguments binder_args = new Arguments (4);
4587 MemberAccess sle = new MemberAccess (new MemberAccess (
4588 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
4590 CSharpBinderFlags flags = 0;
4591 if (ec.HasSet (ResolveContext.Options.CheckedScope))
4592 flags = CSharpBinderFlags.CheckedContext;
4594 if ((oper & Operator.LogicalMask) != 0)
4595 flags |= CSharpBinderFlags.BinaryOperationLogical;
4597 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
4598 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
4599 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
4600 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
4602 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
4605 public override Expression CreateExpressionTree (ResolveContext ec)
4607 return CreateExpressionTree (ec, null);
4610 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
4613 bool lift_arg = false;
4616 case Operator.Addition:
4617 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4618 method_name = "AddChecked";
4620 method_name = "Add";
4622 case Operator.BitwiseAnd:
4623 method_name = "And";
4625 case Operator.BitwiseOr:
4628 case Operator.Division:
4629 method_name = "Divide";
4631 case Operator.Equality:
4632 method_name = "Equal";
4635 case Operator.ExclusiveOr:
4636 method_name = "ExclusiveOr";
4638 case Operator.GreaterThan:
4639 method_name = "GreaterThan";
4642 case Operator.GreaterThanOrEqual:
4643 method_name = "GreaterThanOrEqual";
4646 case Operator.Inequality:
4647 method_name = "NotEqual";
4650 case Operator.LeftShift:
4651 method_name = "LeftShift";
4653 case Operator.LessThan:
4654 method_name = "LessThan";
4657 case Operator.LessThanOrEqual:
4658 method_name = "LessThanOrEqual";
4661 case Operator.LogicalAnd:
4662 method_name = "AndAlso";
4664 case Operator.LogicalOr:
4665 method_name = "OrElse";
4667 case Operator.Modulus:
4668 method_name = "Modulo";
4670 case Operator.Multiply:
4671 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4672 method_name = "MultiplyChecked";
4674 method_name = "Multiply";
4676 case Operator.RightShift:
4677 method_name = "RightShift";
4679 case Operator.Subtraction:
4680 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4681 method_name = "SubtractChecked";
4683 method_name = "Subtract";
4687 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4690 Arguments args = new Arguments (2);
4691 args.Add (new Argument (left.CreateExpressionTree (ec)));
4692 args.Add (new Argument (right.CreateExpressionTree (ec)));
4693 if (method != null) {
4695 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4697 args.Add (new Argument (method));
4700 return CreateExpressionFactoryCall (ec, method_name, args);
4703 public override object Accept (StructuralVisitor visitor)
4705 return visitor.Visit (this);
4711 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4712 // b, c, d... may be strings or objects.
4714 public class StringConcat : Expression
4716 Arguments arguments;
4718 StringConcat (Location loc)
4721 arguments = new Arguments (2);
4724 public override bool ContainsEmitWithAwait ()
4726 return arguments.ContainsEmitWithAwait ();
4729 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4731 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4732 throw new ArgumentException ();
4734 var s = new StringConcat (loc);
4735 s.type = rc.BuiltinTypes.String;
4736 s.eclass = ExprClass.Value;
4738 s.Append (rc, left);
4739 s.Append (rc, right);
4743 public override Expression CreateExpressionTree (ResolveContext ec)
4745 Argument arg = arguments [0];
4746 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4750 // Creates nested calls tree from an array of arguments used for IL emit
4752 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4754 Arguments concat_args = new Arguments (2);
4755 Arguments add_args = new Arguments (3);
4757 concat_args.Add (left);
4758 add_args.Add (new Argument (left_etree));
4760 concat_args.Add (arguments [pos]);
4761 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4763 var methods = GetConcatMethodCandidates ();
4764 if (methods == null)
4767 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4768 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4772 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4774 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4775 if (++pos == arguments.Count)
4778 left = new Argument (new EmptyExpression (method.ReturnType));
4779 return CreateExpressionAddCall (ec, left, expr, pos);
4782 protected override Expression DoResolve (ResolveContext ec)
4787 void Append (ResolveContext rc, Expression operand)
4792 StringConstant sc = operand as StringConstant;
4794 if (arguments.Count != 0) {
4795 Argument last_argument = arguments [arguments.Count - 1];
4796 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4797 if (last_expr_constant != null) {
4798 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4804 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4806 StringConcat concat_oper = operand as StringConcat;
4807 if (concat_oper != null) {
4808 arguments.AddRange (concat_oper.arguments);
4813 arguments.Add (new Argument (operand));
4816 IList<MemberSpec> GetConcatMethodCandidates ()
4818 return MemberCache.FindMembers (type, "Concat", true);
4821 public override void Emit (EmitContext ec)
4823 // Optimize by removing any extra null arguments, they are no-op
4824 for (int i = 0; i < arguments.Count; ++i) {
4825 if (arguments[i].Expr is NullConstant)
4826 arguments.RemoveAt (i--);
4829 var members = GetConcatMethodCandidates ();
4830 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4831 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4832 if (method != null) {
4833 var call = new CallEmitter ();
4834 call.EmitPredefined (ec, method, arguments);
4838 public override SLE.Expression MakeExpression (BuilderContext ctx)
4840 if (arguments.Count != 2)
4841 throw new NotImplementedException ("arguments.Count != 2");
4843 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4844 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4849 // User-defined conditional logical operator
4851 public class ConditionalLogicalOperator : UserOperatorCall
4853 readonly bool is_and;
4854 Expression oper_expr;
4856 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4857 : base (oper, arguments, expr_tree, loc)
4859 this.is_and = is_and;
4860 eclass = ExprClass.Unresolved;
4863 protected override Expression DoResolve (ResolveContext ec)
4865 AParametersCollection pd = oper.Parameters;
4866 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4867 ec.Report.Error (217, loc,
4868 "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",
4869 oper.GetSignatureForError ());
4873 Expression left_dup = new EmptyExpression (type);
4874 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4875 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4876 if (op_true == null || op_false == null) {
4877 ec.Report.Error (218, loc,
4878 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4879 type.GetSignatureForError (), oper.GetSignatureForError ());
4883 oper_expr = is_and ? op_false : op_true;
4884 eclass = ExprClass.Value;
4888 public override void Emit (EmitContext ec)
4890 Label end_target = ec.DefineLabel ();
4893 // Emit and duplicate left argument
4895 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
4896 if (right_contains_await) {
4897 arguments[0] = arguments[0].EmitToField (ec, false);
4898 arguments[0].Expr.Emit (ec);
4900 arguments[0].Expr.Emit (ec);
4901 ec.Emit (OpCodes.Dup);
4902 arguments.RemoveAt (0);
4905 oper_expr.EmitBranchable (ec, end_target, true);
4909 if (right_contains_await) {
4911 // Special handling when right expression contains await and left argument
4912 // could not be left on stack before logical branch
4914 Label skip_left_load = ec.DefineLabel ();
4915 ec.Emit (OpCodes.Br_S, skip_left_load);
4916 ec.MarkLabel (end_target);
4917 arguments[0].Expr.Emit (ec);
4918 ec.MarkLabel (skip_left_load);
4920 ec.MarkLabel (end_target);
4925 public class PointerArithmetic : Expression {
4926 Expression left, right;
4930 // We assume that `l' is always a pointer
4932 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4941 public override bool ContainsEmitWithAwait ()
4943 throw new NotImplementedException ();
4946 public override Expression CreateExpressionTree (ResolveContext ec)
4948 Error_PointerInsideExpressionTree (ec);
4952 protected override Expression DoResolve (ResolveContext ec)
4954 eclass = ExprClass.Variable;
4956 var pc = left.Type as PointerContainer;
4957 if (pc != null && pc.Element.Kind == MemberKind.Void) {
4958 Error_VoidPointerOperation (ec);
4965 public override void Emit (EmitContext ec)
4967 TypeSpec op_type = left.Type;
4969 // It must be either array or fixed buffer
4971 if (TypeManager.HasElementType (op_type)) {
4972 element = TypeManager.GetElementType (op_type);
4974 FieldExpr fe = left as FieldExpr;
4976 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
4981 int size = BuiltinTypeSpec.GetSize(element);
4982 TypeSpec rtype = right.Type;
4984 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4986 // handle (pointer - pointer)
4990 ec.Emit (OpCodes.Sub);
4994 ec.Emit (OpCodes.Sizeof, element);
4997 ec.Emit (OpCodes.Div);
4999 ec.Emit (OpCodes.Conv_I8);
5002 // handle + and - on (pointer op int)
5004 Constant left_const = left as Constant;
5005 if (left_const != null) {
5007 // Optimize ((T*)null) pointer operations
5009 if (left_const.IsDefaultValue) {
5010 left = EmptyExpression.Null;
5018 var right_const = right as Constant;
5019 if (right_const != null) {
5021 // Optimize 0-based arithmetic
5023 if (right_const.IsDefaultValue)
5027 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5029 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5031 // TODO: Should be the checks resolve context sensitive?
5032 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5033 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5039 switch (rtype.BuiltinType) {
5040 case BuiltinTypeSpec.Type.SByte:
5041 case BuiltinTypeSpec.Type.Byte:
5042 case BuiltinTypeSpec.Type.Short:
5043 case BuiltinTypeSpec.Type.UShort:
5044 ec.Emit (OpCodes.Conv_I);
5046 case BuiltinTypeSpec.Type.UInt:
5047 ec.Emit (OpCodes.Conv_U);
5051 if (right_const == null && size != 1){
5053 ec.Emit (OpCodes.Sizeof, element);
5056 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5057 ec.Emit (OpCodes.Conv_I8);
5059 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
5062 if (left_const == null) {
5063 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
5064 ec.Emit (OpCodes.Conv_I);
5065 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5066 ec.Emit (OpCodes.Conv_U);
5068 Binary.EmitOperatorOpcode (ec, op, op_type, right);
5075 // A boolean-expression is an expression that yields a result
5078 public class BooleanExpression : ShimExpression
5080 public BooleanExpression (Expression expr)
5083 this.loc = expr.Location;
5086 public override Expression CreateExpressionTree (ResolveContext ec)
5088 // TODO: We should emit IsTrue (v4) instead of direct user operator
5089 // call but that would break csc compatibility
5090 return base.CreateExpressionTree (ec);
5093 protected override Expression DoResolve (ResolveContext ec)
5095 // A boolean-expression is required to be of a type
5096 // that can be implicitly converted to bool or of
5097 // a type that implements operator true
5099 expr = expr.Resolve (ec);
5103 Assign ass = expr as Assign;
5104 if (ass != null && ass.Source is Constant) {
5105 ec.Report.Warning (665, 3, loc,
5106 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
5109 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
5112 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5113 Arguments args = new Arguments (1);
5114 args.Add (new Argument (expr));
5115 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
5118 type = ec.BuiltinTypes.Bool;
5119 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
5120 if (converted != null)
5124 // If no implicit conversion to bool exists, try using `operator true'
5126 converted = GetOperatorTrue (ec, expr, loc);
5127 if (converted == null) {
5128 expr.Error_ValueCannotBeConverted (ec, type, false);
5135 public override object Accept (StructuralVisitor visitor)
5137 return visitor.Visit (this);
5141 public class BooleanExpressionFalse : Unary
5143 public BooleanExpressionFalse (Expression expr)
5144 : base (Operator.LogicalNot, expr, expr.Location)
5148 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
5150 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
5155 /// Implements the ternary conditional operator (?:)
5157 public class Conditional : Expression {
5158 Expression expr, true_expr, false_expr;
5160 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
5163 this.true_expr = true_expr;
5164 this.false_expr = false_expr;
5170 public Expression Expr {
5176 public Expression TrueExpr {
5182 public Expression FalseExpr {
5190 public override bool ContainsEmitWithAwait ()
5192 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
5195 public override Expression CreateExpressionTree (ResolveContext ec)
5197 Arguments args = new Arguments (3);
5198 args.Add (new Argument (expr.CreateExpressionTree (ec)));
5199 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
5200 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
5201 return CreateExpressionFactoryCall (ec, "Condition", args);
5204 protected override Expression DoResolve (ResolveContext ec)
5206 expr = expr.Resolve (ec);
5209 // Unreachable code needs different resolve path. For instance for await
5210 // expression to not generate unreachable resumable statement
5212 Constant c = expr as Constant;
5213 if (c != null && ec.CurrentBranching != null) {
5214 bool unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
5216 if (c.IsDefaultValue) {
5217 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
5218 true_expr = true_expr.Resolve (ec);
5219 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
5221 false_expr = false_expr.Resolve (ec);
5223 true_expr = true_expr.Resolve (ec);
5225 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
5226 false_expr = false_expr.Resolve (ec);
5227 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
5230 true_expr = true_expr.Resolve (ec);
5231 false_expr = false_expr.Resolve (ec);
5234 if (true_expr == null || false_expr == null || expr == null)
5237 eclass = ExprClass.Value;
5238 TypeSpec true_type = true_expr.Type;
5239 TypeSpec false_type = false_expr.Type;
5243 // First, if an implicit conversion exists from true_expr
5244 // to false_expr, then the result type is of type false_expr.Type
5246 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
5247 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
5248 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5250 // Check if both can convert implicitly to each other's type
5254 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5255 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
5257 // LAMESPEC: There seems to be hardcoded promotition to int type when
5258 // both sides are numeric constants and one side is int constant and
5259 // other side is numeric constant convertible to int.
5261 // var res = condition ? (short)1 : 1;
5263 // Type of res is int even if according to the spec the conversion is
5264 // ambiguous because 1 literal can be converted to short.
5266 if (conv_false_expr != null) {
5267 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
5269 conv_false_expr = null;
5270 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
5271 conv_false_expr = null;
5275 if (conv_false_expr != null) {
5276 ec.Report.Error (172, true_expr.Location,
5277 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
5278 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5283 if (true_expr.Type != type)
5284 true_expr = EmptyCast.Create (true_expr, type);
5285 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
5288 ec.Report.Error (173, true_expr.Location,
5289 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
5290 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5296 bool is_false = c.IsDefaultValue;
5299 // Don't issue the warning for constant expressions
5301 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
5302 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location,
5303 "Unreachable expression code detected");
5306 return ReducedExpression.Create (
5307 is_false ? false_expr : true_expr, this,
5308 false_expr is Constant && true_expr is Constant).Resolve (ec);
5314 public override void Emit (EmitContext ec)
5316 Label false_target = ec.DefineLabel ();
5317 Label end_target = ec.DefineLabel ();
5319 expr.EmitBranchable (ec, false_target, false);
5320 true_expr.Emit (ec);
5323 // Verifier doesn't support interface merging. When there are two types on
5324 // the stack without common type hint and the common type is an interface.
5325 // Use temporary local to give verifier hint on what type to unify the stack
5327 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
5328 var temp = ec.GetTemporaryLocal (type);
5329 ec.Emit (OpCodes.Stloc, temp);
5330 ec.Emit (OpCodes.Ldloc, temp);
5331 ec.FreeTemporaryLocal (temp, type);
5334 ec.Emit (OpCodes.Br, end_target);
5335 ec.MarkLabel (false_target);
5336 false_expr.Emit (ec);
5337 ec.MarkLabel (end_target);
5340 protected override void CloneTo (CloneContext clonectx, Expression t)
5342 Conditional target = (Conditional) t;
5344 target.expr = expr.Clone (clonectx);
5345 target.true_expr = true_expr.Clone (clonectx);
5346 target.false_expr = false_expr.Clone (clonectx);
5350 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
5352 LocalTemporary temp;
5355 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
5356 public abstract void SetHasAddressTaken ();
5357 public abstract void VerifyAssigned (ResolveContext rc);
5359 public abstract bool IsLockedByStatement { get; set; }
5361 public abstract bool IsFixed { get; }
5362 public abstract bool IsRef { get; }
5363 public abstract string Name { get; }
5366 // Variable IL data, it has to be protected to encapsulate hoisted variables
5368 protected abstract ILocalVariable Variable { get; }
5371 // Variable flow-analysis data
5373 public abstract VariableInfo VariableInfo { get; }
5376 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5378 HoistedVariable hv = GetHoistedVariable (ec);
5380 hv.AddressOf (ec, mode);
5384 Variable.EmitAddressOf (ec);
5387 public override bool ContainsEmitWithAwait ()
5392 public override Expression CreateExpressionTree (ResolveContext ec)
5394 HoistedVariable hv = GetHoistedVariable (ec);
5396 return hv.CreateExpressionTree ();
5398 Arguments arg = new Arguments (1);
5399 arg.Add (new Argument (this));
5400 return CreateExpressionFactoryCall (ec, "Constant", arg);
5403 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
5405 if (IsLockedByStatement) {
5406 rc.Report.Warning (728, 2, loc,
5407 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
5414 public override void Emit (EmitContext ec)
5419 public override void EmitSideEffect (EmitContext ec)
5425 // This method is used by parameters that are references, that are
5426 // being passed as references: we only want to pass the pointer (that
5427 // is already stored in the parameter, not the address of the pointer,
5428 // and not the value of the variable).
5430 public void EmitLoad (EmitContext ec)
5435 public void Emit (EmitContext ec, bool leave_copy)
5437 HoistedVariable hv = GetHoistedVariable (ec);
5439 hv.Emit (ec, leave_copy);
5447 // If we are a reference, we loaded on the stack a pointer
5448 // Now lets load the real value
5450 ec.EmitLoadFromPtr (type);
5454 ec.Emit (OpCodes.Dup);
5457 temp = new LocalTemporary (Type);
5463 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
5464 bool prepare_for_load)
5466 HoistedVariable hv = GetHoistedVariable (ec);
5468 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
5472 New n_source = source as New;
5473 if (n_source != null) {
5474 if (!n_source.Emit (ec, this)) {
5478 ec.EmitLoadFromPtr (type);
5490 ec.Emit (OpCodes.Dup);
5492 temp = new LocalTemporary (Type);
5498 ec.EmitStoreFromPtr (type);
5500 Variable.EmitAssign (ec);
5508 public override Expression EmitToField (EmitContext ec)
5510 HoistedVariable hv = GetHoistedVariable (ec);
5512 return hv.EmitToField (ec);
5515 return base.EmitToField (ec);
5518 public HoistedVariable GetHoistedVariable (ResolveContext rc)
5520 return GetHoistedVariable (rc.CurrentAnonymousMethod);
5523 public HoistedVariable GetHoistedVariable (EmitContext ec)
5525 return GetHoistedVariable (ec.CurrentAnonymousMethod);
5528 public override string GetSignatureForError ()
5533 public bool IsHoisted {
5534 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
5539 // Resolved reference to a local variable
5541 public class LocalVariableReference : VariableReference
5543 public LocalVariable local_info;
5545 public LocalVariableReference (LocalVariable li, Location l)
5547 this.local_info = li;
5551 public override VariableInfo VariableInfo {
5552 get { return local_info.VariableInfo; }
5555 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5557 return local_info.HoistedVariant;
5563 // A local variable is always fixed
5565 public override bool IsFixed {
5571 public override bool IsLockedByStatement {
5573 return local_info.IsLocked;
5576 local_info.IsLocked = value;
5580 public override bool IsRef {
5581 get { return false; }
5584 public override string Name {
5585 get { return local_info.Name; }
5590 public override void VerifyAssigned (ResolveContext rc)
5592 VariableInfo variable_info = local_info.VariableInfo;
5593 if (variable_info == null)
5596 if (variable_info.IsAssigned (rc))
5599 rc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
5600 variable_info.SetAssigned (rc);
5603 public override void SetHasAddressTaken ()
5605 local_info.SetHasAddressTaken ();
5608 void DoResolveBase (ResolveContext ec)
5611 // If we are referencing a variable from the external block
5612 // flag it for capturing
5614 if (ec.MustCaptureVariable (local_info)) {
5615 if (local_info.AddressTaken) {
5616 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5617 } else if (local_info.IsFixed) {
5618 ec.Report.Error (1764, loc,
5619 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
5620 GetSignatureForError ());
5623 if (ec.IsVariableCapturingRequired) {
5624 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
5625 storey.CaptureLocalVariable (ec, local_info);
5629 eclass = ExprClass.Variable;
5630 type = local_info.Type;
5633 protected override Expression DoResolve (ResolveContext ec)
5635 local_info.SetIsUsed ();
5637 VerifyAssigned (ec);
5643 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5646 // Don't be too pedantic when variable is used as out param or for some broken code
5647 // which uses property/indexer access to run some initialization
5649 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5650 local_info.SetIsUsed ();
5652 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5655 if (rhs == EmptyExpression.OutAccess) {
5656 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5657 } else if (rhs == EmptyExpression.LValueMemberAccess) {
5658 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
5659 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5660 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5661 } else if (rhs == EmptyExpression.UnaryAddress) {
5662 code = 459; msg = "Cannot take the address of {1} `{0}'";
5664 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5666 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5667 } else if (VariableInfo != null) {
5668 VariableInfo.SetAssigned (ec);
5671 if (eclass == ExprClass.Unresolved)
5674 return base.DoResolveLValue (ec, rhs);
5677 public override int GetHashCode ()
5679 return local_info.GetHashCode ();
5682 public override bool Equals (object obj)
5684 LocalVariableReference lvr = obj as LocalVariableReference;
5688 return local_info == lvr.local_info;
5691 protected override ILocalVariable Variable {
5692 get { return local_info; }
5695 public override string ToString ()
5697 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5700 protected override void CloneTo (CloneContext clonectx, Expression t)
5707 /// This represents a reference to a parameter in the intermediate
5710 public class ParameterReference : VariableReference
5712 protected ParametersBlock.ParameterInfo pi;
5714 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5722 public override bool IsLockedByStatement {
5727 pi.IsLocked = value;
5731 public override bool IsRef {
5732 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5735 bool HasOutModifier {
5736 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5739 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5741 return pi.Parameter.HoistedVariant;
5745 // A ref or out parameter is classified as a moveable variable, even
5746 // if the argument given for the parameter is a fixed variable
5748 public override bool IsFixed {
5749 get { return !IsRef; }
5752 public override string Name {
5753 get { return Parameter.Name; }
5756 public Parameter Parameter {
5757 get { return pi.Parameter; }
5760 public override VariableInfo VariableInfo {
5761 get { return pi.VariableInfo; }
5764 protected override ILocalVariable Variable {
5765 get { return Parameter; }
5770 public override void AddressOf (EmitContext ec, AddressOp mode)
5773 // ParameterReferences might already be a reference
5780 base.AddressOf (ec, mode);
5783 public override void SetHasAddressTaken ()
5785 Parameter.HasAddressTaken = true;
5788 void SetAssigned (ResolveContext ec)
5790 if (Parameter.HoistedVariant != null)
5791 Parameter.HoistedVariant.IsAssigned = true;
5793 if (HasOutModifier && ec.DoFlowAnalysis)
5794 ec.CurrentBranching.SetAssigned (VariableInfo);
5797 bool DoResolveBase (ResolveContext ec)
5799 if (eclass != ExprClass.Unresolved)
5802 type = pi.ParameterType;
5803 eclass = ExprClass.Variable;
5806 // If we are referencing a parameter from the external block
5807 // flag it for capturing
5809 if (ec.MustCaptureVariable (pi)) {
5810 if (Parameter.HasAddressTaken)
5811 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5814 ec.Report.Error (1628, loc,
5815 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5816 Name, ec.CurrentAnonymousMethod.ContainerType);
5819 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5820 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5821 storey.CaptureParameter (ec, pi, this);
5828 public override int GetHashCode ()
5830 return Name.GetHashCode ();
5833 public override bool Equals (object obj)
5835 ParameterReference pr = obj as ParameterReference;
5839 return Name == pr.Name;
5842 protected override void CloneTo (CloneContext clonectx, Expression target)
5848 public override Expression CreateExpressionTree (ResolveContext ec)
5850 HoistedVariable hv = GetHoistedVariable (ec);
5852 return hv.CreateExpressionTree ();
5854 return Parameter.ExpressionTreeVariableReference ();
5858 // Notice that for ref/out parameters, the type exposed is not the
5859 // same type exposed externally.
5862 // externally we expose "int&"
5863 // here we expose "int".
5865 // We record this in "is_ref". This means that the type system can treat
5866 // the type as it is expected, but when we generate the code, we generate
5867 // the alternate kind of code.
5869 protected override Expression DoResolve (ResolveContext ec)
5871 if (!DoResolveBase (ec))
5874 VerifyAssigned (ec);
5878 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5880 if (!DoResolveBase (ec))
5884 return base.DoResolveLValue (ec, right_side);
5887 public override void VerifyAssigned (ResolveContext rc)
5889 // HACK: Variables are not captured in probing mode
5890 if (rc.IsInProbingMode)
5893 if (HasOutModifier && !VariableInfo.IsAssigned (rc)) {
5894 rc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
5900 /// Invocation of methods or delegates.
5902 public class Invocation : ExpressionStatement
5904 protected Arguments arguments;
5905 protected Expression expr;
5906 protected MethodGroupExpr mg;
5908 public Invocation (Expression expr, Arguments arguments)
5911 this.arguments = arguments;
5913 loc = expr.Location;
5918 public Arguments Arguments {
5924 public Expression Exp {
5930 public MethodGroupExpr MethodGroup {
5936 public override Location StartLocation {
5938 return expr.StartLocation;
5944 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
5946 if (MethodGroup == null)
5949 var candidate = MethodGroup.BestCandidate;
5950 if (candidate == null || !(candidate.IsStatic || Exp is This))
5953 var args_count = arguments == null ? 0 : arguments.Count;
5954 if (args_count != body.Parameters.Count)
5957 var lambda_parameters = body.Block.Parameters.FixedParameters;
5958 for (int i = 0; i < args_count; ++i) {
5959 var pr = arguments[i].Expr as ParameterReference;
5963 if (lambda_parameters[i] != pr.Parameter)
5966 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
5970 var emg = MethodGroup as ExtensionMethodGroupExpr;
5972 return MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
5978 protected override void CloneTo (CloneContext clonectx, Expression t)
5980 Invocation target = (Invocation) t;
5982 if (arguments != null)
5983 target.arguments = arguments.Clone (clonectx);
5985 target.expr = expr.Clone (clonectx);
5988 public override bool ContainsEmitWithAwait ()
5990 if (arguments != null && arguments.ContainsEmitWithAwait ())
5993 return mg.ContainsEmitWithAwait ();
5996 public override Expression CreateExpressionTree (ResolveContext ec)
5998 Expression instance = mg.IsInstance ?
5999 mg.InstanceExpression.CreateExpressionTree (ec) :
6000 new NullLiteral (loc);
6002 var args = Arguments.CreateForExpressionTree (ec, arguments,
6004 mg.CreateExpressionTree (ec));
6006 return CreateExpressionFactoryCall (ec, "Call", args);
6009 protected override Expression DoResolve (ResolveContext ec)
6011 Expression member_expr;
6012 var atn = expr as ATypeNameExpression;
6014 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
6015 if (member_expr != null)
6016 member_expr = member_expr.Resolve (ec);
6018 member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
6021 if (member_expr == null)
6025 // Next, evaluate all the expressions in the argument list
6027 bool dynamic_arg = false;
6028 if (arguments != null)
6029 arguments.Resolve (ec, out dynamic_arg);
6031 TypeSpec expr_type = member_expr.Type;
6032 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6033 return DoResolveDynamic (ec, member_expr);
6035 mg = member_expr as MethodGroupExpr;
6036 Expression invoke = null;
6039 if (expr_type != null && expr_type.IsDelegate) {
6040 invoke = new DelegateInvocation (member_expr, arguments, loc);
6041 invoke = invoke.Resolve (ec);
6042 if (invoke == null || !dynamic_arg)
6045 if (member_expr is RuntimeValueExpression) {
6046 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
6047 member_expr.Type.GetSignatureForError ()); ;
6051 MemberExpr me = member_expr as MemberExpr;
6053 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
6057 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
6058 member_expr.GetSignatureForError ());
6063 if (invoke == null) {
6064 mg = DoResolveOverload (ec);
6070 return DoResolveDynamic (ec, member_expr);
6072 var method = mg.BestCandidate;
6073 type = mg.BestCandidateReturnType;
6075 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
6077 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
6079 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
6083 IsSpecialMethodInvocation (ec, method, loc);
6085 eclass = ExprClass.Value;
6089 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
6092 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
6094 args = dmb.Arguments;
6095 if (arguments != null)
6096 args.AddRange (arguments);
6097 } else if (mg == null) {
6098 if (arguments == null)
6099 args = new Arguments (1);
6103 args.Insert (0, new Argument (memberExpr));
6107 ec.Report.Error (1971, loc,
6108 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
6113 if (arguments == null)
6114 args = new Arguments (1);
6118 MemberAccess ma = expr as MemberAccess;
6120 var left_type = ma.LeftExpression as TypeExpr;
6121 if (left_type != null) {
6122 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6125 // Any value type has to be pass as by-ref to get back the same
6126 // instance on which the member was called
6128 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
6129 Argument.AType.Ref : Argument.AType.None;
6130 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
6132 } else { // is SimpleName
6134 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6136 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
6141 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
6144 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
6146 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
6149 public override string GetSignatureForError ()
6151 return mg.GetSignatureForError ();
6155 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
6156 // or the type dynamic, then the member is invocable
6158 public static bool IsMemberInvocable (MemberSpec member)
6160 switch (member.Kind) {
6161 case MemberKind.Event:
6163 case MemberKind.Field:
6164 case MemberKind.Property:
6165 var m = member as IInterfaceMemberSpec;
6166 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
6172 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
6174 if (!method.IsReservedMethod)
6177 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
6180 ec.Report.SymbolRelatedToPreviousError (method);
6181 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
6182 method.GetSignatureForError ());
6187 public override void Emit (EmitContext ec)
6189 mg.EmitCall (ec, arguments);
6192 public override void EmitStatement (EmitContext ec)
6197 // Pop the return value if there is one
6199 if (type.Kind != MemberKind.Void)
6200 ec.Emit (OpCodes.Pop);
6203 public override SLE.Expression MakeExpression (BuilderContext ctx)
6205 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
6208 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
6211 throw new NotSupportedException ();
6213 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
6214 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
6218 public override object Accept (StructuralVisitor visitor)
6220 return visitor.Visit (this);
6225 // Implements simple new expression
6227 public class New : ExpressionStatement, IMemoryLocation
6229 protected Arguments arguments;
6232 // During bootstrap, it contains the RequestedType,
6233 // but if `type' is not null, it *might* contain a NewDelegate
6234 // (because of field multi-initialization)
6236 protected Expression RequestedType;
6238 protected MethodSpec method;
6240 public New (Expression requested_type, Arguments arguments, Location l)
6242 RequestedType = requested_type;
6243 this.arguments = arguments;
6248 public Arguments Arguments {
6255 // Returns true for resolved `new S()'
6257 public bool IsDefaultStruct {
6259 return arguments == null && type.IsStruct && GetType () == typeof (New);
6263 public Expression TypeExpression {
6265 return RequestedType;
6272 /// Converts complex core type syntax like 'new int ()' to simple constant
6274 public static Constant Constantify (TypeSpec t, Location loc)
6276 switch (t.BuiltinType) {
6277 case BuiltinTypeSpec.Type.Int:
6278 return new IntConstant (t, 0, loc);
6279 case BuiltinTypeSpec.Type.UInt:
6280 return new UIntConstant (t, 0, loc);
6281 case BuiltinTypeSpec.Type.Long:
6282 return new LongConstant (t, 0, loc);
6283 case BuiltinTypeSpec.Type.ULong:
6284 return new ULongConstant (t, 0, loc);
6285 case BuiltinTypeSpec.Type.Float:
6286 return new FloatConstant (t, 0, loc);
6287 case BuiltinTypeSpec.Type.Double:
6288 return new DoubleConstant (t, 0, loc);
6289 case BuiltinTypeSpec.Type.Short:
6290 return new ShortConstant (t, 0, loc);
6291 case BuiltinTypeSpec.Type.UShort:
6292 return new UShortConstant (t, 0, loc);
6293 case BuiltinTypeSpec.Type.SByte:
6294 return new SByteConstant (t, 0, loc);
6295 case BuiltinTypeSpec.Type.Byte:
6296 return new ByteConstant (t, 0, loc);
6297 case BuiltinTypeSpec.Type.Char:
6298 return new CharConstant (t, '\0', loc);
6299 case BuiltinTypeSpec.Type.Bool:
6300 return new BoolConstant (t, false, loc);
6301 case BuiltinTypeSpec.Type.Decimal:
6302 return new DecimalConstant (t, 0, loc);
6306 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
6308 if (t.IsNullableType)
6309 return Nullable.LiftedNull.Create (t, loc);
6314 public override bool ContainsEmitWithAwait ()
6316 return arguments != null && arguments.ContainsEmitWithAwait ();
6320 // Checks whether the type is an interface that has the
6321 // [ComImport, CoClass] attributes and must be treated
6324 public Expression CheckComImport (ResolveContext ec)
6326 if (!type.IsInterface)
6330 // Turn the call into:
6331 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
6333 var real_class = type.MemberDefinition.GetAttributeCoClass ();
6334 if (real_class == null)
6337 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
6338 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
6339 return cast.Resolve (ec);
6342 public override Expression CreateExpressionTree (ResolveContext ec)
6345 if (method == null) {
6346 args = new Arguments (1);
6347 args.Add (new Argument (new TypeOf (type, loc)));
6349 args = Arguments.CreateForExpressionTree (ec,
6350 arguments, new TypeOfMethod (method, loc));
6353 return CreateExpressionFactoryCall (ec, "New", args);
6356 protected override Expression DoResolve (ResolveContext ec)
6358 type = RequestedType.ResolveAsType (ec);
6362 eclass = ExprClass.Value;
6364 if (type.IsPointer) {
6365 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
6366 type.GetSignatureForError ());
6370 if (arguments == null) {
6371 Constant c = Constantify (type, RequestedType.Location);
6373 return ReducedExpression.Create (c, this);
6376 if (type.IsDelegate) {
6377 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
6380 var tparam = type as TypeParameterSpec;
6381 if (tparam != null) {
6383 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
6384 // where type parameter constraint is inflated to struct
6386 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
6387 ec.Report.Error (304, loc,
6388 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
6389 type.GetSignatureForError ());
6392 if ((arguments != null) && (arguments.Count != 0)) {
6393 ec.Report.Error (417, loc,
6394 "`{0}': cannot provide arguments when creating an instance of a variable type",
6395 type.GetSignatureForError ());
6401 if (type.IsStatic) {
6402 ec.Report.SymbolRelatedToPreviousError (type);
6403 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
6407 if (type.IsInterface || type.IsAbstract){
6408 if (!TypeManager.IsGenericType (type)) {
6409 RequestedType = CheckComImport (ec);
6410 if (RequestedType != null)
6411 return RequestedType;
6414 ec.Report.SymbolRelatedToPreviousError (type);
6415 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
6420 // Any struct always defines parameterless constructor
6422 if (type.IsStruct && arguments == null)
6426 if (arguments != null) {
6427 arguments.Resolve (ec, out dynamic);
6432 method = ConstructorLookup (ec, type, ref arguments, loc);
6435 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6436 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
6442 bool DoEmitTypeParameter (EmitContext ec)
6444 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
6448 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
6449 var tparam = (TypeParameterSpec) type;
6451 if (tparam.IsReferenceType) {
6452 ec.Emit (OpCodes.Call, ctor_factory);
6456 // Allow DoEmit() to be called multiple times.
6457 // We need to create a new LocalTemporary each time since
6458 // you can't share LocalBuilders among ILGeneators.
6459 LocalTemporary temp = new LocalTemporary (type);
6461 Label label_activator = ec.DefineLabel ();
6462 Label label_end = ec.DefineLabel ();
6464 temp.AddressOf (ec, AddressOp.Store);
6465 ec.Emit (OpCodes.Initobj, type);
6468 ec.Emit (OpCodes.Box, type);
6469 ec.Emit (OpCodes.Brfalse, label_activator);
6471 temp.AddressOf (ec, AddressOp.Store);
6472 ec.Emit (OpCodes.Initobj, type);
6475 ec.Emit (OpCodes.Br_S, label_end);
6477 ec.MarkLabel (label_activator);
6479 ec.Emit (OpCodes.Call, ctor_factory);
6480 ec.MarkLabel (label_end);
6485 // This Emit can be invoked in two contexts:
6486 // * As a mechanism that will leave a value on the stack (new object)
6487 // * As one that wont (init struct)
6489 // If we are dealing with a ValueType, we have a few
6490 // situations to deal with:
6492 // * The target is a ValueType, and we have been provided
6493 // the instance (this is easy, we are being assigned).
6495 // * The target of New is being passed as an argument,
6496 // to a boxing operation or a function that takes a
6499 // In this case, we need to create a temporary variable
6500 // that is the argument of New.
6502 // Returns whether a value is left on the stack
6504 // *** Implementation note ***
6506 // To benefit from this optimization, each assignable expression
6507 // has to manually cast to New and call this Emit.
6509 // TODO: It's worth to implement it for arrays and fields
6511 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
6513 bool is_value_type = TypeSpec.IsValueType (type);
6514 VariableReference vr = target as VariableReference;
6516 if (target != null && is_value_type && (vr != null || method == null)) {
6517 target.AddressOf (ec, AddressOp.Store);
6518 } else if (vr != null && vr.IsRef) {
6522 if (arguments != null) {
6523 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
6524 arguments = arguments.Emit (ec, false, true);
6526 arguments.Emit (ec);
6529 if (is_value_type) {
6530 if (method == null) {
6531 ec.Emit (OpCodes.Initobj, type);
6536 ec.Emit (OpCodes.Call, method);
6541 if (type is TypeParameterSpec)
6542 return DoEmitTypeParameter (ec);
6544 ec.Emit (OpCodes.Newobj, method);
6548 public override void Emit (EmitContext ec)
6550 LocalTemporary v = null;
6551 if (method == null && TypeSpec.IsValueType (type)) {
6552 // TODO: Use temporary variable from pool
6553 v = new LocalTemporary (type);
6560 public override void EmitStatement (EmitContext ec)
6562 LocalTemporary v = null;
6563 if (method == null && TypeSpec.IsValueType (type)) {
6564 // TODO: Use temporary variable from pool
6565 v = new LocalTemporary (type);
6569 ec.Emit (OpCodes.Pop);
6572 public void AddressOf (EmitContext ec, AddressOp mode)
6574 EmitAddressOf (ec, mode);
6577 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
6579 LocalTemporary value_target = new LocalTemporary (type);
6581 if (type is TypeParameterSpec) {
6582 DoEmitTypeParameter (ec);
6583 value_target.Store (ec);
6584 value_target.AddressOf (ec, mode);
6585 return value_target;
6588 value_target.AddressOf (ec, AddressOp.Store);
6590 if (method == null) {
6591 ec.Emit (OpCodes.Initobj, type);
6593 if (arguments != null)
6594 arguments.Emit (ec);
6596 ec.Emit (OpCodes.Call, method);
6599 value_target.AddressOf (ec, mode);
6600 return value_target;
6603 protected override void CloneTo (CloneContext clonectx, Expression t)
6605 New target = (New) t;
6607 target.RequestedType = RequestedType.Clone (clonectx);
6608 if (arguments != null){
6609 target.arguments = arguments.Clone (clonectx);
6613 public override SLE.Expression MakeExpression (BuilderContext ctx)
6616 return base.MakeExpression (ctx);
6618 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
6622 public override object Accept (StructuralVisitor visitor)
6624 return visitor.Visit (this);
6629 // Array initializer expression, the expression is allowed in
6630 // variable or field initialization only which makes it tricky as
6631 // the type has to be infered based on the context either from field
6632 // type or variable type (think of multiple declarators)
6634 public class ArrayInitializer : Expression
6636 List<Expression> elements;
6637 BlockVariable variable;
6639 public ArrayInitializer (List<Expression> init, Location loc)
6645 public ArrayInitializer (int count, Location loc)
6646 : this (new List<Expression> (count), loc)
6650 public ArrayInitializer (Location loc)
6658 get { return elements.Count; }
6661 public List<Expression> Elements {
6667 public Expression this [int index] {
6669 return elements [index];
6673 public BlockVariable VariableDeclaration {
6684 public void Add (Expression expr)
6686 elements.Add (expr);
6689 public override bool ContainsEmitWithAwait ()
6691 throw new NotSupportedException ();
6694 public override Expression CreateExpressionTree (ResolveContext ec)
6696 throw new NotSupportedException ("ET");
6699 protected override void CloneTo (CloneContext clonectx, Expression t)
6701 var target = (ArrayInitializer) t;
6703 target.elements = new List<Expression> (elements.Count);
6704 foreach (var element in elements)
6705 target.elements.Add (element.Clone (clonectx));
6708 protected override Expression DoResolve (ResolveContext rc)
6710 var current_field = rc.CurrentMemberDefinition as FieldBase;
6711 TypeExpression type;
6712 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6713 type = new TypeExpression (current_field.MemberType, current_field.Location);
6714 } else if (variable != null) {
6715 if (variable.TypeExpression is VarExpr) {
6716 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6717 return EmptyExpression.Null;
6720 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6722 throw new NotImplementedException ("Unexpected array initializer context");
6725 return new ArrayCreation (type, this).Resolve (rc);
6728 public override void Emit (EmitContext ec)
6730 throw new InternalErrorException ("Missing Resolve call");
6733 public override object Accept (StructuralVisitor visitor)
6735 return visitor.Visit (this);
6740 /// 14.5.10.2: Represents an array creation expression.
6744 /// There are two possible scenarios here: one is an array creation
6745 /// expression that specifies the dimensions and optionally the
6746 /// initialization data and the other which does not need dimensions
6747 /// specified but where initialization data is mandatory.
6749 public class ArrayCreation : Expression
6751 FullNamedExpression requested_base_type;
6752 ArrayInitializer initializers;
6755 // The list of Argument types.
6756 // This is used to construct the `newarray' or constructor signature
6758 protected List<Expression> arguments;
6760 protected TypeSpec array_element_type;
6761 int num_arguments = 0;
6762 protected int dimensions;
6763 protected readonly ComposedTypeSpecifier rank;
6764 Expression first_emit;
6765 LocalTemporary first_emit_temp;
6767 protected List<Expression> array_data;
6769 Dictionary<int, int> bounds;
6772 // The number of constants in array initializers
6773 int const_initializers_count;
6774 bool only_constant_initializers;
6776 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6777 : this (requested_base_type, rank, initializers, l)
6779 arguments = new List<Expression> (exprs);
6780 num_arguments = arguments.Count;
6784 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6786 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6788 this.requested_base_type = requested_base_type;
6790 this.initializers = initializers;
6794 num_arguments = rank.Dimension;
6798 // For compiler generated single dimensional arrays only
6800 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6801 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6806 // For expressions like int[] foo = { 1, 2, 3 };
6808 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6809 : this (requested_base_type, null, initializers, initializers.Location)
6813 public ComposedTypeSpecifier Rank {
6819 public FullNamedExpression TypeExpression {
6821 return this.requested_base_type;
6825 public ArrayInitializer Initializers {
6827 return this.initializers;
6831 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6833 if (initializers != null && bounds == null) {
6835 // We use this to store all the data values in the order in which we
6836 // will need to store them in the byte blob later
6838 array_data = new List<Expression> (probe.Count);
6839 bounds = new Dictionary<int, int> ();
6842 if (specified_dims) {
6843 Expression a = arguments [idx];
6848 a = ConvertExpressionToArrayIndex (ec, a);
6854 if (initializers != null) {
6855 Constant c = a as Constant;
6856 if (c == null && a is ArrayIndexCast)
6857 c = ((ArrayIndexCast) a).Child as Constant;
6860 ec.Report.Error (150, a.Location, "A constant value is expected");
6866 value = System.Convert.ToInt32 (c.GetValue ());
6868 ec.Report.Error (150, a.Location, "A constant value is expected");
6872 // TODO: probe.Count does not fit ulong in
6873 if (value != probe.Count) {
6874 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6878 bounds[idx] = value;
6882 if (initializers == null)
6885 for (int i = 0; i < probe.Count; ++i) {
6887 if (o is ArrayInitializer) {
6888 var sub_probe = o as ArrayInitializer;
6889 if (idx + 1 >= dimensions){
6890 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6894 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
6895 if (!bounds.ContainsKey(idx + 1))
6896 bounds[idx + 1] = sub_probe.Count;
6898 if (bounds[idx + 1] != sub_probe.Count) {
6899 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
6903 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6906 } else if (child_bounds > 1) {
6907 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6909 Expression element = ResolveArrayElement (ec, o);
6910 if (element == null)
6913 // Initializers with the default values can be ignored
6914 Constant c = element as Constant;
6916 if (!c.IsDefaultInitializer (array_element_type)) {
6917 ++const_initializers_count;
6920 only_constant_initializers = false;
6923 array_data.Add (element);
6930 public override bool ContainsEmitWithAwait ()
6932 foreach (var arg in arguments) {
6933 if (arg.ContainsEmitWithAwait ())
6937 return InitializersContainAwait ();
6940 public override Expression CreateExpressionTree (ResolveContext ec)
6944 if (array_data == null) {
6945 args = new Arguments (arguments.Count + 1);
6946 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6947 foreach (Expression a in arguments)
6948 args.Add (new Argument (a.CreateExpressionTree (ec)));
6950 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6953 if (dimensions > 1) {
6954 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6958 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6959 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6960 if (array_data != null) {
6961 for (int i = 0; i < array_data.Count; ++i) {
6962 Expression e = array_data [i];
6963 args.Add (new Argument (e.CreateExpressionTree (ec)));
6967 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6970 void UpdateIndices (ResolveContext rc)
6973 for (var probe = initializers; probe != null;) {
6974 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
6976 bounds[i++] = probe.Count;
6978 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
6979 probe = (ArrayInitializer) probe[0];
6980 } else if (dimensions > i) {
6988 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
6990 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
6993 bool InitializersContainAwait ()
6995 if (array_data == null)
6998 foreach (var expr in array_data) {
6999 if (expr.ContainsEmitWithAwait ())
7006 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
7008 element = element.Resolve (ec);
7009 if (element == null)
7012 if (element is CompoundAssign.TargetExpression) {
7013 if (first_emit != null)
7014 throw new InternalErrorException ("Can only handle one mutator at a time");
7015 first_emit = element;
7016 element = first_emit_temp = new LocalTemporary (element.Type);
7019 return Convert.ImplicitConversionRequired (
7020 ec, element, array_element_type, loc);
7023 protected bool ResolveInitializers (ResolveContext ec)
7026 only_constant_initializers = true;
7029 if (arguments != null) {
7031 for (int i = 0; i < arguments.Count; ++i) {
7032 res &= CheckIndices (ec, initializers, i, true, dimensions);
7033 if (initializers != null)
7040 arguments = new List<Expression> ();
7042 if (!CheckIndices (ec, initializers, 0, false, dimensions))
7051 // Resolved the type of the array
7053 bool ResolveArrayType (ResolveContext ec)
7058 FullNamedExpression array_type_expr;
7059 if (num_arguments > 0) {
7060 array_type_expr = new ComposedCast (requested_base_type, rank);
7062 array_type_expr = requested_base_type;
7065 type = array_type_expr.ResolveAsType (ec);
7066 if (array_type_expr == null)
7069 var ac = type as ArrayContainer;
7071 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
7075 array_element_type = ac.Element;
7076 dimensions = ac.Rank;
7081 protected override Expression DoResolve (ResolveContext ec)
7086 if (!ResolveArrayType (ec))
7090 // validate the initializers and fill in any missing bits
7092 if (!ResolveInitializers (ec))
7095 eclass = ExprClass.Value;
7099 byte [] MakeByteBlob ()
7104 int count = array_data.Count;
7106 TypeSpec element_type = array_element_type;
7107 if (element_type.IsEnum)
7108 element_type = EnumSpec.GetUnderlyingType (element_type);
7110 factor = BuiltinTypeSpec.GetSize (element_type);
7112 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
7114 data = new byte [(count * factor + 3) & ~3];
7117 for (int i = 0; i < count; ++i) {
7118 var c = array_data[i] as Constant;
7124 object v = c.GetValue ();
7126 switch (element_type.BuiltinType) {
7127 case BuiltinTypeSpec.Type.Long:
7128 long lval = (long) v;
7130 for (int j = 0; j < factor; ++j) {
7131 data[idx + j] = (byte) (lval & 0xFF);
7135 case BuiltinTypeSpec.Type.ULong:
7136 ulong ulval = (ulong) v;
7138 for (int j = 0; j < factor; ++j) {
7139 data[idx + j] = (byte) (ulval & 0xFF);
7140 ulval = (ulval >> 8);
7143 case BuiltinTypeSpec.Type.Float:
7144 var fval = SingleConverter.SingleToInt32Bits((float) v);
7146 data[idx] = (byte) (fval & 0xff);
7147 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
7148 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
7149 data[idx + 3] = (byte) (fval >> 24);
7151 case BuiltinTypeSpec.Type.Double:
7152 element = BitConverter.GetBytes ((double) v);
7154 for (int j = 0; j < factor; ++j)
7155 data[idx + j] = element[j];
7157 // FIXME: Handle the ARM float format.
7158 if (!BitConverter.IsLittleEndian)
7159 System.Array.Reverse (data, idx, 8);
7161 case BuiltinTypeSpec.Type.Char:
7162 int chval = (int) ((char) v);
7164 data[idx] = (byte) (chval & 0xff);
7165 data[idx + 1] = (byte) (chval >> 8);
7167 case BuiltinTypeSpec.Type.Short:
7168 int sval = (int) ((short) v);
7170 data[idx] = (byte) (sval & 0xff);
7171 data[idx + 1] = (byte) (sval >> 8);
7173 case BuiltinTypeSpec.Type.UShort:
7174 int usval = (int) ((ushort) v);
7176 data[idx] = (byte) (usval & 0xff);
7177 data[idx + 1] = (byte) (usval >> 8);
7179 case BuiltinTypeSpec.Type.Int:
7182 data[idx] = (byte) (val & 0xff);
7183 data[idx + 1] = (byte) ((val >> 8) & 0xff);
7184 data[idx + 2] = (byte) ((val >> 16) & 0xff);
7185 data[idx + 3] = (byte) (val >> 24);
7187 case BuiltinTypeSpec.Type.UInt:
7188 uint uval = (uint) v;
7190 data[idx] = (byte) (uval & 0xff);
7191 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
7192 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
7193 data[idx + 3] = (byte) (uval >> 24);
7195 case BuiltinTypeSpec.Type.SByte:
7196 data[idx] = (byte) (sbyte) v;
7198 case BuiltinTypeSpec.Type.Byte:
7199 data[idx] = (byte) v;
7201 case BuiltinTypeSpec.Type.Bool:
7202 data[idx] = (byte) ((bool) v ? 1 : 0);
7204 case BuiltinTypeSpec.Type.Decimal:
7205 int[] bits = Decimal.GetBits ((decimal) v);
7208 // FIXME: For some reason, this doesn't work on the MS runtime.
7209 int[] nbits = new int[4];
7215 for (int j = 0; j < 4; j++) {
7216 data[p++] = (byte) (nbits[j] & 0xff);
7217 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
7218 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
7219 data[p++] = (byte) (nbits[j] >> 24);
7223 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
7232 #if NET_4_0 || MONODROID
7233 public override SLE.Expression MakeExpression (BuilderContext ctx)
7236 return base.MakeExpression (ctx);
7238 var initializers = new SLE.Expression [array_data.Count];
7239 for (var i = 0; i < initializers.Length; i++) {
7240 if (array_data [i] == null)
7241 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
7243 initializers [i] = array_data [i].MakeExpression (ctx);
7246 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
7252 // Emits the initializers for the array
7254 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
7256 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
7261 // First, the static data
7263 byte [] data = MakeByteBlob ();
7264 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
7266 if (stackArray == null) {
7267 ec.Emit (OpCodes.Dup);
7269 stackArray.Emit (ec);
7272 ec.Emit (OpCodes.Ldtoken, fb);
7273 ec.Emit (OpCodes.Call, m);
7278 // Emits pieces of the array that can not be computed at compile
7279 // time (variables and string locations).
7281 // This always expect the top value on the stack to be the array
7283 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
7285 int dims = bounds.Count;
7286 var current_pos = new int [dims];
7288 for (int i = 0; i < array_data.Count; i++){
7290 Expression e = array_data [i];
7291 var c = e as Constant;
7293 // Constant can be initialized via StaticInitializer
7294 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
7298 if (stackArray != null) {
7299 if (e.ContainsEmitWithAwait ()) {
7300 e = e.EmitToField (ec);
7303 stackArray.Emit (ec);
7305 ec.Emit (OpCodes.Dup);
7308 for (int idx = 0; idx < dims; idx++)
7309 ec.EmitInt (current_pos [idx]);
7312 // If we are dealing with a struct, get the
7313 // address of it, so we can store it.
7315 if (dims == 1 && etype.IsStruct) {
7316 switch (etype.BuiltinType) {
7317 case BuiltinTypeSpec.Type.Byte:
7318 case BuiltinTypeSpec.Type.SByte:
7319 case BuiltinTypeSpec.Type.Bool:
7320 case BuiltinTypeSpec.Type.Short:
7321 case BuiltinTypeSpec.Type.UShort:
7322 case BuiltinTypeSpec.Type.Char:
7323 case BuiltinTypeSpec.Type.Int:
7324 case BuiltinTypeSpec.Type.UInt:
7325 case BuiltinTypeSpec.Type.Long:
7326 case BuiltinTypeSpec.Type.ULong:
7327 case BuiltinTypeSpec.Type.Float:
7328 case BuiltinTypeSpec.Type.Double:
7331 ec.Emit (OpCodes.Ldelema, etype);
7338 ec.EmitArrayStore ((ArrayContainer) type);
7344 for (int j = dims - 1; j >= 0; j--){
7346 if (current_pos [j] < bounds [j])
7348 current_pos [j] = 0;
7353 public override void Emit (EmitContext ec)
7355 EmitToFieldSource (ec);
7358 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
7360 if (first_emit != null) {
7361 first_emit.Emit (ec);
7362 first_emit_temp.Store (ec);
7365 FieldExpr await_stack_field;
7366 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
7367 await_stack_field = ec.GetTemporaryField (type);
7370 await_stack_field = null;
7373 EmitExpressionsList (ec, arguments);
7375 ec.EmitArrayNew ((ArrayContainer) type);
7377 if (initializers == null)
7378 return await_stack_field;
7380 if (await_stack_field != null)
7381 await_stack_field.EmitAssignFromStack (ec);
7385 // Emit static initializer for arrays which contain more than 2 items and
7386 // the static initializer will initialize at least 25% of array values or there
7387 // is more than 10 items to be initialized
7389 // NOTE: const_initializers_count does not contain default constant values.
7391 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
7392 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
7393 EmitStaticInitializers (ec, await_stack_field);
7395 if (!only_constant_initializers)
7396 EmitDynamicInitializers (ec, false, await_stack_field);
7400 EmitDynamicInitializers (ec, true, await_stack_field);
7403 if (first_emit_temp != null)
7404 first_emit_temp.Release (ec);
7406 return await_stack_field;
7409 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7411 // no multi dimensional or jagged arrays
7412 if (arguments.Count != 1 || array_element_type.IsArray) {
7413 base.EncodeAttributeValue (rc, enc, targetType);
7417 // No array covariance, except for array -> object
7418 if (type != targetType) {
7419 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
7420 base.EncodeAttributeValue (rc, enc, targetType);
7424 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
7425 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7430 // Single dimensional array of 0 size
7431 if (array_data == null) {
7432 IntConstant ic = arguments[0] as IntConstant;
7433 if (ic == null || !ic.IsDefaultValue) {
7434 base.EncodeAttributeValue (rc, enc, targetType);
7442 enc.Encode (array_data.Count);
7443 foreach (var element in array_data) {
7444 element.EncodeAttributeValue (rc, enc, array_element_type);
7448 protected override void CloneTo (CloneContext clonectx, Expression t)
7450 ArrayCreation target = (ArrayCreation) t;
7452 if (requested_base_type != null)
7453 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
7455 if (arguments != null){
7456 target.arguments = new List<Expression> (arguments.Count);
7457 foreach (Expression e in arguments)
7458 target.arguments.Add (e.Clone (clonectx));
7461 if (initializers != null)
7462 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
7465 public override object Accept (StructuralVisitor visitor)
7467 return visitor.Visit (this);
7472 // Represents an implicitly typed array epxression
7474 class ImplicitlyTypedArrayCreation : ArrayCreation
7476 TypeInferenceContext best_type_inference;
7478 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7479 : base (null, rank, initializers, loc)
7483 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
7484 : base (null, initializers, loc)
7488 protected override Expression DoResolve (ResolveContext ec)
7493 dimensions = rank.Dimension;
7495 best_type_inference = new TypeInferenceContext ();
7497 if (!ResolveInitializers (ec))
7500 best_type_inference.FixAllTypes (ec);
7501 array_element_type = best_type_inference.InferredTypeArguments[0];
7502 best_type_inference = null;
7504 if (array_element_type == null ||
7505 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
7506 arguments.Count != rank.Dimension) {
7507 ec.Report.Error (826, loc,
7508 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
7513 // At this point we found common base type for all initializer elements
7514 // but we have to be sure that all static initializer elements are of
7517 UnifyInitializerElement (ec);
7519 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
7520 eclass = ExprClass.Value;
7525 // Converts static initializer only
7527 void UnifyInitializerElement (ResolveContext ec)
7529 for (int i = 0; i < array_data.Count; ++i) {
7530 Expression e = array_data[i];
7532 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
7536 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
7538 element = element.Resolve (ec);
7539 if (element != null)
7540 best_type_inference.AddCommonTypeBound (element.Type);
7546 sealed class CompilerGeneratedThis : This
7548 public CompilerGeneratedThis (TypeSpec type, Location loc)
7552 eclass = ExprClass.Variable;
7555 protected override Expression DoResolve (ResolveContext ec)
7560 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7567 /// Represents the `this' construct
7570 public class This : VariableReference
7572 sealed class ThisVariable : ILocalVariable
7574 public static readonly ILocalVariable Instance = new ThisVariable ();
7576 public void Emit (EmitContext ec)
7581 public void EmitAssign (EmitContext ec)
7583 throw new InvalidOperationException ();
7586 public void EmitAddressOf (EmitContext ec)
7592 VariableInfo variable_info;
7594 public This (Location loc)
7601 public override string Name {
7602 get { return "this"; }
7605 public override bool IsLockedByStatement {
7613 public override bool IsRef {
7614 get { return type.IsStruct; }
7617 public override bool IsSideEffectFree {
7623 protected override ILocalVariable Variable {
7624 get { return ThisVariable.Instance; }
7627 public override VariableInfo VariableInfo {
7628 get { return variable_info; }
7631 public override bool IsFixed {
7632 get { return false; }
7637 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
7640 // It's null for all cases when we don't need to check `this'
7641 // definitive assignment
7643 if (variable_info == null)
7646 if (rc.OmitStructFlowAnalysis)
7649 if (!variable_info.IsAssigned (rc)) {
7650 rc.Report.Error (188, loc,
7651 "The `this' object cannot be used before all of its fields are assigned to");
7655 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7657 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7658 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7659 } else if (ec.CurrentAnonymousMethod != null) {
7660 ec.Report.Error (1673, loc,
7661 "Anonymous methods inside structs cannot access instance members of `this'. " +
7662 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7664 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7668 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7673 AnonymousMethodStorey storey = ae.Storey;
7674 return storey != null ? storey.HoistedThis : null;
7677 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7679 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7682 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7685 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7691 public virtual void ResolveBase (ResolveContext ec)
7693 eclass = ExprClass.Variable;
7694 type = ec.CurrentType;
7696 if (!IsThisAvailable (ec, false)) {
7697 Error_ThisNotAvailable (ec);
7701 var block = ec.CurrentBlock;
7702 if (block != null) {
7703 var top = block.ParametersBlock.TopBlock;
7704 if (top.ThisVariable != null)
7705 variable_info = top.ThisVariable.VariableInfo;
7707 AnonymousExpression am = ec.CurrentAnonymousMethod;
7708 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7710 // Hoisted this is almost like hoisted variable but not exactly. When
7711 // there is no variable hoisted we can simply emit an instance method
7712 // without lifting this into a storey. Unfotunatelly this complicates
7713 // things in other cases because we don't know where this will be hoisted
7714 // until top-level block is fully resolved
7716 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7717 am.SetHasThisAccess ();
7722 protected override Expression DoResolve (ResolveContext ec)
7726 CheckStructThisDefiniteAssignment (ec);
7731 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7733 if (eclass == ExprClass.Unresolved)
7736 if (variable_info != null)
7737 variable_info.SetAssigned (ec);
7740 if (right_side == EmptyExpression.UnaryAddress)
7741 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7742 else if (right_side == EmptyExpression.OutAccess)
7743 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7745 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7751 public override int GetHashCode()
7753 throw new NotImplementedException ();
7756 public override bool Equals (object obj)
7758 This t = obj as This;
7765 protected override void CloneTo (CloneContext clonectx, Expression t)
7770 public override void SetHasAddressTaken ()
7775 public override void VerifyAssigned (ResolveContext rc)
7779 public override object Accept (StructuralVisitor visitor)
7781 return visitor.Visit (this);
7786 /// Represents the `__arglist' construct
7788 public class ArglistAccess : Expression
7790 public ArglistAccess (Location loc)
7795 protected override void CloneTo (CloneContext clonectx, Expression target)
7800 public override bool ContainsEmitWithAwait ()
7805 public override Expression CreateExpressionTree (ResolveContext ec)
7807 throw new NotSupportedException ("ET");
7810 protected override Expression DoResolve (ResolveContext ec)
7812 eclass = ExprClass.Variable;
7813 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
7815 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7816 ec.Report.Error (190, loc,
7817 "The __arglist construct is valid only within a variable argument method");
7823 public override void Emit (EmitContext ec)
7825 ec.Emit (OpCodes.Arglist);
7828 public override object Accept (StructuralVisitor visitor)
7830 return visitor.Visit (this);
7835 /// Represents the `__arglist (....)' construct
7837 public class Arglist : Expression
7839 Arguments arguments;
7841 public Arglist (Location loc)
7846 public Arglist (Arguments args, Location l)
7852 public Arguments Arguments {
7858 public MetaType[] ArgumentTypes {
7860 if (arguments == null)
7861 return MetaType.EmptyTypes;
7863 var retval = new MetaType[arguments.Count];
7864 for (int i = 0; i < retval.Length; i++)
7865 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
7871 public override bool ContainsEmitWithAwait ()
7873 throw new NotImplementedException ();
7876 public override Expression CreateExpressionTree (ResolveContext ec)
7878 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7882 protected override Expression DoResolve (ResolveContext ec)
7884 eclass = ExprClass.Variable;
7885 type = InternalType.Arglist;
7886 if (arguments != null) {
7887 bool dynamic; // Can be ignored as there is always only 1 overload
7888 arguments.Resolve (ec, out dynamic);
7894 public override void Emit (EmitContext ec)
7896 if (arguments != null)
7897 arguments.Emit (ec);
7900 protected override void CloneTo (CloneContext clonectx, Expression t)
7902 Arglist target = (Arglist) t;
7904 if (arguments != null)
7905 target.arguments = arguments.Clone (clonectx);
7908 public override object Accept (StructuralVisitor visitor)
7910 return visitor.Visit (this);
7914 public class RefValueExpr : ShimExpression, IAssignMethod
7916 FullNamedExpression texpr;
7918 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7925 public FullNamedExpression TypeExpression {
7931 public override bool ContainsEmitWithAwait ()
7936 protected override Expression DoResolve (ResolveContext rc)
7938 expr = expr.Resolve (rc);
7939 type = texpr.ResolveAsType (rc);
7940 if (expr == null || type == null)
7943 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7944 eclass = ExprClass.Value;
7948 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7950 return DoResolve (rc);
7953 public override void Emit (EmitContext ec)
7956 ec.Emit (OpCodes.Refanyval, type);
7957 ec.EmitLoadFromPtr (type);
7960 public void Emit (EmitContext ec, bool leave_copy)
7962 throw new NotImplementedException ();
7965 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7968 ec.Emit (OpCodes.Refanyval, type);
7971 LocalTemporary temporary = null;
7973 ec.Emit (OpCodes.Dup);
7974 temporary = new LocalTemporary (source.Type);
7975 temporary.Store (ec);
7978 ec.EmitStoreFromPtr (type);
7980 if (temporary != null) {
7981 temporary.Emit (ec);
7982 temporary.Release (ec);
7986 public override object Accept (StructuralVisitor visitor)
7988 return visitor.Visit (this);
7992 public class RefTypeExpr : ShimExpression
7994 public RefTypeExpr (Expression expr, Location loc)
8000 protected override Expression DoResolve (ResolveContext rc)
8002 expr = expr.Resolve (rc);
8006 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8010 type = rc.BuiltinTypes.Type;
8011 eclass = ExprClass.Value;
8015 public override void Emit (EmitContext ec)
8018 ec.Emit (OpCodes.Refanytype);
8019 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8021 ec.Emit (OpCodes.Call, m);
8024 public override object Accept (StructuralVisitor visitor)
8026 return visitor.Visit (this);
8030 public class MakeRefExpr : ShimExpression
8032 public MakeRefExpr (Expression expr, Location loc)
8038 public override bool ContainsEmitWithAwait ()
8040 throw new NotImplementedException ();
8043 protected override Expression DoResolve (ResolveContext rc)
8045 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8046 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8047 eclass = ExprClass.Value;
8051 public override void Emit (EmitContext ec)
8053 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8054 ec.Emit (OpCodes.Mkrefany, expr.Type);
8057 public override object Accept (StructuralVisitor visitor)
8059 return visitor.Visit (this);
8064 /// Implements the typeof operator
8066 public class TypeOf : Expression {
8067 FullNamedExpression QueriedType;
8070 public TypeOf (FullNamedExpression queried_type, Location l)
8072 QueriedType = queried_type;
8077 // Use this constructor for any compiler generated typeof expression
8079 public TypeOf (TypeSpec type, Location loc)
8081 this.typearg = type;
8087 public override bool IsSideEffectFree {
8093 public TypeSpec TypeArgument {
8099 public FullNamedExpression TypeExpression {
8108 protected override void CloneTo (CloneContext clonectx, Expression t)
8110 TypeOf target = (TypeOf) t;
8111 if (QueriedType != null)
8112 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
8115 public override bool ContainsEmitWithAwait ()
8120 public override Expression CreateExpressionTree (ResolveContext ec)
8122 Arguments args = new Arguments (2);
8123 args.Add (new Argument (this));
8124 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8125 return CreateExpressionFactoryCall (ec, "Constant", args);
8128 protected override Expression DoResolve (ResolveContext ec)
8130 if (eclass != ExprClass.Unresolved)
8133 if (typearg == null) {
8135 // Pointer types are allowed without explicit unsafe, they are just tokens
8137 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
8138 typearg = QueriedType.ResolveAsType (ec);
8141 if (typearg == null)
8144 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8145 ec.Report.Error (1962, QueriedType.Location,
8146 "The typeof operator cannot be used on the dynamic type");
8150 type = ec.BuiltinTypes.Type;
8152 // Even though what is returned is a type object, it's treated as a value by the compiler.
8153 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
8154 eclass = ExprClass.Value;
8158 static bool ContainsDynamicType (TypeSpec type)
8160 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
8163 var element_container = type as ElementTypeSpec;
8164 if (element_container != null)
8165 return ContainsDynamicType (element_container.Element);
8167 foreach (var t in type.TypeArguments) {
8168 if (ContainsDynamicType (t)) {
8176 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
8178 // Target type is not System.Type therefore must be object
8179 // and we need to use different encoding sequence
8180 if (targetType != type)
8183 if (typearg is InflatedTypeSpec) {
8186 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
8187 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
8188 typearg.GetSignatureForError ());
8192 gt = gt.DeclaringType;
8193 } while (gt != null);
8196 if (ContainsDynamicType (typearg)) {
8197 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8201 enc.EncodeTypeName (typearg);
8204 public override void Emit (EmitContext ec)
8206 ec.Emit (OpCodes.Ldtoken, typearg);
8207 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8209 ec.Emit (OpCodes.Call, m);
8212 public override object Accept (StructuralVisitor visitor)
8214 return visitor.Visit (this);
8218 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
8220 public TypeOfMethod (MethodSpec method, Location loc)
8221 : base (method, loc)
8225 protected override Expression DoResolve (ResolveContext ec)
8227 if (member.IsConstructor) {
8228 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
8230 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
8236 return base.DoResolve (ec);
8239 public override void Emit (EmitContext ec)
8241 ec.Emit (OpCodes.Ldtoken, member);
8244 ec.Emit (OpCodes.Castclass, type);
8247 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8249 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
8252 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8254 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
8258 abstract class TypeOfMember<T> : Expression where T : MemberSpec
8260 protected readonly T member;
8262 protected TypeOfMember (T member, Location loc)
8264 this.member = member;
8268 public override bool IsSideEffectFree {
8274 public override bool ContainsEmitWithAwait ()
8279 public override Expression CreateExpressionTree (ResolveContext ec)
8281 Arguments args = new Arguments (2);
8282 args.Add (new Argument (this));
8283 args.Add (new Argument (new TypeOf (type, loc)));
8284 return CreateExpressionFactoryCall (ec, "Constant", args);
8287 protected override Expression DoResolve (ResolveContext ec)
8289 eclass = ExprClass.Value;
8293 public override void Emit (EmitContext ec)
8295 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
8296 PredefinedMember<MethodSpec> p;
8298 p = GetTypeFromHandleGeneric (ec);
8299 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
8301 p = GetTypeFromHandle (ec);
8304 var mi = p.Resolve (loc);
8306 ec.Emit (OpCodes.Call, mi);
8309 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
8310 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
8313 sealed class TypeOfField : TypeOfMember<FieldSpec>
8315 public TypeOfField (FieldSpec field, Location loc)
8320 protected override Expression DoResolve (ResolveContext ec)
8322 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
8326 return base.DoResolve (ec);
8329 public override void Emit (EmitContext ec)
8331 ec.Emit (OpCodes.Ldtoken, member);
8335 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8337 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
8340 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8342 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
8347 /// Implements the sizeof expression
8349 public class SizeOf : Expression {
8350 readonly Expression texpr;
8351 TypeSpec type_queried;
8353 public SizeOf (Expression queried_type, Location l)
8355 this.texpr = queried_type;
8359 public override bool IsSideEffectFree {
8365 public Expression TypeExpression {
8371 public override bool ContainsEmitWithAwait ()
8376 public override Expression CreateExpressionTree (ResolveContext ec)
8378 Error_PointerInsideExpressionTree (ec);
8382 protected override Expression DoResolve (ResolveContext ec)
8384 type_queried = texpr.ResolveAsType (ec);
8385 if (type_queried == null)
8388 if (type_queried.IsEnum)
8389 type_queried = EnumSpec.GetUnderlyingType (type_queried);
8391 int size_of = BuiltinTypeSpec.GetSize (type_queried);
8393 return new IntConstant (ec.BuiltinTypes, size_of, loc);
8396 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
8401 ec.Report.Error (233, loc,
8402 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
8403 type_queried.GetSignatureForError ());
8406 type = ec.BuiltinTypes.Int;
8407 eclass = ExprClass.Value;
8411 public override void Emit (EmitContext ec)
8413 ec.Emit (OpCodes.Sizeof, type_queried);
8416 protected override void CloneTo (CloneContext clonectx, Expression t)
8420 public override object Accept (StructuralVisitor visitor)
8422 return visitor.Visit (this);
8427 /// Implements the qualified-alias-member (::) expression.
8429 public class QualifiedAliasMember : MemberAccess
8431 readonly string alias;
8432 public static readonly string GlobalAlias = "global";
8434 public QualifiedAliasMember (string alias, string identifier, Location l)
8435 : base (null, identifier, l)
8440 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
8441 : base (null, identifier, targs, l)
8446 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
8447 : base (null, identifier, arity, l)
8452 public string Alias {
8458 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
8460 if (alias == GlobalAlias) {
8461 expr = ec.Module.GlobalRootNamespace;
8462 return base.ResolveAsTypeOrNamespace (ec);
8465 int errors = ec.Module.Compiler.Report.Errors;
8466 expr = ec.LookupNamespaceAlias (alias);
8468 if (errors == ec.Module.Compiler.Report.Errors)
8469 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
8473 return base.ResolveAsTypeOrNamespace (ec);
8476 protected override Expression DoResolve (ResolveContext ec)
8478 return ResolveAsTypeOrNamespace (ec);
8481 public override string GetSignatureForError ()
8484 if (targs != null) {
8485 name = Name + "<" + targs.GetSignatureForError () + ">";
8488 return alias + "::" + name;
8491 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8493 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
8494 rc.Module.Compiler.Report.Error (687, loc,
8495 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
8496 GetSignatureForError ());
8501 return DoResolve (rc);
8504 protected override void CloneTo (CloneContext clonectx, Expression t)
8509 public override object Accept (StructuralVisitor visitor)
8511 return visitor.Visit (this);
8516 /// Implements the member access expression
8518 public class MemberAccess : ATypeNameExpression
8520 protected Expression expr;
8522 public MemberAccess (Expression expr, string id)
8523 : base (id, expr.Location)
8528 public MemberAccess (Expression expr, string identifier, Location loc)
8529 : base (identifier, loc)
8534 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
8535 : base (identifier, args, loc)
8540 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
8541 : base (identifier, arity, loc)
8546 public Expression LeftExpression {
8552 public override Location StartLocation {
8554 return expr == null ? loc : expr.StartLocation;
8558 protected override Expression DoResolve (ResolveContext rc)
8560 var e = DoResolveName (rc, null);
8562 if (!rc.OmitStructFlowAnalysis) {
8563 var fe = e as FieldExpr;
8565 fe.VerifyAssignedStructField (rc, null);
8572 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
8574 var e = DoResolveName (rc, rhs);
8576 if (!rc.OmitStructFlowAnalysis) {
8577 var fe = e as FieldExpr;
8578 if (fe != null && fe.InstanceExpression is FieldExpr) {
8579 fe = (FieldExpr) fe.InstanceExpression;
8580 fe.VerifyAssignedStructField (rc, rhs);
8587 Expression DoResolveName (ResolveContext rc, Expression right_side)
8589 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
8593 if (right_side != null) {
8594 if (e is TypeExpr) {
8595 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8599 e = e.ResolveLValue (rc, right_side);
8601 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
8607 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8609 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8610 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8612 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8615 public static bool IsValidDotExpression (TypeSpec type)
8617 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8618 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8620 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8623 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8625 var sn = expr as SimpleName;
8626 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8629 // Resolve the expression with flow analysis turned off, we'll do the definite
8630 // assignment checks later. This is because we don't know yet what the expression
8631 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
8632 // definite assignment check on the actual field and not on the whole struct.
8634 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
8636 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8639 // Resolve expression which does have type set as we need expression type
8640 // with disable flow analysis as we don't know whether left side expression
8641 // is used as variable or type
8643 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8644 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
8645 expr = expr.Resolve (rc);
8647 } else if (expr is TypeParameterExpr) {
8648 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8652 expr = expr.Resolve (rc, flags);
8659 Namespace ns = expr as Namespace;
8661 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8663 if (retval == null) {
8664 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8668 if (HasTypeArguments)
8669 return new GenericTypeExpr (retval.Type, targs, loc);
8675 TypeSpec expr_type = expr.Type;
8676 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8677 me = expr as MemberExpr;
8679 me.ResolveInstanceExpression (rc, null);
8682 // Run defined assigned checks on expressions resolved with
8683 // disabled flow-analysis
8686 var vr = expr as VariableReference;
8688 vr.VerifyAssigned (rc);
8691 Arguments args = new Arguments (1);
8692 args.Add (new Argument (expr));
8693 return new DynamicMemberBinder (Name, args, loc);
8696 if (!IsValidDotExpression (expr_type)) {
8697 Error_OperatorCannotBeApplied (rc, expr_type);
8701 var lookup_arity = Arity;
8702 bool errorMode = false;
8703 Expression member_lookup;
8705 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8706 if (member_lookup == null) {
8708 // Try to look for extension method when member lookup failed
8710 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8711 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8712 if (methods != null) {
8713 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8714 if (HasTypeArguments) {
8715 if (!targs.Resolve (rc))
8718 emg.SetTypeArguments (rc, targs);
8722 // Run defined assigned checks on expressions resolved with
8723 // disabled flow-analysis
8725 if (sn != null && !errorMode) {
8726 var vr = expr as VariableReference;
8728 vr.VerifyAssigned (rc);
8731 // TODO: it should really skip the checks bellow
8732 return emg.Resolve (rc);
8738 if (member_lookup == null) {
8739 var dep = expr_type.GetMissingDependencies ();
8741 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8742 } else if (expr is TypeExpr) {
8743 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8745 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8751 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8752 // Leave it to overload resolution to report correct error
8753 } else if (!(member_lookup is TypeExpr)) {
8754 // TODO: rc.SymbolRelatedToPreviousError
8755 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8760 if (member_lookup != null)
8764 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8768 TypeExpr texpr = member_lookup as TypeExpr;
8769 if (texpr != null) {
8770 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8771 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8772 Name, texpr.GetSignatureForError ());
8775 if (!texpr.Type.IsAccessible (rc)) {
8776 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8777 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8781 if (HasTypeArguments) {
8782 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8785 return member_lookup;
8788 me = member_lookup as MemberExpr;
8790 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8794 me = me.ResolveMemberAccess (rc, expr, sn);
8797 if (!targs.Resolve (rc))
8800 me.SetTypeArguments (rc, targs);
8804 // Run defined assigned checks on expressions resolved with
8805 // disabled flow-analysis
8807 if (sn != null && !(me is FieldExpr && TypeSpec.IsValueType (expr_type))) {
8808 var vr = expr as VariableReference;
8810 vr.VerifyAssigned (rc);
8816 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8818 FullNamedExpression fexpr = expr as FullNamedExpression;
8819 if (fexpr == null) {
8820 expr.ResolveAsType (rc);
8824 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8826 if (expr_resolved == null)
8829 Namespace ns = expr_resolved as Namespace;
8831 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8833 if (retval == null) {
8834 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8835 } else if (HasTypeArguments) {
8836 retval = new GenericTypeExpr (retval.Type, targs, loc);
8837 if (retval.ResolveAsType (rc) == null)
8844 var tnew_expr = expr_resolved.ResolveAsType (rc);
8845 if (tnew_expr == null)
8848 TypeSpec expr_type = tnew_expr;
8849 if (TypeManager.IsGenericParameter (expr_type)) {
8850 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8851 tnew_expr.GetSignatureForError ());
8855 var qam = this as QualifiedAliasMember;
8857 rc.Module.Compiler.Report.Error (431, loc,
8858 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8863 TypeSpec nested = null;
8864 while (expr_type != null) {
8865 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8866 if (nested == null) {
8867 if (expr_type == tnew_expr) {
8868 Error_IdentifierNotFound (rc, expr_type, Name);
8872 expr_type = tnew_expr;
8873 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8874 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
8878 if (nested.IsAccessible (rc))
8882 // Keep looking after inaccessible candidate but only if
8883 // we are not in same context as the definition itself
8885 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
8888 expr_type = expr_type.BaseType;
8893 if (HasTypeArguments) {
8894 texpr = new GenericTypeExpr (nested, targs, loc);
8896 texpr = new GenericOpenTypeExpr (nested, loc);
8899 texpr = new TypeExpression (nested, loc);
8902 if (texpr.ResolveAsType (rc) == null)
8908 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
8910 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
8912 if (nested != null) {
8913 Error_TypeArgumentsCannotBeUsed (rc, nested, Arity, expr.Location);
8917 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
8918 if (any_other_member != null) {
8919 any_other_member.Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
8923 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
8924 Name, expr_type.GetSignatureForError ());
8927 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
8929 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
8932 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
8934 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8935 ec.Report.SymbolRelatedToPreviousError (type);
8937 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, type, name, Arity);
8939 // a using directive or an assembly reference
8941 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
8943 missing = "an assembly reference";
8946 ec.Report.Error (1061, loc,
8947 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
8948 type.GetSignatureForError (), name, missing);
8952 base.Error_TypeDoesNotContainDefinition (ec, type, name);
8955 public override string GetSignatureForError ()
8957 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
8960 protected override void CloneTo (CloneContext clonectx, Expression t)
8962 MemberAccess target = (MemberAccess) t;
8964 target.expr = expr.Clone (clonectx);
8967 public override object Accept (StructuralVisitor visitor)
8969 return visitor.Visit (this);
8974 /// Implements checked expressions
8976 public class CheckedExpr : Expression {
8978 public Expression Expr;
8980 public CheckedExpr (Expression e, Location l)
8986 public override bool ContainsEmitWithAwait ()
8988 return Expr.ContainsEmitWithAwait ();
8991 public override Expression CreateExpressionTree (ResolveContext ec)
8993 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
8994 return Expr.CreateExpressionTree (ec);
8997 protected override Expression DoResolve (ResolveContext ec)
8999 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9000 Expr = Expr.Resolve (ec);
9005 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9008 eclass = Expr.eclass;
9013 public override void Emit (EmitContext ec)
9015 using (ec.With (EmitContext.Options.CheckedScope, true))
9019 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9021 using (ec.With (EmitContext.Options.CheckedScope, true))
9022 Expr.EmitBranchable (ec, target, on_true);
9025 public override SLE.Expression MakeExpression (BuilderContext ctx)
9027 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9028 return Expr.MakeExpression (ctx);
9032 protected override void CloneTo (CloneContext clonectx, Expression t)
9034 CheckedExpr target = (CheckedExpr) t;
9036 target.Expr = Expr.Clone (clonectx);
9039 public override object Accept (StructuralVisitor visitor)
9041 return visitor.Visit (this);
9046 /// Implements the unchecked expression
9048 public class UnCheckedExpr : Expression {
9050 public Expression Expr;
9052 public UnCheckedExpr (Expression e, Location l)
9058 public override bool ContainsEmitWithAwait ()
9060 return Expr.ContainsEmitWithAwait ();
9063 public override Expression CreateExpressionTree (ResolveContext ec)
9065 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9066 return Expr.CreateExpressionTree (ec);
9069 protected override Expression DoResolve (ResolveContext ec)
9071 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9072 Expr = Expr.Resolve (ec);
9077 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9080 eclass = Expr.eclass;
9085 public override void Emit (EmitContext ec)
9087 using (ec.With (EmitContext.Options.CheckedScope, false))
9091 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9093 using (ec.With (EmitContext.Options.CheckedScope, false))
9094 Expr.EmitBranchable (ec, target, on_true);
9097 protected override void CloneTo (CloneContext clonectx, Expression t)
9099 UnCheckedExpr target = (UnCheckedExpr) t;
9101 target.Expr = Expr.Clone (clonectx);
9104 public override object Accept (StructuralVisitor visitor)
9106 return visitor.Visit (this);
9111 /// An Element Access expression.
9113 /// During semantic analysis these are transformed into
9114 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
9116 public class ElementAccess : Expression
9118 public Arguments Arguments;
9119 public Expression Expr;
9121 public ElementAccess (Expression e, Arguments args, Location loc)
9125 this.Arguments = args;
9128 public override Location StartLocation {
9130 return Expr.StartLocation;
9134 public override bool ContainsEmitWithAwait ()
9136 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
9140 // We perform some simple tests, and then to "split" the emit and store
9141 // code we create an instance of a different class, and return that.
9143 Expression CreateAccessExpression (ResolveContext ec)
9146 return (new ArrayAccess (this, loc));
9149 return MakePointerAccess (ec, type);
9151 FieldExpr fe = Expr as FieldExpr;
9153 var ff = fe.Spec as FixedFieldSpec;
9155 return MakePointerAccess (ec, ff.ElementType);
9159 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
9160 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9161 return new IndexerExpr (indexers, type, this);
9164 if (type != InternalType.ErrorType) {
9165 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
9166 type.GetSignatureForError ());
9172 public override Expression CreateExpressionTree (ResolveContext ec)
9174 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
9175 Expr.CreateExpressionTree (ec));
9177 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
9180 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
9182 if (Arguments.Count != 1){
9183 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
9187 if (Arguments [0] is NamedArgument)
9188 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
9190 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
9191 return new Indirection (p, loc);
9194 protected override Expression DoResolve (ResolveContext ec)
9196 Expr = Expr.Resolve (ec);
9202 // TODO: Create 1 result for Resolve and ResolveLValue ?
9203 var res = CreateAccessExpression (ec);
9207 return res.Resolve (ec);
9210 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
9212 Expr = Expr.Resolve (ec);
9218 var res = CreateAccessExpression (ec);
9222 return res.ResolveLValue (ec, rhs);
9225 public override void Emit (EmitContext ec)
9227 throw new Exception ("Should never be reached");
9230 public static void Error_NamedArgument (NamedArgument na, Report Report)
9232 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
9235 public override string GetSignatureForError ()
9237 return Expr.GetSignatureForError ();
9240 protected override void CloneTo (CloneContext clonectx, Expression t)
9242 ElementAccess target = (ElementAccess) t;
9244 target.Expr = Expr.Clone (clonectx);
9245 if (Arguments != null)
9246 target.Arguments = Arguments.Clone (clonectx);
9249 public override object Accept (StructuralVisitor visitor)
9251 return visitor.Visit (this);
9256 /// Implements array access
9258 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
9260 // Points to our "data" repository
9264 LocalTemporary temp;
9266 bool? has_await_args;
9268 public ArrayAccess (ElementAccess ea_data, Location l)
9274 public void AddressOf (EmitContext ec, AddressOp mode)
9276 var ac = (ArrayContainer) ea.Expr.Type;
9278 LoadInstanceAndArguments (ec, false, false);
9280 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
9281 ec.Emit (OpCodes.Readonly);
9283 ec.EmitArrayAddress (ac);
9286 public override Expression CreateExpressionTree (ResolveContext ec)
9288 return ea.CreateExpressionTree (ec);
9291 public override bool ContainsEmitWithAwait ()
9293 return ea.ContainsEmitWithAwait ();
9296 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9298 return DoResolve (ec);
9301 protected override Expression DoResolve (ResolveContext ec)
9303 // dynamic is used per argument in ConvertExpressionToArrayIndex case
9305 ea.Arguments.Resolve (ec, out dynamic);
9307 var ac = ea.Expr.Type as ArrayContainer;
9308 int rank = ea.Arguments.Count;
9309 if (ac.Rank != rank) {
9310 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
9311 rank.ToString (), ac.Rank.ToString ());
9316 if (type.IsPointer && !ec.IsUnsafe) {
9317 UnsafeError (ec, ea.Location);
9320 foreach (Argument a in ea.Arguments) {
9321 if (a is NamedArgument)
9322 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
9324 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
9327 eclass = ExprClass.Variable;
9332 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
9334 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
9338 // Load the array arguments into the stack.
9340 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
9343 ea.Expr = ea.Expr.EmitToField (ec);
9344 } else if (duplicateArguments) {
9346 ec.Emit (OpCodes.Dup);
9348 var copy = new LocalTemporary (ea.Expr.Type);
9355 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
9356 if (dup_args != null)
9357 ea.Arguments = dup_args;
9360 public void Emit (EmitContext ec, bool leave_copy)
9362 var ac = ea.Expr.Type as ArrayContainer;
9365 ec.EmitLoadFromPtr (type);
9367 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
9368 LoadInstanceAndArguments (ec, false, true);
9371 LoadInstanceAndArguments (ec, false, false);
9372 ec.EmitArrayLoad (ac);
9376 ec.Emit (OpCodes.Dup);
9377 temp = new LocalTemporary (this.type);
9382 public override void Emit (EmitContext ec)
9387 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9389 var ac = (ArrayContainer) ea.Expr.Type;
9390 TypeSpec t = source.Type;
9392 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
9395 // When we are dealing with a struct, get the address of it to avoid value copy
9396 // Same cannot be done for reference type because array covariance and the
9397 // check in ldelema requires to specify the type of array element stored at the index
9399 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
9400 LoadInstanceAndArguments (ec, false, has_await_args.Value);
9402 if (has_await_args.Value) {
9403 if (source.ContainsEmitWithAwait ()) {
9404 source = source.EmitToField (ec);
9409 LoadInstanceAndArguments (ec, isCompound, false);
9414 ec.EmitArrayAddress (ac);
9417 ec.Emit (OpCodes.Dup);
9421 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
9423 if (has_await_args.Value) {
9424 if (source.ContainsEmitWithAwait ())
9425 source = source.EmitToField (ec);
9427 LoadInstanceAndArguments (ec, false, false);
9434 var lt = ea.Expr as LocalTemporary;
9440 ec.Emit (OpCodes.Dup);
9441 temp = new LocalTemporary (this.type);
9446 ec.EmitStoreFromPtr (t);
9448 ec.EmitArrayStore (ac);
9457 public override Expression EmitToField (EmitContext ec)
9460 // Have to be specialized for arrays to get access to
9461 // underlying element. Instead of another result copy we
9462 // need direct access to element
9466 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
9468 ea.Expr = ea.Expr.EmitToField (ec);
9472 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9474 #if NET_4_0 || MONODROID
9475 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9477 throw new NotImplementedException ();
9481 public override SLE.Expression MakeExpression (BuilderContext ctx)
9483 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9486 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
9488 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9489 return Arguments.MakeExpression (ea.Arguments, ctx);
9495 // Indexer access expression
9497 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
9499 IList<MemberSpec> indexers;
9500 Arguments arguments;
9501 TypeSpec queried_type;
9503 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
9504 : base (ea.Location)
9506 this.indexers = indexers;
9507 this.queried_type = queriedType;
9508 this.InstanceExpression = ea.Expr;
9509 this.arguments = ea.Arguments;
9514 protected override Arguments Arguments {
9523 protected override TypeSpec DeclaringType {
9525 return best_candidate.DeclaringType;
9529 public override bool IsInstance {
9535 public override bool IsStatic {
9541 public override string KindName {
9542 get { return "indexer"; }
9545 public override string Name {
9553 public override bool ContainsEmitWithAwait ()
9555 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
9558 public override Expression CreateExpressionTree (ResolveContext ec)
9560 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
9561 InstanceExpression.CreateExpressionTree (ec),
9562 new TypeOfMethod (Getter, loc));
9564 return CreateExpressionFactoryCall (ec, "Call", args);
9567 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9569 LocalTemporary await_source_arg = null;
9572 emitting_compound_assignment = true;
9573 if (source is DynamicExpressionStatement) {
9578 emitting_compound_assignment = false;
9580 if (has_await_arguments) {
9581 await_source_arg = new LocalTemporary (Type);
9582 await_source_arg.Store (ec);
9584 arguments.Add (new Argument (await_source_arg));
9587 temp = await_source_arg;
9590 has_await_arguments = false;
9595 ec.Emit (OpCodes.Dup);
9596 temp = new LocalTemporary (Type);
9602 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9603 source = source.EmitToField (ec);
9605 temp = new LocalTemporary (Type);
9612 arguments.Add (new Argument (source));
9615 var call = new CallEmitter ();
9616 call.InstanceExpression = InstanceExpression;
9617 if (arguments == null)
9618 call.InstanceExpressionOnStack = true;
9620 call.Emit (ec, Setter, arguments, loc);
9625 } else if (leave_copy) {
9629 if (await_source_arg != null) {
9630 await_source_arg.Release (ec);
9634 public override string GetSignatureForError ()
9636 return best_candidate.GetSignatureForError ();
9639 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9642 throw new NotSupportedException ();
9644 var value = new[] { source.MakeExpression (ctx) };
9645 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9646 #if NET_4_0 || MONODROID
9647 return SLE.Expression.Block (
9648 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9651 return args.First ();
9656 public override SLE.Expression MakeExpression (BuilderContext ctx)
9659 return base.MakeExpression (ctx);
9661 var args = Arguments.MakeExpression (arguments, ctx);
9662 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9666 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9668 if (best_candidate != null)
9671 eclass = ExprClass.IndexerAccess;
9674 arguments.Resolve (rc, out dynamic);
9676 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9679 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9680 res.BaseMembersProvider = this;
9681 res.InstanceQualifier = this;
9683 // TODO: Do I need 2 argument sets?
9684 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9685 if (best_candidate != null)
9686 type = res.BestCandidateReturnType;
9687 else if (!res.BestCandidateIsDynamic)
9692 // It has dynamic arguments
9695 Arguments args = new Arguments (arguments.Count + 1);
9697 rc.Report.Error (1972, loc,
9698 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9700 args.Add (new Argument (InstanceExpression));
9702 args.AddRange (arguments);
9704 best_candidate = null;
9705 return new DynamicIndexBinder (args, loc);
9709 // Try to avoid resolving left expression again
9711 if (right_side != null)
9712 ResolveInstanceExpression (rc, right_side);
9717 protected override void CloneTo (CloneContext clonectx, Expression t)
9719 IndexerExpr target = (IndexerExpr) t;
9721 if (arguments != null)
9722 target.arguments = arguments.Clone (clonectx);
9725 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9727 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9730 #region IBaseMembersProvider Members
9732 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9734 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9737 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9739 if (queried_type == member.DeclaringType)
9742 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9743 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9746 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9755 // A base access expression
9757 public class BaseThis : This
9759 public BaseThis (Location loc)
9764 public BaseThis (TypeSpec type, Location loc)
9768 eclass = ExprClass.Variable;
9773 public override string Name {
9781 public override Expression CreateExpressionTree (ResolveContext ec)
9783 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9784 return base.CreateExpressionTree (ec);
9787 public override void Emit (EmitContext ec)
9791 var context_type = ec.CurrentType;
9792 if (context_type.IsStruct) {
9793 ec.Emit (OpCodes.Ldobj, context_type);
9794 ec.Emit (OpCodes.Box, context_type);
9798 protected override void Error_ThisNotAvailable (ResolveContext ec)
9801 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9803 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9807 public override void ResolveBase (ResolveContext ec)
9809 base.ResolveBase (ec);
9810 type = ec.CurrentType.BaseType;
9813 public override object Accept (StructuralVisitor visitor)
9815 return visitor.Visit (this);
9820 /// This class exists solely to pass the Type around and to be a dummy
9821 /// that can be passed to the conversion functions (this is used by
9822 /// foreach implementation to typecast the object return value from
9823 /// get_Current into the proper type. All code has been generated and
9824 /// we only care about the side effect conversions to be performed
9826 /// This is also now used as a placeholder where a no-action expression
9827 /// is needed (the `New' class).
9829 public class EmptyExpression : Expression
9831 sealed class OutAccessExpression : EmptyExpression
9833 public OutAccessExpression (TypeSpec t)
9838 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9840 rc.Report.Error (206, right_side.Location,
9841 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
9847 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
9848 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
9849 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
9850 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
9851 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
9852 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
9853 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
9854 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
9856 public EmptyExpression (TypeSpec t)
9859 eclass = ExprClass.Value;
9860 loc = Location.Null;
9863 public override bool ContainsEmitWithAwait ()
9868 public override Expression CreateExpressionTree (ResolveContext ec)
9870 throw new NotSupportedException ("ET");
9873 protected override Expression DoResolve (ResolveContext ec)
9878 public override void Emit (EmitContext ec)
9880 // nothing, as we only exist to not do anything.
9883 public override void EmitSideEffect (EmitContext ec)
9887 public override object Accept (StructuralVisitor visitor)
9889 return visitor.Visit (this);
9893 sealed class EmptyAwaitExpression : EmptyExpression
9895 public EmptyAwaitExpression (TypeSpec type)
9900 public override bool ContainsEmitWithAwait ()
9907 // Empty statement expression
9909 public sealed class EmptyExpressionStatement : ExpressionStatement
9911 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
9913 private EmptyExpressionStatement ()
9915 loc = Location.Null;
9918 public override bool ContainsEmitWithAwait ()
9923 public override Expression CreateExpressionTree (ResolveContext ec)
9928 public override void EmitStatement (EmitContext ec)
9933 protected override Expression DoResolve (ResolveContext ec)
9935 eclass = ExprClass.Value;
9936 type = ec.BuiltinTypes.Object;
9940 public override void Emit (EmitContext ec)
9945 public override object Accept (StructuralVisitor visitor)
9947 return visitor.Visit (this);
9951 public class ErrorExpression : EmptyExpression
9953 public static readonly ErrorExpression Instance = new ErrorExpression ();
9955 private ErrorExpression ()
9956 : base (InternalType.ErrorType)
9960 public override Expression CreateExpressionTree (ResolveContext ec)
9965 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9970 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
9974 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
9978 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
9982 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
9986 public override object Accept (StructuralVisitor visitor)
9988 return visitor.Visit (this);
9992 public class UserCast : Expression {
9996 public UserCast (MethodSpec method, Expression source, Location l)
9999 throw new ArgumentNullException ("source");
10001 this.method = method;
10002 this.source = source;
10003 type = method.ReturnType;
10007 public Expression Source {
10013 public override bool ContainsEmitWithAwait ()
10015 return source.ContainsEmitWithAwait ();
10018 public override Expression CreateExpressionTree (ResolveContext ec)
10020 Arguments args = new Arguments (3);
10021 args.Add (new Argument (source.CreateExpressionTree (ec)));
10022 args.Add (new Argument (new TypeOf (type, loc)));
10023 args.Add (new Argument (new TypeOfMethod (method, loc)));
10024 return CreateExpressionFactoryCall (ec, "Convert", args);
10027 protected override Expression DoResolve (ResolveContext ec)
10029 ObsoleteAttribute oa = method.GetAttributeObsolete ();
10031 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
10033 eclass = ExprClass.Value;
10037 public override void Emit (EmitContext ec)
10040 ec.Emit (OpCodes.Call, method);
10043 public override string GetSignatureForError ()
10045 return TypeManager.CSharpSignature (method);
10048 public override SLE.Expression MakeExpression (BuilderContext ctx)
10051 return base.MakeExpression (ctx);
10053 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
10059 // Holds additional type specifiers like ?, *, []
10061 public class ComposedTypeSpecifier
10063 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
10065 public readonly int Dimension;
10066 public readonly Location Location;
10068 public ComposedTypeSpecifier (int specifier, Location loc)
10070 this.Dimension = specifier;
10071 this.Location = loc;
10075 public bool IsNullable {
10077 return Dimension == -1;
10081 public bool IsPointer {
10083 return Dimension == -2;
10087 public ComposedTypeSpecifier Next { get; set; }
10091 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
10093 return new ComposedTypeSpecifier (dimension, loc);
10096 public static ComposedTypeSpecifier CreateNullable (Location loc)
10098 return new ComposedTypeSpecifier (-1, loc);
10101 public static ComposedTypeSpecifier CreatePointer (Location loc)
10103 return new ComposedTypeSpecifier (-2, loc);
10106 public string GetSignatureForError ()
10111 ArrayContainer.GetPostfixSignature (Dimension);
10113 return Next != null ? s + Next.GetSignatureForError () : s;
10118 // This class is used to "construct" the type during a typecast
10119 // operation. Since the Type.GetType class in .NET can parse
10120 // the type specification, we just use this to construct the type
10121 // one bit at a time.
10123 public class ComposedCast : TypeExpr {
10124 FullNamedExpression left;
10125 ComposedTypeSpecifier spec;
10127 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
10130 throw new ArgumentNullException ("spec");
10134 this.loc = left.Location;
10137 public override TypeSpec ResolveAsType (IMemberContext ec)
10139 type = left.ResolveAsType (ec);
10143 eclass = ExprClass.Type;
10145 var single_spec = spec;
10147 if (single_spec.IsNullable) {
10148 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
10152 single_spec = single_spec.Next;
10153 } else if (single_spec.IsPointer) {
10154 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
10157 if (!ec.IsUnsafe) {
10158 UnsafeError (ec.Module.Compiler.Report, loc);
10162 type = PointerContainer.MakeType (ec.Module, type);
10163 single_spec = single_spec.Next;
10164 } while (single_spec != null && single_spec.IsPointer);
10167 if (single_spec != null && single_spec.Dimension > 0) {
10168 if (type.IsSpecialRuntimeType) {
10169 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
10170 } else if (type.IsStatic) {
10171 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
10172 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
10173 type.GetSignatureForError ());
10175 MakeArray (ec.Module, single_spec);
10182 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
10184 if (spec.Next != null)
10185 MakeArray (module, spec.Next);
10187 type = ArrayContainer.MakeType (module, type, spec.Dimension);
10190 public override string GetSignatureForError ()
10192 return left.GetSignatureForError () + spec.GetSignatureForError ();
10195 public override object Accept (StructuralVisitor visitor)
10197 return visitor.Visit (this);
10201 class FixedBufferPtr : Expression
10203 readonly Expression array;
10205 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
10207 this.type = array_type;
10208 this.array = array;
10212 public override bool ContainsEmitWithAwait ()
10214 throw new NotImplementedException ();
10217 public override Expression CreateExpressionTree (ResolveContext ec)
10219 Error_PointerInsideExpressionTree (ec);
10223 public override void Emit(EmitContext ec)
10228 protected override Expression DoResolve (ResolveContext ec)
10230 type = PointerContainer.MakeType (ec.Module, type);
10231 eclass = ExprClass.Value;
10238 // This class is used to represent the address of an array, used
10239 // only by the Fixed statement, this generates "&a [0]" construct
10240 // for fixed (char *pa = a)
10242 class ArrayPtr : FixedBufferPtr
10244 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
10245 base (array, array_type, l)
10249 public override void Emit (EmitContext ec)
10254 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
10259 // Encapsulates a conversion rules required for array indexes
10261 public class ArrayIndexCast : TypeCast
10263 public ArrayIndexCast (Expression expr, TypeSpec returnType)
10264 : base (expr, returnType)
10266 if (expr.Type == returnType) // int -> int
10267 throw new ArgumentException ("unnecessary array index conversion");
10270 public override Expression CreateExpressionTree (ResolveContext ec)
10272 using (ec.Set (ResolveContext.Options.CheckedScope)) {
10273 return base.CreateExpressionTree (ec);
10277 public override void Emit (EmitContext ec)
10281 switch (child.Type.BuiltinType) {
10282 case BuiltinTypeSpec.Type.UInt:
10283 ec.Emit (OpCodes.Conv_U);
10285 case BuiltinTypeSpec.Type.Long:
10286 ec.Emit (OpCodes.Conv_Ovf_I);
10288 case BuiltinTypeSpec.Type.ULong:
10289 ec.Emit (OpCodes.Conv_Ovf_I_Un);
10292 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
10298 // Implements the `stackalloc' keyword
10300 public class StackAlloc : Expression {
10305 public StackAlloc (Expression type, Expression count, Location l)
10308 this.count = count;
10312 public Expression TypeExpression {
10318 public Expression CountExpression {
10324 public override bool ContainsEmitWithAwait ()
10329 public override Expression CreateExpressionTree (ResolveContext ec)
10331 throw new NotSupportedException ("ET");
10334 protected override Expression DoResolve (ResolveContext ec)
10336 count = count.Resolve (ec);
10340 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
10341 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
10346 Constant c = count as Constant;
10347 if (c != null && c.IsNegative) {
10348 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
10351 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
10352 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
10355 otype = t.ResolveAsType (ec);
10359 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
10362 type = PointerContainer.MakeType (ec.Module, otype);
10363 eclass = ExprClass.Value;
10368 public override void Emit (EmitContext ec)
10370 int size = BuiltinTypeSpec.GetSize (otype);
10375 ec.Emit (OpCodes.Sizeof, otype);
10379 ec.Emit (OpCodes.Mul_Ovf_Un);
10380 ec.Emit (OpCodes.Localloc);
10383 protected override void CloneTo (CloneContext clonectx, Expression t)
10385 StackAlloc target = (StackAlloc) t;
10386 target.count = count.Clone (clonectx);
10387 target.t = t.Clone (clonectx);
10390 public override object Accept (StructuralVisitor visitor)
10392 return visitor.Visit (this);
10397 // An object initializer expression
10399 public class ElementInitializer : Assign
10401 public readonly string Name;
10403 public ElementInitializer (string name, Expression initializer, Location loc)
10404 : base (null, initializer, loc)
10409 protected override void CloneTo (CloneContext clonectx, Expression t)
10411 ElementInitializer target = (ElementInitializer) t;
10412 target.source = source.Clone (clonectx);
10415 public override Expression CreateExpressionTree (ResolveContext ec)
10417 Arguments args = new Arguments (2);
10418 FieldExpr fe = target as FieldExpr;
10420 args.Add (new Argument (fe.CreateTypeOfExpression ()));
10422 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
10425 Expression arg_expr;
10426 var cinit = source as CollectionOrObjectInitializers;
10427 if (cinit == null) {
10429 arg_expr = source.CreateExpressionTree (ec);
10431 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
10432 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
10435 args.Add (new Argument (arg_expr));
10436 return CreateExpressionFactoryCall (ec, mname, args);
10439 protected override Expression DoResolve (ResolveContext ec)
10441 if (source == null)
10442 return EmptyExpressionStatement.Instance;
10444 var t = ec.CurrentInitializerVariable.Type;
10445 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10446 Arguments args = new Arguments (1);
10447 args.Add (new Argument (ec.CurrentInitializerVariable));
10448 target = new DynamicMemberBinder (Name, args, loc);
10451 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10452 if (member == null) {
10453 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10455 if (member != null) {
10456 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
10457 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
10462 if (member == null) {
10463 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
10467 if (!(member is PropertyExpr || member is FieldExpr)) {
10468 ec.Report.Error (1913, loc,
10469 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
10470 member.GetSignatureForError ());
10475 var me = member as MemberExpr;
10477 ec.Report.Error (1914, loc,
10478 "Static field or property `{0}' cannot be assigned in an object initializer",
10479 me.GetSignatureForError ());
10483 me.InstanceExpression = ec.CurrentInitializerVariable;
10486 if (source is CollectionOrObjectInitializers) {
10487 Expression previous = ec.CurrentInitializerVariable;
10488 ec.CurrentInitializerVariable = target;
10489 source = source.Resolve (ec);
10490 ec.CurrentInitializerVariable = previous;
10491 if (source == null)
10494 eclass = source.eclass;
10495 type = source.Type;
10499 return base.DoResolve (ec);
10502 public override void EmitStatement (EmitContext ec)
10504 if (source is CollectionOrObjectInitializers)
10507 base.EmitStatement (ec);
10512 // A collection initializer expression
10514 class CollectionElementInitializer : Invocation
10516 public class ElementInitializerArgument : Argument
10518 public ElementInitializerArgument (Expression e)
10524 sealed class AddMemberAccess : MemberAccess
10526 public AddMemberAccess (Expression expr, Location loc)
10527 : base (expr, "Add", loc)
10531 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10533 if (TypeManager.HasElementType (type))
10536 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10540 public CollectionElementInitializer (Expression argument)
10541 : base (null, new Arguments (1))
10543 base.arguments.Add (new ElementInitializerArgument (argument));
10544 this.loc = argument.Location;
10547 public CollectionElementInitializer (List<Expression> arguments, Location loc)
10548 : base (null, new Arguments (arguments.Count))
10550 foreach (Expression e in arguments)
10551 base.arguments.Add (new ElementInitializerArgument (e));
10556 public override Expression CreateExpressionTree (ResolveContext ec)
10558 Arguments args = new Arguments (2);
10559 args.Add (new Argument (mg.CreateExpressionTree (ec)));
10561 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
10562 foreach (Argument a in arguments)
10563 expr_initializers.Add (a.CreateExpressionTree (ec));
10565 args.Add (new Argument (new ArrayCreation (
10566 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
10567 return CreateExpressionFactoryCall (ec, "ElementInit", args);
10570 protected override void CloneTo (CloneContext clonectx, Expression t)
10572 CollectionElementInitializer target = (CollectionElementInitializer) t;
10573 if (arguments != null)
10574 target.arguments = arguments.Clone (clonectx);
10577 protected override Expression DoResolve (ResolveContext ec)
10579 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
10581 return base.DoResolve (ec);
10586 // A block of object or collection initializers
10588 public class CollectionOrObjectInitializers : ExpressionStatement
10590 IList<Expression> initializers;
10591 bool is_collection_initialization;
10593 public CollectionOrObjectInitializers (Location loc)
10594 : this (new Expression[0], loc)
10598 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10600 this.initializers = initializers;
10604 public IList<Expression> Initializers {
10606 return initializers;
10610 public bool IsEmpty {
10612 return initializers.Count == 0;
10616 public bool IsCollectionInitializer {
10618 return is_collection_initialization;
10622 protected override void CloneTo (CloneContext clonectx, Expression target)
10624 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10626 t.initializers = new List<Expression> (initializers.Count);
10627 foreach (var e in initializers)
10628 t.initializers.Add (e.Clone (clonectx));
10631 public override bool ContainsEmitWithAwait ()
10633 foreach (var e in initializers) {
10634 if (e.ContainsEmitWithAwait ())
10641 public override Expression CreateExpressionTree (ResolveContext ec)
10643 return CreateExpressionTree (ec, false);
10646 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10648 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10649 foreach (Expression e in initializers) {
10650 Expression expr = e.CreateExpressionTree (ec);
10652 expr_initializers.Add (expr);
10656 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10658 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10661 protected override Expression DoResolve (ResolveContext ec)
10663 List<string> element_names = null;
10664 for (int i = 0; i < initializers.Count; ++i) {
10665 Expression initializer = initializers [i];
10666 ElementInitializer element_initializer = initializer as ElementInitializer;
10669 if (element_initializer != null) {
10670 element_names = new List<string> (initializers.Count);
10671 element_names.Add (element_initializer.Name);
10672 } else if (initializer is CompletingExpression){
10673 initializer.Resolve (ec);
10674 throw new InternalErrorException ("This line should never be reached");
10676 var t = ec.CurrentInitializerVariable.Type;
10677 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10678 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10679 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10680 "object initializer because type `{1}' does not implement `{2}' interface",
10681 ec.CurrentInitializerVariable.GetSignatureForError (),
10682 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10683 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10686 is_collection_initialization = true;
10689 if (is_collection_initialization != (element_initializer == null)) {
10690 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10691 is_collection_initialization ? "collection initializer" : "object initializer");
10695 if (!is_collection_initialization) {
10696 if (element_names.Contains (element_initializer.Name)) {
10697 ec.Report.Error (1912, element_initializer.Location,
10698 "An object initializer includes more than one member `{0}' initialization",
10699 element_initializer.Name);
10701 element_names.Add (element_initializer.Name);
10706 Expression e = initializer.Resolve (ec);
10707 if (e == EmptyExpressionStatement.Instance)
10708 initializers.RemoveAt (i--);
10710 initializers [i] = e;
10713 type = ec.CurrentInitializerVariable.Type;
10714 if (is_collection_initialization) {
10715 if (TypeManager.HasElementType (type)) {
10716 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10717 type.GetSignatureForError ());
10721 eclass = ExprClass.Variable;
10725 public override void Emit (EmitContext ec)
10727 EmitStatement (ec);
10730 public override void EmitStatement (EmitContext ec)
10732 foreach (ExpressionStatement e in initializers) {
10733 // TODO: need location region
10734 ec.Mark (e.Location);
10735 e.EmitStatement (ec);
10741 // New expression with element/object initializers
10743 public class NewInitialize : New
10746 // This class serves as a proxy for variable initializer target instances.
10747 // A real variable is assigned later when we resolve left side of an
10750 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10752 NewInitialize new_instance;
10754 public InitializerTargetExpression (NewInitialize newInstance)
10756 this.type = newInstance.type;
10757 this.loc = newInstance.loc;
10758 this.eclass = newInstance.eclass;
10759 this.new_instance = newInstance;
10762 public override bool ContainsEmitWithAwait ()
10767 public override Expression CreateExpressionTree (ResolveContext ec)
10769 // Should not be reached
10770 throw new NotSupportedException ("ET");
10773 protected override Expression DoResolve (ResolveContext ec)
10778 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10783 public override void Emit (EmitContext ec)
10785 Expression e = (Expression) new_instance.instance;
10789 public override Expression EmitToField (EmitContext ec)
10791 return (Expression) new_instance.instance;
10794 #region IMemoryLocation Members
10796 public void AddressOf (EmitContext ec, AddressOp mode)
10798 new_instance.instance.AddressOf (ec, mode);
10804 CollectionOrObjectInitializers initializers;
10805 IMemoryLocation instance;
10806 DynamicExpressionStatement dynamic;
10808 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10809 : base (requested_type, arguments, l)
10811 this.initializers = initializers;
10814 public CollectionOrObjectInitializers Initializers {
10816 return initializers;
10820 protected override void CloneTo (CloneContext clonectx, Expression t)
10822 base.CloneTo (clonectx, t);
10824 NewInitialize target = (NewInitialize) t;
10825 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
10828 public override bool ContainsEmitWithAwait ()
10830 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
10833 public override Expression CreateExpressionTree (ResolveContext ec)
10835 Arguments args = new Arguments (2);
10836 args.Add (new Argument (base.CreateExpressionTree (ec)));
10837 if (!initializers.IsEmpty)
10838 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
10840 return CreateExpressionFactoryCall (ec,
10841 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
10845 protected override Expression DoResolve (ResolveContext ec)
10847 Expression e = base.DoResolve (ec);
10851 if (type.IsDelegate) {
10852 ec.Report.Error (1958, Initializers.Location,
10853 "Object and collection initializers cannot be used to instantiate a delegate");
10856 Expression previous = ec.CurrentInitializerVariable;
10857 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
10858 initializers.Resolve (ec);
10859 ec.CurrentInitializerVariable = previous;
10861 dynamic = e as DynamicExpressionStatement;
10862 if (dynamic != null)
10868 public override bool Emit (EmitContext ec, IMemoryLocation target)
10870 bool left_on_stack;
10871 if (dynamic != null) {
10873 left_on_stack = true;
10875 left_on_stack = base.Emit (ec, target);
10878 if (initializers.IsEmpty)
10879 return left_on_stack;
10881 LocalTemporary temp = null;
10883 instance = target as LocalTemporary;
10885 if (instance == null) {
10886 if (!left_on_stack) {
10887 VariableReference vr = target as VariableReference;
10889 // FIXME: This still does not work correctly for pre-set variables
10890 if (vr != null && vr.IsRef)
10891 target.AddressOf (ec, AddressOp.Load);
10893 ((Expression) target).Emit (ec);
10894 left_on_stack = true;
10897 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
10898 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
10900 temp = new LocalTemporary (type);
10905 if (left_on_stack && temp != null)
10908 initializers.Emit (ec);
10910 if (left_on_stack) {
10911 if (temp != null) {
10915 ((Expression) instance).Emit (ec);
10919 return left_on_stack;
10922 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
10924 instance = base.EmitAddressOf (ec, Mode);
10926 if (!initializers.IsEmpty)
10927 initializers.Emit (ec);
10932 public override object Accept (StructuralVisitor visitor)
10934 return visitor.Visit (this);
10938 public class NewAnonymousType : New
10940 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
10942 List<AnonymousTypeParameter> parameters;
10943 readonly TypeContainer parent;
10944 AnonymousTypeClass anonymous_type;
10946 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
10947 : base (null, null, loc)
10949 this.parameters = parameters;
10950 this.parent = parent;
10953 public List<AnonymousTypeParameter> Parameters {
10955 return this.parameters;
10959 protected override void CloneTo (CloneContext clonectx, Expression target)
10961 if (parameters == null)
10964 NewAnonymousType t = (NewAnonymousType) target;
10965 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
10966 foreach (AnonymousTypeParameter atp in parameters)
10967 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
10970 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
10972 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
10976 type = AnonymousTypeClass.Create (parent, parameters, loc);
10980 int errors = ec.Report.Errors;
10981 type.CreateContainer ();
10982 type.DefineContainer ();
10984 if ((ec.Report.Errors - errors) == 0) {
10985 parent.Module.AddAnonymousType (type);
10991 public override Expression CreateExpressionTree (ResolveContext ec)
10993 if (parameters == null)
10994 return base.CreateExpressionTree (ec);
10996 var init = new ArrayInitializer (parameters.Count, loc);
10997 foreach (var m in anonymous_type.Members) {
10998 var p = m as Property;
11000 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
11003 var ctor_args = new ArrayInitializer (arguments.Count, loc);
11004 foreach (Argument a in arguments)
11005 ctor_args.Add (a.CreateExpressionTree (ec));
11007 Arguments args = new Arguments (3);
11008 args.Add (new Argument (new TypeOfMethod (method, loc)));
11009 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
11010 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
11012 return CreateExpressionFactoryCall (ec, "New", args);
11015 protected override Expression DoResolve (ResolveContext ec)
11017 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
11018 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
11022 if (parameters == null) {
11023 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
11024 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
11025 return base.DoResolve (ec);
11028 bool error = false;
11029 arguments = new Arguments (parameters.Count);
11030 var t_args = new TypeSpec [parameters.Count];
11031 for (int i = 0; i < parameters.Count; ++i) {
11032 Expression e = parameters [i].Resolve (ec);
11038 arguments.Add (new Argument (e));
11039 t_args [i] = e.Type;
11045 anonymous_type = CreateAnonymousType (ec, parameters);
11046 if (anonymous_type == null)
11049 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
11050 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
11051 eclass = ExprClass.Value;
11055 public override void EmitStatement (EmitContext ec)
11057 base.EmitStatement (ec);
11060 public override object Accept (StructuralVisitor visitor)
11062 return visitor.Visit (this);
11066 public class AnonymousTypeParameter : ShimExpression
11068 public readonly string Name;
11070 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
11071 : base (initializer)
11077 public AnonymousTypeParameter (Parameter parameter)
11078 : base (new SimpleName (parameter.Name, parameter.Location))
11080 this.Name = parameter.Name;
11081 this.loc = parameter.Location;
11084 public override bool Equals (object o)
11086 AnonymousTypeParameter other = o as AnonymousTypeParameter;
11087 return other != null && Name == other.Name;
11090 public override int GetHashCode ()
11092 return Name.GetHashCode ();
11095 protected override Expression DoResolve (ResolveContext ec)
11097 Expression e = expr.Resolve (ec);
11101 if (e.eclass == ExprClass.MethodGroup) {
11102 Error_InvalidInitializer (ec, e.ExprClassName);
11107 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
11108 Error_InvalidInitializer (ec, type.GetSignatureForError ());
11115 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
11117 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
11118 Name, initializer);