2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
19 using MetaType = IKVM.Reflection.Type;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
23 using MetaType = System.Type;
24 using System.Reflection;
25 using System.Reflection.Emit;
31 // This is an user operator expression, automatically created during
34 public class UserOperatorCall : Expression {
35 protected readonly Arguments arguments;
36 protected readonly MethodSpec oper;
37 readonly Func<ResolveContext, Expression, Expression> expr_tree;
39 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
42 this.arguments = args;
43 this.expr_tree = expr_tree;
45 type = oper.ReturnType;
46 eclass = ExprClass.Value;
50 public override bool ContainsEmitWithAwait ()
52 return arguments.ContainsEmitWithAwait ();
55 public override Expression CreateExpressionTree (ResolveContext ec)
57 if (expr_tree != null)
58 return expr_tree (ec, new TypeOfMethod (oper, loc));
60 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
61 new NullLiteral (loc),
62 new TypeOfMethod (oper, loc));
64 return CreateExpressionFactoryCall (ec, "Call", args);
67 protected override void CloneTo (CloneContext context, Expression target)
72 protected override Expression DoResolve (ResolveContext ec)
75 // We are born fully resolved
80 public override void Emit (EmitContext ec)
82 var call = new CallEmitter ();
83 call.EmitPredefined (ec, oper, arguments, loc);
86 public override 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);
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.MarkCallEntry (loc);
6537 ec.Emit (OpCodes.Call, method);
6542 if (type is TypeParameterSpec)
6543 return DoEmitTypeParameter (ec);
6545 ec.MarkCallEntry (loc);
6546 ec.Emit (OpCodes.Newobj, method);
6550 public override void Emit (EmitContext ec)
6552 LocalTemporary v = null;
6553 if (method == null && TypeSpec.IsValueType (type)) {
6554 // TODO: Use temporary variable from pool
6555 v = new LocalTemporary (type);
6562 public override void EmitStatement (EmitContext ec)
6564 LocalTemporary v = null;
6565 if (method == null && TypeSpec.IsValueType (type)) {
6566 // TODO: Use temporary variable from pool
6567 v = new LocalTemporary (type);
6571 ec.Emit (OpCodes.Pop);
6574 public void AddressOf (EmitContext ec, AddressOp mode)
6576 EmitAddressOf (ec, mode);
6579 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
6581 LocalTemporary value_target = new LocalTemporary (type);
6583 if (type is TypeParameterSpec) {
6584 DoEmitTypeParameter (ec);
6585 value_target.Store (ec);
6586 value_target.AddressOf (ec, mode);
6587 return value_target;
6590 value_target.AddressOf (ec, AddressOp.Store);
6592 if (method == null) {
6593 ec.Emit (OpCodes.Initobj, type);
6595 if (arguments != null)
6596 arguments.Emit (ec);
6598 ec.Emit (OpCodes.Call, method);
6601 value_target.AddressOf (ec, mode);
6602 return value_target;
6605 protected override void CloneTo (CloneContext clonectx, Expression t)
6607 New target = (New) t;
6609 target.RequestedType = RequestedType.Clone (clonectx);
6610 if (arguments != null){
6611 target.arguments = arguments.Clone (clonectx);
6615 public override SLE.Expression MakeExpression (BuilderContext ctx)
6618 return base.MakeExpression (ctx);
6620 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
6624 public override object Accept (StructuralVisitor visitor)
6626 return visitor.Visit (this);
6631 // Array initializer expression, the expression is allowed in
6632 // variable or field initialization only which makes it tricky as
6633 // the type has to be infered based on the context either from field
6634 // type or variable type (think of multiple declarators)
6636 public class ArrayInitializer : Expression
6638 List<Expression> elements;
6639 BlockVariable variable;
6641 public ArrayInitializer (List<Expression> init, Location loc)
6647 public ArrayInitializer (int count, Location loc)
6648 : this (new List<Expression> (count), loc)
6652 public ArrayInitializer (Location loc)
6660 get { return elements.Count; }
6663 public List<Expression> Elements {
6669 public Expression this [int index] {
6671 return elements [index];
6675 public BlockVariable VariableDeclaration {
6686 public void Add (Expression expr)
6688 elements.Add (expr);
6691 public override bool ContainsEmitWithAwait ()
6693 throw new NotSupportedException ();
6696 public override Expression CreateExpressionTree (ResolveContext ec)
6698 throw new NotSupportedException ("ET");
6701 protected override void CloneTo (CloneContext clonectx, Expression t)
6703 var target = (ArrayInitializer) t;
6705 target.elements = new List<Expression> (elements.Count);
6706 foreach (var element in elements)
6707 target.elements.Add (element.Clone (clonectx));
6710 protected override Expression DoResolve (ResolveContext rc)
6712 var current_field = rc.CurrentMemberDefinition as FieldBase;
6713 TypeExpression type;
6714 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6715 type = new TypeExpression (current_field.MemberType, current_field.Location);
6716 } else if (variable != null) {
6717 if (variable.TypeExpression is VarExpr) {
6718 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6719 return EmptyExpression.Null;
6722 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6724 throw new NotImplementedException ("Unexpected array initializer context");
6727 return new ArrayCreation (type, this).Resolve (rc);
6730 public override void Emit (EmitContext ec)
6732 throw new InternalErrorException ("Missing Resolve call");
6735 public override object Accept (StructuralVisitor visitor)
6737 return visitor.Visit (this);
6742 /// 14.5.10.2: Represents an array creation expression.
6746 /// There are two possible scenarios here: one is an array creation
6747 /// expression that specifies the dimensions and optionally the
6748 /// initialization data and the other which does not need dimensions
6749 /// specified but where initialization data is mandatory.
6751 public class ArrayCreation : Expression
6753 FullNamedExpression requested_base_type;
6754 ArrayInitializer initializers;
6757 // The list of Argument types.
6758 // This is used to construct the `newarray' or constructor signature
6760 protected List<Expression> arguments;
6762 protected TypeSpec array_element_type;
6763 int num_arguments = 0;
6764 protected int dimensions;
6765 protected readonly ComposedTypeSpecifier rank;
6766 Expression first_emit;
6767 LocalTemporary first_emit_temp;
6769 protected List<Expression> array_data;
6771 Dictionary<int, int> bounds;
6774 // The number of constants in array initializers
6775 int const_initializers_count;
6776 bool only_constant_initializers;
6778 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6779 : this (requested_base_type, rank, initializers, l)
6781 arguments = new List<Expression> (exprs);
6782 num_arguments = arguments.Count;
6786 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6788 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6790 this.requested_base_type = requested_base_type;
6792 this.initializers = initializers;
6796 num_arguments = rank.Dimension;
6800 // For compiler generated single dimensional arrays only
6802 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6803 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6808 // For expressions like int[] foo = { 1, 2, 3 };
6810 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6811 : this (requested_base_type, null, initializers, initializers.Location)
6815 public ComposedTypeSpecifier Rank {
6821 public FullNamedExpression TypeExpression {
6823 return this.requested_base_type;
6827 public ArrayInitializer Initializers {
6829 return this.initializers;
6833 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6835 if (initializers != null && bounds == null) {
6837 // We use this to store all the data values in the order in which we
6838 // will need to store them in the byte blob later
6840 array_data = new List<Expression> (probe.Count);
6841 bounds = new Dictionary<int, int> ();
6844 if (specified_dims) {
6845 Expression a = arguments [idx];
6850 a = ConvertExpressionToArrayIndex (ec, a);
6856 if (initializers != null) {
6857 Constant c = a as Constant;
6858 if (c == null && a is ArrayIndexCast)
6859 c = ((ArrayIndexCast) a).Child as Constant;
6862 ec.Report.Error (150, a.Location, "A constant value is expected");
6868 value = System.Convert.ToInt32 (c.GetValue ());
6870 ec.Report.Error (150, a.Location, "A constant value is expected");
6874 // TODO: probe.Count does not fit ulong in
6875 if (value != probe.Count) {
6876 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6880 bounds[idx] = value;
6884 if (initializers == null)
6887 for (int i = 0; i < probe.Count; ++i) {
6889 if (o is ArrayInitializer) {
6890 var sub_probe = o as ArrayInitializer;
6891 if (idx + 1 >= dimensions){
6892 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6896 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
6897 if (!bounds.ContainsKey(idx + 1))
6898 bounds[idx + 1] = sub_probe.Count;
6900 if (bounds[idx + 1] != sub_probe.Count) {
6901 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
6905 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6908 } else if (child_bounds > 1) {
6909 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6911 Expression element = ResolveArrayElement (ec, o);
6912 if (element == null)
6915 // Initializers with the default values can be ignored
6916 Constant c = element as Constant;
6918 if (!c.IsDefaultInitializer (array_element_type)) {
6919 ++const_initializers_count;
6922 only_constant_initializers = false;
6925 array_data.Add (element);
6932 public override bool ContainsEmitWithAwait ()
6934 foreach (var arg in arguments) {
6935 if (arg.ContainsEmitWithAwait ())
6939 return InitializersContainAwait ();
6942 public override Expression CreateExpressionTree (ResolveContext ec)
6946 if (array_data == null) {
6947 args = new Arguments (arguments.Count + 1);
6948 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6949 foreach (Expression a in arguments)
6950 args.Add (new Argument (a.CreateExpressionTree (ec)));
6952 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6955 if (dimensions > 1) {
6956 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6960 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6961 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6962 if (array_data != null) {
6963 for (int i = 0; i < array_data.Count; ++i) {
6964 Expression e = array_data [i];
6965 args.Add (new Argument (e.CreateExpressionTree (ec)));
6969 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6972 void UpdateIndices (ResolveContext rc)
6975 for (var probe = initializers; probe != null;) {
6976 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
6978 bounds[i++] = probe.Count;
6980 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
6981 probe = (ArrayInitializer) probe[0];
6982 } else if (dimensions > i) {
6990 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
6992 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
6995 bool InitializersContainAwait ()
6997 if (array_data == null)
7000 foreach (var expr in array_data) {
7001 if (expr.ContainsEmitWithAwait ())
7008 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
7010 element = element.Resolve (ec);
7011 if (element == null)
7014 if (element is CompoundAssign.TargetExpression) {
7015 if (first_emit != null)
7016 throw new InternalErrorException ("Can only handle one mutator at a time");
7017 first_emit = element;
7018 element = first_emit_temp = new LocalTemporary (element.Type);
7021 return Convert.ImplicitConversionRequired (
7022 ec, element, array_element_type, loc);
7025 protected bool ResolveInitializers (ResolveContext ec)
7028 only_constant_initializers = true;
7031 if (arguments != null) {
7033 for (int i = 0; i < arguments.Count; ++i) {
7034 res &= CheckIndices (ec, initializers, i, true, dimensions);
7035 if (initializers != null)
7042 arguments = new List<Expression> ();
7044 if (!CheckIndices (ec, initializers, 0, false, dimensions))
7053 // Resolved the type of the array
7055 bool ResolveArrayType (ResolveContext ec)
7060 FullNamedExpression array_type_expr;
7061 if (num_arguments > 0) {
7062 array_type_expr = new ComposedCast (requested_base_type, rank);
7064 array_type_expr = requested_base_type;
7067 type = array_type_expr.ResolveAsType (ec);
7068 if (array_type_expr == null)
7071 var ac = type as ArrayContainer;
7073 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
7077 array_element_type = ac.Element;
7078 dimensions = ac.Rank;
7083 protected override Expression DoResolve (ResolveContext ec)
7088 if (!ResolveArrayType (ec))
7092 // validate the initializers and fill in any missing bits
7094 if (!ResolveInitializers (ec))
7097 eclass = ExprClass.Value;
7101 byte [] MakeByteBlob ()
7106 int count = array_data.Count;
7108 TypeSpec element_type = array_element_type;
7109 if (element_type.IsEnum)
7110 element_type = EnumSpec.GetUnderlyingType (element_type);
7112 factor = BuiltinTypeSpec.GetSize (element_type);
7114 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
7116 data = new byte [(count * factor + 3) & ~3];
7119 for (int i = 0; i < count; ++i) {
7120 var c = array_data[i] as Constant;
7126 object v = c.GetValue ();
7128 switch (element_type.BuiltinType) {
7129 case BuiltinTypeSpec.Type.Long:
7130 long lval = (long) v;
7132 for (int j = 0; j < factor; ++j) {
7133 data[idx + j] = (byte) (lval & 0xFF);
7137 case BuiltinTypeSpec.Type.ULong:
7138 ulong ulval = (ulong) v;
7140 for (int j = 0; j < factor; ++j) {
7141 data[idx + j] = (byte) (ulval & 0xFF);
7142 ulval = (ulval >> 8);
7145 case BuiltinTypeSpec.Type.Float:
7146 var fval = SingleConverter.SingleToInt32Bits((float) v);
7148 data[idx] = (byte) (fval & 0xff);
7149 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
7150 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
7151 data[idx + 3] = (byte) (fval >> 24);
7153 case BuiltinTypeSpec.Type.Double:
7154 element = BitConverter.GetBytes ((double) v);
7156 for (int j = 0; j < factor; ++j)
7157 data[idx + j] = element[j];
7159 // FIXME: Handle the ARM float format.
7160 if (!BitConverter.IsLittleEndian)
7161 System.Array.Reverse (data, idx, 8);
7163 case BuiltinTypeSpec.Type.Char:
7164 int chval = (int) ((char) v);
7166 data[idx] = (byte) (chval & 0xff);
7167 data[idx + 1] = (byte) (chval >> 8);
7169 case BuiltinTypeSpec.Type.Short:
7170 int sval = (int) ((short) v);
7172 data[idx] = (byte) (sval & 0xff);
7173 data[idx + 1] = (byte) (sval >> 8);
7175 case BuiltinTypeSpec.Type.UShort:
7176 int usval = (int) ((ushort) v);
7178 data[idx] = (byte) (usval & 0xff);
7179 data[idx + 1] = (byte) (usval >> 8);
7181 case BuiltinTypeSpec.Type.Int:
7184 data[idx] = (byte) (val & 0xff);
7185 data[idx + 1] = (byte) ((val >> 8) & 0xff);
7186 data[idx + 2] = (byte) ((val >> 16) & 0xff);
7187 data[idx + 3] = (byte) (val >> 24);
7189 case BuiltinTypeSpec.Type.UInt:
7190 uint uval = (uint) v;
7192 data[idx] = (byte) (uval & 0xff);
7193 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
7194 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
7195 data[idx + 3] = (byte) (uval >> 24);
7197 case BuiltinTypeSpec.Type.SByte:
7198 data[idx] = (byte) (sbyte) v;
7200 case BuiltinTypeSpec.Type.Byte:
7201 data[idx] = (byte) v;
7203 case BuiltinTypeSpec.Type.Bool:
7204 data[idx] = (byte) ((bool) v ? 1 : 0);
7206 case BuiltinTypeSpec.Type.Decimal:
7207 int[] bits = Decimal.GetBits ((decimal) v);
7210 // FIXME: For some reason, this doesn't work on the MS runtime.
7211 int[] nbits = new int[4];
7217 for (int j = 0; j < 4; j++) {
7218 data[p++] = (byte) (nbits[j] & 0xff);
7219 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
7220 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
7221 data[p++] = (byte) (nbits[j] >> 24);
7225 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
7234 #if NET_4_0 || MONODROID
7235 public override SLE.Expression MakeExpression (BuilderContext ctx)
7238 return base.MakeExpression (ctx);
7240 var initializers = new SLE.Expression [array_data.Count];
7241 for (var i = 0; i < initializers.Length; i++) {
7242 if (array_data [i] == null)
7243 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
7245 initializers [i] = array_data [i].MakeExpression (ctx);
7248 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
7254 // Emits the initializers for the array
7256 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
7258 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
7263 // First, the static data
7265 byte [] data = MakeByteBlob ();
7266 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
7268 if (stackArray == null) {
7269 ec.Emit (OpCodes.Dup);
7271 stackArray.Emit (ec);
7274 ec.Emit (OpCodes.Ldtoken, fb);
7275 ec.Emit (OpCodes.Call, m);
7280 // Emits pieces of the array that can not be computed at compile
7281 // time (variables and string locations).
7283 // This always expect the top value on the stack to be the array
7285 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
7287 int dims = bounds.Count;
7288 var current_pos = new int [dims];
7290 for (int i = 0; i < array_data.Count; i++){
7292 Expression e = array_data [i];
7293 var c = e as Constant;
7295 // Constant can be initialized via StaticInitializer
7296 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
7300 if (stackArray != null) {
7301 if (e.ContainsEmitWithAwait ()) {
7302 e = e.EmitToField (ec);
7305 stackArray.Emit (ec);
7307 ec.Emit (OpCodes.Dup);
7310 for (int idx = 0; idx < dims; idx++)
7311 ec.EmitInt (current_pos [idx]);
7314 // If we are dealing with a struct, get the
7315 // address of it, so we can store it.
7317 if (dims == 1 && etype.IsStruct) {
7318 switch (etype.BuiltinType) {
7319 case BuiltinTypeSpec.Type.Byte:
7320 case BuiltinTypeSpec.Type.SByte:
7321 case BuiltinTypeSpec.Type.Bool:
7322 case BuiltinTypeSpec.Type.Short:
7323 case BuiltinTypeSpec.Type.UShort:
7324 case BuiltinTypeSpec.Type.Char:
7325 case BuiltinTypeSpec.Type.Int:
7326 case BuiltinTypeSpec.Type.UInt:
7327 case BuiltinTypeSpec.Type.Long:
7328 case BuiltinTypeSpec.Type.ULong:
7329 case BuiltinTypeSpec.Type.Float:
7330 case BuiltinTypeSpec.Type.Double:
7333 ec.Emit (OpCodes.Ldelema, etype);
7340 ec.EmitArrayStore ((ArrayContainer) type);
7346 for (int j = dims - 1; j >= 0; j--){
7348 if (current_pos [j] < bounds [j])
7350 current_pos [j] = 0;
7355 public override void Emit (EmitContext ec)
7357 EmitToFieldSource (ec);
7360 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
7362 if (first_emit != null) {
7363 first_emit.Emit (ec);
7364 first_emit_temp.Store (ec);
7367 FieldExpr await_stack_field;
7368 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
7369 await_stack_field = ec.GetTemporaryField (type);
7372 await_stack_field = null;
7375 EmitExpressionsList (ec, arguments);
7377 ec.EmitArrayNew ((ArrayContainer) type);
7379 if (initializers == null)
7380 return await_stack_field;
7382 if (await_stack_field != null)
7383 await_stack_field.EmitAssignFromStack (ec);
7387 // Emit static initializer for arrays which contain more than 2 items and
7388 // the static initializer will initialize at least 25% of array values or there
7389 // is more than 10 items to be initialized
7391 // NOTE: const_initializers_count does not contain default constant values.
7393 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
7394 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
7395 EmitStaticInitializers (ec, await_stack_field);
7397 if (!only_constant_initializers)
7398 EmitDynamicInitializers (ec, false, await_stack_field);
7402 EmitDynamicInitializers (ec, true, await_stack_field);
7405 if (first_emit_temp != null)
7406 first_emit_temp.Release (ec);
7408 return await_stack_field;
7411 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7413 // no multi dimensional or jagged arrays
7414 if (arguments.Count != 1 || array_element_type.IsArray) {
7415 base.EncodeAttributeValue (rc, enc, targetType);
7419 // No array covariance, except for array -> object
7420 if (type != targetType) {
7421 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
7422 base.EncodeAttributeValue (rc, enc, targetType);
7426 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
7427 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7432 // Single dimensional array of 0 size
7433 if (array_data == null) {
7434 IntConstant ic = arguments[0] as IntConstant;
7435 if (ic == null || !ic.IsDefaultValue) {
7436 base.EncodeAttributeValue (rc, enc, targetType);
7444 enc.Encode (array_data.Count);
7445 foreach (var element in array_data) {
7446 element.EncodeAttributeValue (rc, enc, array_element_type);
7450 protected override void CloneTo (CloneContext clonectx, Expression t)
7452 ArrayCreation target = (ArrayCreation) t;
7454 if (requested_base_type != null)
7455 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
7457 if (arguments != null){
7458 target.arguments = new List<Expression> (arguments.Count);
7459 foreach (Expression e in arguments)
7460 target.arguments.Add (e.Clone (clonectx));
7463 if (initializers != null)
7464 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
7467 public override object Accept (StructuralVisitor visitor)
7469 return visitor.Visit (this);
7474 // Represents an implicitly typed array epxression
7476 class ImplicitlyTypedArrayCreation : ArrayCreation
7478 TypeInferenceContext best_type_inference;
7480 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7481 : base (null, rank, initializers, loc)
7485 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
7486 : base (null, initializers, loc)
7490 protected override Expression DoResolve (ResolveContext ec)
7495 dimensions = rank.Dimension;
7497 best_type_inference = new TypeInferenceContext ();
7499 if (!ResolveInitializers (ec))
7502 best_type_inference.FixAllTypes (ec);
7503 array_element_type = best_type_inference.InferredTypeArguments[0];
7504 best_type_inference = null;
7506 if (array_element_type == null ||
7507 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
7508 arguments.Count != rank.Dimension) {
7509 ec.Report.Error (826, loc,
7510 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
7515 // At this point we found common base type for all initializer elements
7516 // but we have to be sure that all static initializer elements are of
7519 UnifyInitializerElement (ec);
7521 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
7522 eclass = ExprClass.Value;
7527 // Converts static initializer only
7529 void UnifyInitializerElement (ResolveContext ec)
7531 for (int i = 0; i < array_data.Count; ++i) {
7532 Expression e = array_data[i];
7534 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
7538 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
7540 element = element.Resolve (ec);
7541 if (element != null)
7542 best_type_inference.AddCommonTypeBound (element.Type);
7548 sealed class CompilerGeneratedThis : This
7550 public CompilerGeneratedThis (TypeSpec type, Location loc)
7554 eclass = ExprClass.Variable;
7557 protected override Expression DoResolve (ResolveContext ec)
7562 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7569 /// Represents the `this' construct
7572 public class This : VariableReference
7574 sealed class ThisVariable : ILocalVariable
7576 public static readonly ILocalVariable Instance = new ThisVariable ();
7578 public void Emit (EmitContext ec)
7583 public void EmitAssign (EmitContext ec)
7585 throw new InvalidOperationException ();
7588 public void EmitAddressOf (EmitContext ec)
7594 VariableInfo variable_info;
7596 public This (Location loc)
7603 public override string Name {
7604 get { return "this"; }
7607 public override bool IsLockedByStatement {
7615 public override bool IsRef {
7616 get { return type.IsStruct; }
7619 public override bool IsSideEffectFree {
7625 protected override ILocalVariable Variable {
7626 get { return ThisVariable.Instance; }
7629 public override VariableInfo VariableInfo {
7630 get { return variable_info; }
7633 public override bool IsFixed {
7634 get { return false; }
7639 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
7642 // It's null for all cases when we don't need to check `this'
7643 // definitive assignment
7645 if (variable_info == null)
7648 if (rc.OmitStructFlowAnalysis)
7651 if (!variable_info.IsAssigned (rc)) {
7652 rc.Report.Error (188, loc,
7653 "The `this' object cannot be used before all of its fields are assigned to");
7657 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7659 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7660 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7661 } else if (ec.CurrentAnonymousMethod != null) {
7662 ec.Report.Error (1673, loc,
7663 "Anonymous methods inside structs cannot access instance members of `this'. " +
7664 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7666 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7670 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7675 AnonymousMethodStorey storey = ae.Storey;
7676 return storey != null ? storey.HoistedThis : null;
7679 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7681 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7684 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7687 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7693 public virtual void ResolveBase (ResolveContext ec)
7695 eclass = ExprClass.Variable;
7696 type = ec.CurrentType;
7698 if (!IsThisAvailable (ec, false)) {
7699 Error_ThisNotAvailable (ec);
7703 var block = ec.CurrentBlock;
7704 if (block != null) {
7705 var top = block.ParametersBlock.TopBlock;
7706 if (top.ThisVariable != null)
7707 variable_info = top.ThisVariable.VariableInfo;
7709 AnonymousExpression am = ec.CurrentAnonymousMethod;
7710 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7712 // Hoisted this is almost like hoisted variable but not exactly. When
7713 // there is no variable hoisted we can simply emit an instance method
7714 // without lifting this into a storey. Unfotunatelly this complicates
7715 // things in other cases because we don't know where this will be hoisted
7716 // until top-level block is fully resolved
7718 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7719 am.SetHasThisAccess ();
7724 protected override Expression DoResolve (ResolveContext ec)
7728 CheckStructThisDefiniteAssignment (ec);
7733 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7735 if (eclass == ExprClass.Unresolved)
7738 if (variable_info != null)
7739 variable_info.SetAssigned (ec);
7742 if (right_side == EmptyExpression.UnaryAddress)
7743 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7744 else if (right_side == EmptyExpression.OutAccess)
7745 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7747 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7753 public override int GetHashCode()
7755 throw new NotImplementedException ();
7758 public override bool Equals (object obj)
7760 This t = obj as This;
7767 protected override void CloneTo (CloneContext clonectx, Expression t)
7772 public override void SetHasAddressTaken ()
7777 public override void VerifyAssigned (ResolveContext rc)
7781 public override object Accept (StructuralVisitor visitor)
7783 return visitor.Visit (this);
7788 /// Represents the `__arglist' construct
7790 public class ArglistAccess : Expression
7792 public ArglistAccess (Location loc)
7797 protected override void CloneTo (CloneContext clonectx, Expression target)
7802 public override bool ContainsEmitWithAwait ()
7807 public override Expression CreateExpressionTree (ResolveContext ec)
7809 throw new NotSupportedException ("ET");
7812 protected override Expression DoResolve (ResolveContext ec)
7814 eclass = ExprClass.Variable;
7815 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
7817 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7818 ec.Report.Error (190, loc,
7819 "The __arglist construct is valid only within a variable argument method");
7825 public override void Emit (EmitContext ec)
7827 ec.Emit (OpCodes.Arglist);
7830 public override object Accept (StructuralVisitor visitor)
7832 return visitor.Visit (this);
7837 /// Represents the `__arglist (....)' construct
7839 public class Arglist : Expression
7841 Arguments arguments;
7843 public Arglist (Location loc)
7848 public Arglist (Arguments args, Location l)
7854 public Arguments Arguments {
7860 public MetaType[] ArgumentTypes {
7862 if (arguments == null)
7863 return MetaType.EmptyTypes;
7865 var retval = new MetaType[arguments.Count];
7866 for (int i = 0; i < retval.Length; i++)
7867 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
7873 public override bool ContainsEmitWithAwait ()
7875 throw new NotImplementedException ();
7878 public override Expression CreateExpressionTree (ResolveContext ec)
7880 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7884 protected override Expression DoResolve (ResolveContext ec)
7886 eclass = ExprClass.Variable;
7887 type = InternalType.Arglist;
7888 if (arguments != null) {
7889 bool dynamic; // Can be ignored as there is always only 1 overload
7890 arguments.Resolve (ec, out dynamic);
7896 public override void Emit (EmitContext ec)
7898 if (arguments != null)
7899 arguments.Emit (ec);
7902 protected override void CloneTo (CloneContext clonectx, Expression t)
7904 Arglist target = (Arglist) t;
7906 if (arguments != null)
7907 target.arguments = arguments.Clone (clonectx);
7910 public override object Accept (StructuralVisitor visitor)
7912 return visitor.Visit (this);
7916 public class RefValueExpr : ShimExpression, IAssignMethod
7918 FullNamedExpression texpr;
7920 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7927 public FullNamedExpression TypeExpression {
7933 public override bool ContainsEmitWithAwait ()
7938 protected override Expression DoResolve (ResolveContext rc)
7940 expr = expr.Resolve (rc);
7941 type = texpr.ResolveAsType (rc);
7942 if (expr == null || type == null)
7945 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7946 eclass = ExprClass.Value;
7950 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7952 return DoResolve (rc);
7955 public override void Emit (EmitContext ec)
7958 ec.Emit (OpCodes.Refanyval, type);
7959 ec.EmitLoadFromPtr (type);
7962 public void Emit (EmitContext ec, bool leave_copy)
7964 throw new NotImplementedException ();
7967 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7970 ec.Emit (OpCodes.Refanyval, type);
7973 LocalTemporary temporary = null;
7975 ec.Emit (OpCodes.Dup);
7976 temporary = new LocalTemporary (source.Type);
7977 temporary.Store (ec);
7980 ec.EmitStoreFromPtr (type);
7982 if (temporary != null) {
7983 temporary.Emit (ec);
7984 temporary.Release (ec);
7988 public override object Accept (StructuralVisitor visitor)
7990 return visitor.Visit (this);
7994 public class RefTypeExpr : ShimExpression
7996 public RefTypeExpr (Expression expr, Location loc)
8002 protected override Expression DoResolve (ResolveContext rc)
8004 expr = expr.Resolve (rc);
8008 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8012 type = rc.BuiltinTypes.Type;
8013 eclass = ExprClass.Value;
8017 public override void Emit (EmitContext ec)
8020 ec.Emit (OpCodes.Refanytype);
8021 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8023 ec.Emit (OpCodes.Call, m);
8026 public override object Accept (StructuralVisitor visitor)
8028 return visitor.Visit (this);
8032 public class MakeRefExpr : ShimExpression
8034 public MakeRefExpr (Expression expr, Location loc)
8040 public override bool ContainsEmitWithAwait ()
8042 throw new NotImplementedException ();
8045 protected override Expression DoResolve (ResolveContext rc)
8047 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8048 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8049 eclass = ExprClass.Value;
8053 public override void Emit (EmitContext ec)
8055 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8056 ec.Emit (OpCodes.Mkrefany, expr.Type);
8059 public override object Accept (StructuralVisitor visitor)
8061 return visitor.Visit (this);
8066 /// Implements the typeof operator
8068 public class TypeOf : Expression {
8069 FullNamedExpression QueriedType;
8072 public TypeOf (FullNamedExpression queried_type, Location l)
8074 QueriedType = queried_type;
8079 // Use this constructor for any compiler generated typeof expression
8081 public TypeOf (TypeSpec type, Location loc)
8083 this.typearg = type;
8089 public override bool IsSideEffectFree {
8095 public TypeSpec TypeArgument {
8101 public FullNamedExpression TypeExpression {
8110 protected override void CloneTo (CloneContext clonectx, Expression t)
8112 TypeOf target = (TypeOf) t;
8113 if (QueriedType != null)
8114 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
8117 public override bool ContainsEmitWithAwait ()
8122 public override Expression CreateExpressionTree (ResolveContext ec)
8124 Arguments args = new Arguments (2);
8125 args.Add (new Argument (this));
8126 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8127 return CreateExpressionFactoryCall (ec, "Constant", args);
8130 protected override Expression DoResolve (ResolveContext ec)
8132 if (eclass != ExprClass.Unresolved)
8135 if (typearg == null) {
8137 // Pointer types are allowed without explicit unsafe, they are just tokens
8139 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
8140 typearg = QueriedType.ResolveAsType (ec);
8143 if (typearg == null)
8146 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8147 ec.Report.Error (1962, QueriedType.Location,
8148 "The typeof operator cannot be used on the dynamic type");
8152 type = ec.BuiltinTypes.Type;
8154 // Even though what is returned is a type object, it's treated as a value by the compiler.
8155 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
8156 eclass = ExprClass.Value;
8160 static bool ContainsDynamicType (TypeSpec type)
8162 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
8165 var element_container = type as ElementTypeSpec;
8166 if (element_container != null)
8167 return ContainsDynamicType (element_container.Element);
8169 foreach (var t in type.TypeArguments) {
8170 if (ContainsDynamicType (t)) {
8178 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
8180 // Target type is not System.Type therefore must be object
8181 // and we need to use different encoding sequence
8182 if (targetType != type)
8185 if (typearg is InflatedTypeSpec) {
8188 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
8189 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
8190 typearg.GetSignatureForError ());
8194 gt = gt.DeclaringType;
8195 } while (gt != null);
8198 if (ContainsDynamicType (typearg)) {
8199 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8203 enc.EncodeTypeName (typearg);
8206 public override void Emit (EmitContext ec)
8208 ec.Emit (OpCodes.Ldtoken, typearg);
8209 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8211 ec.Emit (OpCodes.Call, m);
8214 public override object Accept (StructuralVisitor visitor)
8216 return visitor.Visit (this);
8220 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
8222 public TypeOfMethod (MethodSpec method, Location loc)
8223 : base (method, loc)
8227 protected override Expression DoResolve (ResolveContext ec)
8229 if (member.IsConstructor) {
8230 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
8232 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
8238 return base.DoResolve (ec);
8241 public override void Emit (EmitContext ec)
8243 ec.Emit (OpCodes.Ldtoken, member);
8246 ec.Emit (OpCodes.Castclass, type);
8249 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8251 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
8254 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8256 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
8260 abstract class TypeOfMember<T> : Expression where T : MemberSpec
8262 protected readonly T member;
8264 protected TypeOfMember (T member, Location loc)
8266 this.member = member;
8270 public override bool IsSideEffectFree {
8276 public override bool ContainsEmitWithAwait ()
8281 public override Expression CreateExpressionTree (ResolveContext ec)
8283 Arguments args = new Arguments (2);
8284 args.Add (new Argument (this));
8285 args.Add (new Argument (new TypeOf (type, loc)));
8286 return CreateExpressionFactoryCall (ec, "Constant", args);
8289 protected override Expression DoResolve (ResolveContext ec)
8291 eclass = ExprClass.Value;
8295 public override void Emit (EmitContext ec)
8297 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
8298 PredefinedMember<MethodSpec> p;
8300 p = GetTypeFromHandleGeneric (ec);
8301 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
8303 p = GetTypeFromHandle (ec);
8306 var mi = p.Resolve (loc);
8308 ec.Emit (OpCodes.Call, mi);
8311 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
8312 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
8315 sealed class TypeOfField : TypeOfMember<FieldSpec>
8317 public TypeOfField (FieldSpec field, Location loc)
8322 protected override Expression DoResolve (ResolveContext ec)
8324 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
8328 return base.DoResolve (ec);
8331 public override void Emit (EmitContext ec)
8333 ec.Emit (OpCodes.Ldtoken, member);
8337 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8339 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
8342 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8344 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
8349 /// Implements the sizeof expression
8351 public class SizeOf : Expression {
8352 readonly Expression texpr;
8353 TypeSpec type_queried;
8355 public SizeOf (Expression queried_type, Location l)
8357 this.texpr = queried_type;
8361 public override bool IsSideEffectFree {
8367 public Expression TypeExpression {
8373 public override bool ContainsEmitWithAwait ()
8378 public override Expression CreateExpressionTree (ResolveContext ec)
8380 Error_PointerInsideExpressionTree (ec);
8384 protected override Expression DoResolve (ResolveContext ec)
8386 type_queried = texpr.ResolveAsType (ec);
8387 if (type_queried == null)
8390 if (type_queried.IsEnum)
8391 type_queried = EnumSpec.GetUnderlyingType (type_queried);
8393 int size_of = BuiltinTypeSpec.GetSize (type_queried);
8395 return new IntConstant (ec.BuiltinTypes, size_of, loc);
8398 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
8403 ec.Report.Error (233, loc,
8404 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
8405 type_queried.GetSignatureForError ());
8408 type = ec.BuiltinTypes.Int;
8409 eclass = ExprClass.Value;
8413 public override void Emit (EmitContext ec)
8415 ec.Emit (OpCodes.Sizeof, type_queried);
8418 protected override void CloneTo (CloneContext clonectx, Expression t)
8422 public override object Accept (StructuralVisitor visitor)
8424 return visitor.Visit (this);
8429 /// Implements the qualified-alias-member (::) expression.
8431 public class QualifiedAliasMember : MemberAccess
8433 readonly string alias;
8434 public static readonly string GlobalAlias = "global";
8436 public QualifiedAliasMember (string alias, string identifier, Location l)
8437 : base (null, identifier, l)
8442 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
8443 : base (null, identifier, targs, l)
8448 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
8449 : base (null, identifier, arity, l)
8454 public string Alias {
8460 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
8462 if (alias == GlobalAlias) {
8463 expr = ec.Module.GlobalRootNamespace;
8464 return base.ResolveAsTypeOrNamespace (ec);
8467 int errors = ec.Module.Compiler.Report.Errors;
8468 expr = ec.LookupNamespaceAlias (alias);
8470 if (errors == ec.Module.Compiler.Report.Errors)
8471 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
8475 return base.ResolveAsTypeOrNamespace (ec);
8478 protected override Expression DoResolve (ResolveContext ec)
8480 return ResolveAsTypeOrNamespace (ec);
8483 public override string GetSignatureForError ()
8486 if (targs != null) {
8487 name = Name + "<" + targs.GetSignatureForError () + ">";
8490 return alias + "::" + name;
8493 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8495 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
8496 rc.Module.Compiler.Report.Error (687, loc,
8497 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
8498 GetSignatureForError ());
8503 return DoResolve (rc);
8506 protected override void CloneTo (CloneContext clonectx, Expression t)
8511 public override object Accept (StructuralVisitor visitor)
8513 return visitor.Visit (this);
8518 /// Implements the member access expression
8520 public class MemberAccess : ATypeNameExpression
8522 protected Expression expr;
8524 public MemberAccess (Expression expr, string id)
8525 : base (id, expr.Location)
8530 public MemberAccess (Expression expr, string identifier, Location loc)
8531 : base (identifier, loc)
8536 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
8537 : base (identifier, args, loc)
8542 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
8543 : base (identifier, arity, loc)
8548 public Expression LeftExpression {
8554 public override Location StartLocation {
8556 return expr == null ? loc : expr.StartLocation;
8560 protected override Expression DoResolve (ResolveContext rc)
8562 var e = DoResolveName (rc, null);
8564 if (!rc.OmitStructFlowAnalysis) {
8565 var fe = e as FieldExpr;
8567 fe.VerifyAssignedStructField (rc, null);
8574 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
8576 var e = DoResolveName (rc, rhs);
8578 if (!rc.OmitStructFlowAnalysis) {
8579 var fe = e as FieldExpr;
8580 if (fe != null && fe.InstanceExpression is FieldExpr) {
8581 fe = (FieldExpr) fe.InstanceExpression;
8582 fe.VerifyAssignedStructField (rc, rhs);
8589 Expression DoResolveName (ResolveContext rc, Expression right_side)
8591 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
8595 if (right_side != null) {
8596 if (e is TypeExpr) {
8597 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8601 e = e.ResolveLValue (rc, right_side);
8603 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
8609 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8611 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8612 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8614 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8617 public static bool IsValidDotExpression (TypeSpec type)
8619 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8620 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8622 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8625 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8627 var sn = expr as SimpleName;
8628 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8631 // Resolve the expression with flow analysis turned off, we'll do the definite
8632 // assignment checks later. This is because we don't know yet what the expression
8633 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
8634 // definite assignment check on the actual field and not on the whole struct.
8636 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
8638 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8641 // Resolve expression which does have type set as we need expression type
8642 // with disable flow analysis as we don't know whether left side expression
8643 // is used as variable or type
8645 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8646 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
8647 expr = expr.Resolve (rc);
8649 } else if (expr is TypeParameterExpr) {
8650 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8654 expr = expr.Resolve (rc, flags);
8661 Namespace ns = expr as Namespace;
8663 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8665 if (retval == null) {
8666 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8670 if (HasTypeArguments)
8671 return new GenericTypeExpr (retval.Type, targs, loc);
8677 TypeSpec expr_type = expr.Type;
8678 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8679 me = expr as MemberExpr;
8681 me.ResolveInstanceExpression (rc, null);
8684 // Run defined assigned checks on expressions resolved with
8685 // disabled flow-analysis
8688 var vr = expr as VariableReference;
8690 vr.VerifyAssigned (rc);
8693 Arguments args = new Arguments (1);
8694 args.Add (new Argument (expr));
8695 return new DynamicMemberBinder (Name, args, loc);
8698 if (!IsValidDotExpression (expr_type)) {
8699 Error_OperatorCannotBeApplied (rc, expr_type);
8703 var lookup_arity = Arity;
8704 bool errorMode = false;
8705 Expression member_lookup;
8707 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8708 if (member_lookup == null) {
8710 // Try to look for extension method when member lookup failed
8712 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8713 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8714 if (methods != null) {
8715 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8716 if (HasTypeArguments) {
8717 if (!targs.Resolve (rc))
8720 emg.SetTypeArguments (rc, targs);
8724 // Run defined assigned checks on expressions resolved with
8725 // disabled flow-analysis
8727 if (sn != null && !errorMode) {
8728 var vr = expr as VariableReference;
8730 vr.VerifyAssigned (rc);
8733 // TODO: it should really skip the checks bellow
8734 return emg.Resolve (rc);
8740 if (member_lookup == null) {
8741 var dep = expr_type.GetMissingDependencies ();
8743 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8744 } else if (expr is TypeExpr) {
8745 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8747 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8753 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8754 // Leave it to overload resolution to report correct error
8755 } else if (!(member_lookup is TypeExpr)) {
8756 // TODO: rc.SymbolRelatedToPreviousError
8757 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8762 if (member_lookup != null)
8766 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8770 TypeExpr texpr = member_lookup as TypeExpr;
8771 if (texpr != null) {
8772 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8773 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8774 Name, texpr.GetSignatureForError ());
8777 if (!texpr.Type.IsAccessible (rc)) {
8778 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8779 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8783 if (HasTypeArguments) {
8784 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8787 return member_lookup;
8790 me = member_lookup as MemberExpr;
8792 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8796 me = me.ResolveMemberAccess (rc, expr, sn);
8799 if (!targs.Resolve (rc))
8802 me.SetTypeArguments (rc, targs);
8806 // Run defined assigned checks on expressions resolved with
8807 // disabled flow-analysis
8809 if (sn != null && !(me is FieldExpr && TypeSpec.IsValueType (expr_type))) {
8810 var vr = expr as VariableReference;
8812 vr.VerifyAssigned (rc);
8818 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8820 FullNamedExpression fexpr = expr as FullNamedExpression;
8821 if (fexpr == null) {
8822 expr.ResolveAsType (rc);
8826 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8828 if (expr_resolved == null)
8831 Namespace ns = expr_resolved as Namespace;
8833 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8835 if (retval == null) {
8836 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8837 } else if (HasTypeArguments) {
8838 retval = new GenericTypeExpr (retval.Type, targs, loc);
8839 if (retval.ResolveAsType (rc) == null)
8846 var tnew_expr = expr_resolved.ResolveAsType (rc);
8847 if (tnew_expr == null)
8850 TypeSpec expr_type = tnew_expr;
8851 if (TypeManager.IsGenericParameter (expr_type)) {
8852 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8853 tnew_expr.GetSignatureForError ());
8857 var qam = this as QualifiedAliasMember;
8859 rc.Module.Compiler.Report.Error (431, loc,
8860 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8865 TypeSpec nested = null;
8866 while (expr_type != null) {
8867 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8868 if (nested == null) {
8869 if (expr_type == tnew_expr) {
8870 Error_IdentifierNotFound (rc, expr_type, Name);
8874 expr_type = tnew_expr;
8875 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8876 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
8880 if (nested.IsAccessible (rc))
8884 // Keep looking after inaccessible candidate but only if
8885 // we are not in same context as the definition itself
8887 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
8890 expr_type = expr_type.BaseType;
8895 if (HasTypeArguments) {
8896 texpr = new GenericTypeExpr (nested, targs, loc);
8898 texpr = new GenericOpenTypeExpr (nested, loc);
8901 texpr = new TypeExpression (nested, loc);
8904 if (texpr.ResolveAsType (rc) == null)
8910 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
8912 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
8914 if (nested != null) {
8915 Error_TypeArgumentsCannotBeUsed (rc, nested, Arity, expr.Location);
8919 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
8920 if (any_other_member != null) {
8921 any_other_member.Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
8925 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
8926 Name, expr_type.GetSignatureForError ());
8929 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
8931 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
8934 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
8936 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8937 ec.Report.SymbolRelatedToPreviousError (type);
8939 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, type, name, Arity);
8941 // a using directive or an assembly reference
8943 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
8945 missing = "an assembly reference";
8948 ec.Report.Error (1061, loc,
8949 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
8950 type.GetSignatureForError (), name, missing);
8954 base.Error_TypeDoesNotContainDefinition (ec, type, name);
8957 public override string GetSignatureForError ()
8959 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
8962 protected override void CloneTo (CloneContext clonectx, Expression t)
8964 MemberAccess target = (MemberAccess) t;
8966 target.expr = expr.Clone (clonectx);
8969 public override object Accept (StructuralVisitor visitor)
8971 return visitor.Visit (this);
8976 /// Implements checked expressions
8978 public class CheckedExpr : Expression {
8980 public Expression Expr;
8982 public CheckedExpr (Expression e, Location l)
8988 public override bool ContainsEmitWithAwait ()
8990 return Expr.ContainsEmitWithAwait ();
8993 public override Expression CreateExpressionTree (ResolveContext ec)
8995 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
8996 return Expr.CreateExpressionTree (ec);
8999 protected override Expression DoResolve (ResolveContext ec)
9001 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9002 Expr = Expr.Resolve (ec);
9007 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9010 eclass = Expr.eclass;
9015 public override void Emit (EmitContext ec)
9017 using (ec.With (EmitContext.Options.CheckedScope, true))
9021 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9023 using (ec.With (EmitContext.Options.CheckedScope, true))
9024 Expr.EmitBranchable (ec, target, on_true);
9027 public override SLE.Expression MakeExpression (BuilderContext ctx)
9029 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9030 return Expr.MakeExpression (ctx);
9034 protected override void CloneTo (CloneContext clonectx, Expression t)
9036 CheckedExpr target = (CheckedExpr) t;
9038 target.Expr = Expr.Clone (clonectx);
9041 public override object Accept (StructuralVisitor visitor)
9043 return visitor.Visit (this);
9048 /// Implements the unchecked expression
9050 public class UnCheckedExpr : Expression {
9052 public Expression Expr;
9054 public UnCheckedExpr (Expression e, Location l)
9060 public override bool ContainsEmitWithAwait ()
9062 return Expr.ContainsEmitWithAwait ();
9065 public override Expression CreateExpressionTree (ResolveContext ec)
9067 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9068 return Expr.CreateExpressionTree (ec);
9071 protected override Expression DoResolve (ResolveContext ec)
9073 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9074 Expr = Expr.Resolve (ec);
9079 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9082 eclass = Expr.eclass;
9087 public override void Emit (EmitContext ec)
9089 using (ec.With (EmitContext.Options.CheckedScope, false))
9093 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9095 using (ec.With (EmitContext.Options.CheckedScope, false))
9096 Expr.EmitBranchable (ec, target, on_true);
9099 protected override void CloneTo (CloneContext clonectx, Expression t)
9101 UnCheckedExpr target = (UnCheckedExpr) t;
9103 target.Expr = Expr.Clone (clonectx);
9106 public override object Accept (StructuralVisitor visitor)
9108 return visitor.Visit (this);
9113 /// An Element Access expression.
9115 /// During semantic analysis these are transformed into
9116 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
9118 public class ElementAccess : Expression
9120 public Arguments Arguments;
9121 public Expression Expr;
9123 public ElementAccess (Expression e, Arguments args, Location loc)
9127 this.Arguments = args;
9130 public override Location StartLocation {
9132 return Expr.StartLocation;
9136 public override bool ContainsEmitWithAwait ()
9138 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
9142 // We perform some simple tests, and then to "split" the emit and store
9143 // code we create an instance of a different class, and return that.
9145 Expression CreateAccessExpression (ResolveContext ec)
9148 return (new ArrayAccess (this, loc));
9151 return MakePointerAccess (ec, type);
9153 FieldExpr fe = Expr as FieldExpr;
9155 var ff = fe.Spec as FixedFieldSpec;
9157 return MakePointerAccess (ec, ff.ElementType);
9161 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
9162 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9163 return new IndexerExpr (indexers, type, this);
9166 if (type != InternalType.ErrorType) {
9167 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
9168 type.GetSignatureForError ());
9174 public override Expression CreateExpressionTree (ResolveContext ec)
9176 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
9177 Expr.CreateExpressionTree (ec));
9179 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
9182 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
9184 if (Arguments.Count != 1){
9185 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
9189 if (Arguments [0] is NamedArgument)
9190 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
9192 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
9193 return new Indirection (p, loc);
9196 protected override Expression DoResolve (ResolveContext ec)
9198 Expr = Expr.Resolve (ec);
9204 // TODO: Create 1 result for Resolve and ResolveLValue ?
9205 var res = CreateAccessExpression (ec);
9209 return res.Resolve (ec);
9212 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
9214 Expr = Expr.Resolve (ec);
9220 var res = CreateAccessExpression (ec);
9224 return res.ResolveLValue (ec, rhs);
9227 public override void Emit (EmitContext ec)
9229 throw new Exception ("Should never be reached");
9232 public static void Error_NamedArgument (NamedArgument na, Report Report)
9234 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
9237 public override string GetSignatureForError ()
9239 return Expr.GetSignatureForError ();
9242 protected override void CloneTo (CloneContext clonectx, Expression t)
9244 ElementAccess target = (ElementAccess) t;
9246 target.Expr = Expr.Clone (clonectx);
9247 if (Arguments != null)
9248 target.Arguments = Arguments.Clone (clonectx);
9251 public override object Accept (StructuralVisitor visitor)
9253 return visitor.Visit (this);
9258 /// Implements array access
9260 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
9262 // Points to our "data" repository
9266 LocalTemporary temp;
9268 bool? has_await_args;
9270 public ArrayAccess (ElementAccess ea_data, Location l)
9276 public void AddressOf (EmitContext ec, AddressOp mode)
9278 var ac = (ArrayContainer) ea.Expr.Type;
9280 LoadInstanceAndArguments (ec, false, false);
9282 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
9283 ec.Emit (OpCodes.Readonly);
9285 ec.EmitArrayAddress (ac);
9288 public override Expression CreateExpressionTree (ResolveContext ec)
9290 return ea.CreateExpressionTree (ec);
9293 public override bool ContainsEmitWithAwait ()
9295 return ea.ContainsEmitWithAwait ();
9298 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9300 return DoResolve (ec);
9303 protected override Expression DoResolve (ResolveContext ec)
9305 // dynamic is used per argument in ConvertExpressionToArrayIndex case
9307 ea.Arguments.Resolve (ec, out dynamic);
9309 var ac = ea.Expr.Type as ArrayContainer;
9310 int rank = ea.Arguments.Count;
9311 if (ac.Rank != rank) {
9312 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
9313 rank.ToString (), ac.Rank.ToString ());
9318 if (type.IsPointer && !ec.IsUnsafe) {
9319 UnsafeError (ec, ea.Location);
9322 foreach (Argument a in ea.Arguments) {
9323 if (a is NamedArgument)
9324 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
9326 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
9329 eclass = ExprClass.Variable;
9334 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
9336 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
9340 // Load the array arguments into the stack.
9342 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
9345 ea.Expr = ea.Expr.EmitToField (ec);
9346 } else if (duplicateArguments) {
9348 ec.Emit (OpCodes.Dup);
9350 var copy = new LocalTemporary (ea.Expr.Type);
9357 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
9358 if (dup_args != null)
9359 ea.Arguments = dup_args;
9362 public void Emit (EmitContext ec, bool leave_copy)
9364 var ac = ea.Expr.Type as ArrayContainer;
9367 ec.EmitLoadFromPtr (type);
9369 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
9370 LoadInstanceAndArguments (ec, false, true);
9373 LoadInstanceAndArguments (ec, false, false);
9374 ec.EmitArrayLoad (ac);
9378 ec.Emit (OpCodes.Dup);
9379 temp = new LocalTemporary (this.type);
9384 public override void Emit (EmitContext ec)
9389 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9391 var ac = (ArrayContainer) ea.Expr.Type;
9392 TypeSpec t = source.Type;
9394 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
9397 // When we are dealing with a struct, get the address of it to avoid value copy
9398 // Same cannot be done for reference type because array covariance and the
9399 // check in ldelema requires to specify the type of array element stored at the index
9401 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
9402 LoadInstanceAndArguments (ec, false, has_await_args.Value);
9404 if (has_await_args.Value) {
9405 if (source.ContainsEmitWithAwait ()) {
9406 source = source.EmitToField (ec);
9411 LoadInstanceAndArguments (ec, isCompound, false);
9416 ec.EmitArrayAddress (ac);
9419 ec.Emit (OpCodes.Dup);
9423 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
9425 if (has_await_args.Value) {
9426 if (source.ContainsEmitWithAwait ())
9427 source = source.EmitToField (ec);
9429 LoadInstanceAndArguments (ec, false, false);
9436 var lt = ea.Expr as LocalTemporary;
9442 ec.Emit (OpCodes.Dup);
9443 temp = new LocalTemporary (this.type);
9448 ec.EmitStoreFromPtr (t);
9450 ec.EmitArrayStore (ac);
9459 public override Expression EmitToField (EmitContext ec)
9462 // Have to be specialized for arrays to get access to
9463 // underlying element. Instead of another result copy we
9464 // need direct access to element
9468 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
9470 ea.Expr = ea.Expr.EmitToField (ec);
9474 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9476 #if NET_4_0 || MONODROID
9477 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9479 throw new NotImplementedException ();
9483 public override SLE.Expression MakeExpression (BuilderContext ctx)
9485 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9488 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
9490 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9491 return Arguments.MakeExpression (ea.Arguments, ctx);
9497 // Indexer access expression
9499 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
9501 IList<MemberSpec> indexers;
9502 Arguments arguments;
9503 TypeSpec queried_type;
9505 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
9506 : base (ea.Location)
9508 this.indexers = indexers;
9509 this.queried_type = queriedType;
9510 this.InstanceExpression = ea.Expr;
9511 this.arguments = ea.Arguments;
9516 protected override Arguments Arguments {
9525 protected override TypeSpec DeclaringType {
9527 return best_candidate.DeclaringType;
9531 public override bool IsInstance {
9537 public override bool IsStatic {
9543 public override string KindName {
9544 get { return "indexer"; }
9547 public override string Name {
9555 public override bool ContainsEmitWithAwait ()
9557 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
9560 public override Expression CreateExpressionTree (ResolveContext ec)
9562 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
9563 InstanceExpression.CreateExpressionTree (ec),
9564 new TypeOfMethod (Getter, loc));
9566 return CreateExpressionFactoryCall (ec, "Call", args);
9569 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9571 LocalTemporary await_source_arg = null;
9574 emitting_compound_assignment = true;
9575 if (source is DynamicExpressionStatement) {
9580 emitting_compound_assignment = false;
9582 if (has_await_arguments) {
9583 await_source_arg = new LocalTemporary (Type);
9584 await_source_arg.Store (ec);
9586 arguments.Add (new Argument (await_source_arg));
9589 temp = await_source_arg;
9592 has_await_arguments = false;
9597 ec.Emit (OpCodes.Dup);
9598 temp = new LocalTemporary (Type);
9604 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9605 source = source.EmitToField (ec);
9607 temp = new LocalTemporary (Type);
9614 arguments.Add (new Argument (source));
9617 var call = new CallEmitter ();
9618 call.InstanceExpression = InstanceExpression;
9619 if (arguments == null)
9620 call.InstanceExpressionOnStack = true;
9622 call.Emit (ec, Setter, arguments, loc);
9627 } else if (leave_copy) {
9631 if (await_source_arg != null) {
9632 await_source_arg.Release (ec);
9636 public override string GetSignatureForError ()
9638 return best_candidate.GetSignatureForError ();
9641 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9644 throw new NotSupportedException ();
9646 var value = new[] { source.MakeExpression (ctx) };
9647 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9648 #if NET_4_0 || MONODROID
9649 return SLE.Expression.Block (
9650 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9653 return args.First ();
9658 public override SLE.Expression MakeExpression (BuilderContext ctx)
9661 return base.MakeExpression (ctx);
9663 var args = Arguments.MakeExpression (arguments, ctx);
9664 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9668 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9670 if (best_candidate != null)
9673 eclass = ExprClass.IndexerAccess;
9676 arguments.Resolve (rc, out dynamic);
9678 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9681 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9682 res.BaseMembersProvider = this;
9683 res.InstanceQualifier = this;
9685 // TODO: Do I need 2 argument sets?
9686 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9687 if (best_candidate != null)
9688 type = res.BestCandidateReturnType;
9689 else if (!res.BestCandidateIsDynamic)
9694 // It has dynamic arguments
9697 Arguments args = new Arguments (arguments.Count + 1);
9699 rc.Report.Error (1972, loc,
9700 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9702 args.Add (new Argument (InstanceExpression));
9704 args.AddRange (arguments);
9706 best_candidate = null;
9707 return new DynamicIndexBinder (args, loc);
9711 // Try to avoid resolving left expression again
9713 if (right_side != null)
9714 ResolveInstanceExpression (rc, right_side);
9719 protected override void CloneTo (CloneContext clonectx, Expression t)
9721 IndexerExpr target = (IndexerExpr) t;
9723 if (arguments != null)
9724 target.arguments = arguments.Clone (clonectx);
9727 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9729 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9732 #region IBaseMembersProvider Members
9734 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9736 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9739 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9741 if (queried_type == member.DeclaringType)
9744 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9745 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9748 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9757 // A base access expression
9759 public class BaseThis : This
9761 public BaseThis (Location loc)
9766 public BaseThis (TypeSpec type, Location loc)
9770 eclass = ExprClass.Variable;
9775 public override string Name {
9783 public override Expression CreateExpressionTree (ResolveContext ec)
9785 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9786 return base.CreateExpressionTree (ec);
9789 public override void Emit (EmitContext ec)
9793 var context_type = ec.CurrentType;
9794 if (context_type.IsStruct) {
9795 ec.Emit (OpCodes.Ldobj, context_type);
9796 ec.Emit (OpCodes.Box, context_type);
9800 protected override void Error_ThisNotAvailable (ResolveContext ec)
9803 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9805 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9809 public override void ResolveBase (ResolveContext ec)
9811 base.ResolveBase (ec);
9812 type = ec.CurrentType.BaseType;
9815 public override object Accept (StructuralVisitor visitor)
9817 return visitor.Visit (this);
9822 /// This class exists solely to pass the Type around and to be a dummy
9823 /// that can be passed to the conversion functions (this is used by
9824 /// foreach implementation to typecast the object return value from
9825 /// get_Current into the proper type. All code has been generated and
9826 /// we only care about the side effect conversions to be performed
9828 /// This is also now used as a placeholder where a no-action expression
9829 /// is needed (the `New' class).
9831 public class EmptyExpression : Expression
9833 sealed class OutAccessExpression : EmptyExpression
9835 public OutAccessExpression (TypeSpec t)
9840 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9842 rc.Report.Error (206, right_side.Location,
9843 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
9849 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
9850 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
9851 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
9852 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
9853 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
9854 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
9855 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
9856 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
9858 public EmptyExpression (TypeSpec t)
9861 eclass = ExprClass.Value;
9862 loc = Location.Null;
9865 public override bool ContainsEmitWithAwait ()
9870 public override Expression CreateExpressionTree (ResolveContext ec)
9872 throw new NotSupportedException ("ET");
9875 protected override Expression DoResolve (ResolveContext ec)
9880 public override void Emit (EmitContext ec)
9882 // nothing, as we only exist to not do anything.
9885 public override void EmitSideEffect (EmitContext ec)
9889 public override object Accept (StructuralVisitor visitor)
9891 return visitor.Visit (this);
9895 sealed class EmptyAwaitExpression : EmptyExpression
9897 public EmptyAwaitExpression (TypeSpec type)
9902 public override bool ContainsEmitWithAwait ()
9909 // Empty statement expression
9911 public sealed class EmptyExpressionStatement : ExpressionStatement
9913 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
9915 private EmptyExpressionStatement ()
9917 loc = Location.Null;
9920 public override bool ContainsEmitWithAwait ()
9925 public override Expression CreateExpressionTree (ResolveContext ec)
9930 public override void EmitStatement (EmitContext ec)
9935 protected override Expression DoResolve (ResolveContext ec)
9937 eclass = ExprClass.Value;
9938 type = ec.BuiltinTypes.Object;
9942 public override void Emit (EmitContext ec)
9947 public override object Accept (StructuralVisitor visitor)
9949 return visitor.Visit (this);
9953 public class ErrorExpression : EmptyExpression
9955 public static readonly ErrorExpression Instance = new ErrorExpression ();
9957 private ErrorExpression ()
9958 : base (InternalType.ErrorType)
9962 public override Expression CreateExpressionTree (ResolveContext ec)
9967 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9972 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
9976 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
9980 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
9984 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
9988 public override object Accept (StructuralVisitor visitor)
9990 return visitor.Visit (this);
9994 public class UserCast : Expression {
9998 public UserCast (MethodSpec method, Expression source, Location l)
10000 if (source == null)
10001 throw new ArgumentNullException ("source");
10003 this.method = method;
10004 this.source = source;
10005 type = method.ReturnType;
10009 public Expression Source {
10015 public override bool ContainsEmitWithAwait ()
10017 return source.ContainsEmitWithAwait ();
10020 public override Expression CreateExpressionTree (ResolveContext ec)
10022 Arguments args = new Arguments (3);
10023 args.Add (new Argument (source.CreateExpressionTree (ec)));
10024 args.Add (new Argument (new TypeOf (type, loc)));
10025 args.Add (new Argument (new TypeOfMethod (method, loc)));
10026 return CreateExpressionFactoryCall (ec, "Convert", args);
10029 protected override Expression DoResolve (ResolveContext ec)
10031 ObsoleteAttribute oa = method.GetAttributeObsolete ();
10033 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
10035 eclass = ExprClass.Value;
10039 public override void Emit (EmitContext ec)
10042 ec.MarkCallEntry (loc);
10043 ec.Emit (OpCodes.Call, method);
10046 public override string GetSignatureForError ()
10048 return TypeManager.CSharpSignature (method);
10051 public override SLE.Expression MakeExpression (BuilderContext ctx)
10054 return base.MakeExpression (ctx);
10056 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
10062 // Holds additional type specifiers like ?, *, []
10064 public class ComposedTypeSpecifier
10066 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
10068 public readonly int Dimension;
10069 public readonly Location Location;
10071 public ComposedTypeSpecifier (int specifier, Location loc)
10073 this.Dimension = specifier;
10074 this.Location = loc;
10078 public bool IsNullable {
10080 return Dimension == -1;
10084 public bool IsPointer {
10086 return Dimension == -2;
10090 public ComposedTypeSpecifier Next { get; set; }
10094 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
10096 return new ComposedTypeSpecifier (dimension, loc);
10099 public static ComposedTypeSpecifier CreateNullable (Location loc)
10101 return new ComposedTypeSpecifier (-1, loc);
10104 public static ComposedTypeSpecifier CreatePointer (Location loc)
10106 return new ComposedTypeSpecifier (-2, loc);
10109 public string GetSignatureForError ()
10114 ArrayContainer.GetPostfixSignature (Dimension);
10116 return Next != null ? s + Next.GetSignatureForError () : s;
10121 // This class is used to "construct" the type during a typecast
10122 // operation. Since the Type.GetType class in .NET can parse
10123 // the type specification, we just use this to construct the type
10124 // one bit at a time.
10126 public class ComposedCast : TypeExpr {
10127 FullNamedExpression left;
10128 ComposedTypeSpecifier spec;
10130 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
10133 throw new ArgumentNullException ("spec");
10137 this.loc = left.Location;
10140 public override TypeSpec ResolveAsType (IMemberContext ec)
10142 type = left.ResolveAsType (ec);
10146 eclass = ExprClass.Type;
10148 var single_spec = spec;
10150 if (single_spec.IsNullable) {
10151 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
10155 single_spec = single_spec.Next;
10156 } else if (single_spec.IsPointer) {
10157 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
10160 if (!ec.IsUnsafe) {
10161 UnsafeError (ec.Module.Compiler.Report, loc);
10165 type = PointerContainer.MakeType (ec.Module, type);
10166 single_spec = single_spec.Next;
10167 } while (single_spec != null && single_spec.IsPointer);
10170 if (single_spec != null && single_spec.Dimension > 0) {
10171 if (type.IsSpecialRuntimeType) {
10172 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
10173 } else if (type.IsStatic) {
10174 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
10175 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
10176 type.GetSignatureForError ());
10178 MakeArray (ec.Module, single_spec);
10185 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
10187 if (spec.Next != null)
10188 MakeArray (module, spec.Next);
10190 type = ArrayContainer.MakeType (module, type, spec.Dimension);
10193 public override string GetSignatureForError ()
10195 return left.GetSignatureForError () + spec.GetSignatureForError ();
10198 public override object Accept (StructuralVisitor visitor)
10200 return visitor.Visit (this);
10204 class FixedBufferPtr : Expression
10206 readonly Expression array;
10208 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
10210 this.type = array_type;
10211 this.array = array;
10215 public override bool ContainsEmitWithAwait ()
10217 throw new NotImplementedException ();
10220 public override Expression CreateExpressionTree (ResolveContext ec)
10222 Error_PointerInsideExpressionTree (ec);
10226 public override void Emit(EmitContext ec)
10231 protected override Expression DoResolve (ResolveContext ec)
10233 type = PointerContainer.MakeType (ec.Module, type);
10234 eclass = ExprClass.Value;
10241 // This class is used to represent the address of an array, used
10242 // only by the Fixed statement, this generates "&a [0]" construct
10243 // for fixed (char *pa = a)
10245 class ArrayPtr : FixedBufferPtr
10247 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
10248 base (array, array_type, l)
10252 public override void Emit (EmitContext ec)
10257 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
10262 // Encapsulates a conversion rules required for array indexes
10264 public class ArrayIndexCast : TypeCast
10266 public ArrayIndexCast (Expression expr, TypeSpec returnType)
10267 : base (expr, returnType)
10269 if (expr.Type == returnType) // int -> int
10270 throw new ArgumentException ("unnecessary array index conversion");
10273 public override Expression CreateExpressionTree (ResolveContext ec)
10275 using (ec.Set (ResolveContext.Options.CheckedScope)) {
10276 return base.CreateExpressionTree (ec);
10280 public override void Emit (EmitContext ec)
10284 switch (child.Type.BuiltinType) {
10285 case BuiltinTypeSpec.Type.UInt:
10286 ec.Emit (OpCodes.Conv_U);
10288 case BuiltinTypeSpec.Type.Long:
10289 ec.Emit (OpCodes.Conv_Ovf_I);
10291 case BuiltinTypeSpec.Type.ULong:
10292 ec.Emit (OpCodes.Conv_Ovf_I_Un);
10295 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
10301 // Implements the `stackalloc' keyword
10303 public class StackAlloc : Expression {
10308 public StackAlloc (Expression type, Expression count, Location l)
10311 this.count = count;
10315 public Expression TypeExpression {
10321 public Expression CountExpression {
10327 public override bool ContainsEmitWithAwait ()
10332 public override Expression CreateExpressionTree (ResolveContext ec)
10334 throw new NotSupportedException ("ET");
10337 protected override Expression DoResolve (ResolveContext ec)
10339 count = count.Resolve (ec);
10343 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
10344 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
10349 Constant c = count as Constant;
10350 if (c != null && c.IsNegative) {
10351 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
10354 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
10355 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
10358 otype = t.ResolveAsType (ec);
10362 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
10365 type = PointerContainer.MakeType (ec.Module, otype);
10366 eclass = ExprClass.Value;
10371 public override void Emit (EmitContext ec)
10373 int size = BuiltinTypeSpec.GetSize (otype);
10378 ec.Emit (OpCodes.Sizeof, otype);
10382 ec.Emit (OpCodes.Mul_Ovf_Un);
10383 ec.Emit (OpCodes.Localloc);
10386 protected override void CloneTo (CloneContext clonectx, Expression t)
10388 StackAlloc target = (StackAlloc) t;
10389 target.count = count.Clone (clonectx);
10390 target.t = t.Clone (clonectx);
10393 public override object Accept (StructuralVisitor visitor)
10395 return visitor.Visit (this);
10400 // An object initializer expression
10402 public class ElementInitializer : Assign
10404 public readonly string Name;
10406 public ElementInitializer (string name, Expression initializer, Location loc)
10407 : base (null, initializer, loc)
10412 protected override void CloneTo (CloneContext clonectx, Expression t)
10414 ElementInitializer target = (ElementInitializer) t;
10415 target.source = source.Clone (clonectx);
10418 public override Expression CreateExpressionTree (ResolveContext ec)
10420 Arguments args = new Arguments (2);
10421 FieldExpr fe = target as FieldExpr;
10423 args.Add (new Argument (fe.CreateTypeOfExpression ()));
10425 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
10428 Expression arg_expr;
10429 var cinit = source as CollectionOrObjectInitializers;
10430 if (cinit == null) {
10432 arg_expr = source.CreateExpressionTree (ec);
10434 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
10435 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
10438 args.Add (new Argument (arg_expr));
10439 return CreateExpressionFactoryCall (ec, mname, args);
10442 protected override Expression DoResolve (ResolveContext ec)
10444 if (source == null)
10445 return EmptyExpressionStatement.Instance;
10447 var t = ec.CurrentInitializerVariable.Type;
10448 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10449 Arguments args = new Arguments (1);
10450 args.Add (new Argument (ec.CurrentInitializerVariable));
10451 target = new DynamicMemberBinder (Name, args, loc);
10454 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10455 if (member == null) {
10456 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10458 if (member != null) {
10459 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
10460 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
10465 if (member == null) {
10466 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
10470 if (!(member is PropertyExpr || member is FieldExpr)) {
10471 ec.Report.Error (1913, loc,
10472 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
10473 member.GetSignatureForError ());
10478 var me = member as MemberExpr;
10480 ec.Report.Error (1914, loc,
10481 "Static field or property `{0}' cannot be assigned in an object initializer",
10482 me.GetSignatureForError ());
10486 me.InstanceExpression = ec.CurrentInitializerVariable;
10489 if (source is CollectionOrObjectInitializers) {
10490 Expression previous = ec.CurrentInitializerVariable;
10491 ec.CurrentInitializerVariable = target;
10492 source = source.Resolve (ec);
10493 ec.CurrentInitializerVariable = previous;
10494 if (source == null)
10497 eclass = source.eclass;
10498 type = source.Type;
10502 return base.DoResolve (ec);
10505 public override void EmitStatement (EmitContext ec)
10507 if (source is CollectionOrObjectInitializers)
10510 base.EmitStatement (ec);
10515 // A collection initializer expression
10517 class CollectionElementInitializer : Invocation
10519 public class ElementInitializerArgument : Argument
10521 public ElementInitializerArgument (Expression e)
10527 sealed class AddMemberAccess : MemberAccess
10529 public AddMemberAccess (Expression expr, Location loc)
10530 : base (expr, "Add", loc)
10534 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10536 if (TypeManager.HasElementType (type))
10539 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10543 public CollectionElementInitializer (Expression argument)
10544 : base (null, new Arguments (1))
10546 base.arguments.Add (new ElementInitializerArgument (argument));
10547 this.loc = argument.Location;
10550 public CollectionElementInitializer (List<Expression> arguments, Location loc)
10551 : base (null, new Arguments (arguments.Count))
10553 foreach (Expression e in arguments)
10554 base.arguments.Add (new ElementInitializerArgument (e));
10559 public override Expression CreateExpressionTree (ResolveContext ec)
10561 Arguments args = new Arguments (2);
10562 args.Add (new Argument (mg.CreateExpressionTree (ec)));
10564 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
10565 foreach (Argument a in arguments)
10566 expr_initializers.Add (a.CreateExpressionTree (ec));
10568 args.Add (new Argument (new ArrayCreation (
10569 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
10570 return CreateExpressionFactoryCall (ec, "ElementInit", args);
10573 protected override void CloneTo (CloneContext clonectx, Expression t)
10575 CollectionElementInitializer target = (CollectionElementInitializer) t;
10576 if (arguments != null)
10577 target.arguments = arguments.Clone (clonectx);
10580 protected override Expression DoResolve (ResolveContext ec)
10582 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
10584 return base.DoResolve (ec);
10589 // A block of object or collection initializers
10591 public class CollectionOrObjectInitializers : ExpressionStatement
10593 IList<Expression> initializers;
10594 bool is_collection_initialization;
10596 public CollectionOrObjectInitializers (Location loc)
10597 : this (new Expression[0], loc)
10601 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10603 this.initializers = initializers;
10607 public IList<Expression> Initializers {
10609 return initializers;
10613 public bool IsEmpty {
10615 return initializers.Count == 0;
10619 public bool IsCollectionInitializer {
10621 return is_collection_initialization;
10625 protected override void CloneTo (CloneContext clonectx, Expression target)
10627 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10629 t.initializers = new List<Expression> (initializers.Count);
10630 foreach (var e in initializers)
10631 t.initializers.Add (e.Clone (clonectx));
10634 public override bool ContainsEmitWithAwait ()
10636 foreach (var e in initializers) {
10637 if (e.ContainsEmitWithAwait ())
10644 public override Expression CreateExpressionTree (ResolveContext ec)
10646 return CreateExpressionTree (ec, false);
10649 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10651 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10652 foreach (Expression e in initializers) {
10653 Expression expr = e.CreateExpressionTree (ec);
10655 expr_initializers.Add (expr);
10659 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10661 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10664 protected override Expression DoResolve (ResolveContext ec)
10666 List<string> element_names = null;
10667 for (int i = 0; i < initializers.Count; ++i) {
10668 Expression initializer = initializers [i];
10669 ElementInitializer element_initializer = initializer as ElementInitializer;
10672 if (element_initializer != null) {
10673 element_names = new List<string> (initializers.Count);
10674 element_names.Add (element_initializer.Name);
10675 } else if (initializer is CompletingExpression){
10676 initializer.Resolve (ec);
10677 throw new InternalErrorException ("This line should never be reached");
10679 var t = ec.CurrentInitializerVariable.Type;
10680 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10681 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10682 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10683 "object initializer because type `{1}' does not implement `{2}' interface",
10684 ec.CurrentInitializerVariable.GetSignatureForError (),
10685 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10686 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10689 is_collection_initialization = true;
10692 if (is_collection_initialization != (element_initializer == null)) {
10693 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10694 is_collection_initialization ? "collection initializer" : "object initializer");
10698 if (!is_collection_initialization) {
10699 if (element_names.Contains (element_initializer.Name)) {
10700 ec.Report.Error (1912, element_initializer.Location,
10701 "An object initializer includes more than one member `{0}' initialization",
10702 element_initializer.Name);
10704 element_names.Add (element_initializer.Name);
10709 Expression e = initializer.Resolve (ec);
10710 if (e == EmptyExpressionStatement.Instance)
10711 initializers.RemoveAt (i--);
10713 initializers [i] = e;
10716 type = ec.CurrentInitializerVariable.Type;
10717 if (is_collection_initialization) {
10718 if (TypeManager.HasElementType (type)) {
10719 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10720 type.GetSignatureForError ());
10724 eclass = ExprClass.Variable;
10728 public override void Emit (EmitContext ec)
10730 EmitStatement (ec);
10733 public override void EmitStatement (EmitContext ec)
10735 foreach (ExpressionStatement e in initializers) {
10736 // TODO: need location region
10737 ec.Mark (e.Location);
10738 e.EmitStatement (ec);
10744 // New expression with element/object initializers
10746 public class NewInitialize : New
10749 // This class serves as a proxy for variable initializer target instances.
10750 // A real variable is assigned later when we resolve left side of an
10753 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10755 NewInitialize new_instance;
10757 public InitializerTargetExpression (NewInitialize newInstance)
10759 this.type = newInstance.type;
10760 this.loc = newInstance.loc;
10761 this.eclass = newInstance.eclass;
10762 this.new_instance = newInstance;
10765 public override bool ContainsEmitWithAwait ()
10770 public override Expression CreateExpressionTree (ResolveContext ec)
10772 // Should not be reached
10773 throw new NotSupportedException ("ET");
10776 protected override Expression DoResolve (ResolveContext ec)
10781 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10786 public override void Emit (EmitContext ec)
10788 Expression e = (Expression) new_instance.instance;
10792 public override Expression EmitToField (EmitContext ec)
10794 return (Expression) new_instance.instance;
10797 #region IMemoryLocation Members
10799 public void AddressOf (EmitContext ec, AddressOp mode)
10801 new_instance.instance.AddressOf (ec, mode);
10807 CollectionOrObjectInitializers initializers;
10808 IMemoryLocation instance;
10809 DynamicExpressionStatement dynamic;
10811 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10812 : base (requested_type, arguments, l)
10814 this.initializers = initializers;
10817 public CollectionOrObjectInitializers Initializers {
10819 return initializers;
10823 protected override void CloneTo (CloneContext clonectx, Expression t)
10825 base.CloneTo (clonectx, t);
10827 NewInitialize target = (NewInitialize) t;
10828 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
10831 public override bool ContainsEmitWithAwait ()
10833 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
10836 public override Expression CreateExpressionTree (ResolveContext ec)
10838 Arguments args = new Arguments (2);
10839 args.Add (new Argument (base.CreateExpressionTree (ec)));
10840 if (!initializers.IsEmpty)
10841 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
10843 return CreateExpressionFactoryCall (ec,
10844 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
10848 protected override Expression DoResolve (ResolveContext ec)
10850 Expression e = base.DoResolve (ec);
10854 if (type.IsDelegate) {
10855 ec.Report.Error (1958, Initializers.Location,
10856 "Object and collection initializers cannot be used to instantiate a delegate");
10859 Expression previous = ec.CurrentInitializerVariable;
10860 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
10861 initializers.Resolve (ec);
10862 ec.CurrentInitializerVariable = previous;
10864 dynamic = e as DynamicExpressionStatement;
10865 if (dynamic != null)
10871 public override bool Emit (EmitContext ec, IMemoryLocation target)
10873 bool left_on_stack;
10874 if (dynamic != null) {
10876 left_on_stack = true;
10878 left_on_stack = base.Emit (ec, target);
10881 if (initializers.IsEmpty)
10882 return left_on_stack;
10884 LocalTemporary temp = null;
10886 instance = target as LocalTemporary;
10888 if (instance == null) {
10889 if (!left_on_stack) {
10890 VariableReference vr = target as VariableReference;
10892 // FIXME: This still does not work correctly for pre-set variables
10893 if (vr != null && vr.IsRef)
10894 target.AddressOf (ec, AddressOp.Load);
10896 ((Expression) target).Emit (ec);
10897 left_on_stack = true;
10900 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
10901 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
10903 temp = new LocalTemporary (type);
10908 if (left_on_stack && temp != null)
10911 initializers.Emit (ec);
10913 if (left_on_stack) {
10914 if (temp != null) {
10918 ((Expression) instance).Emit (ec);
10922 return left_on_stack;
10925 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
10927 instance = base.EmitAddressOf (ec, Mode);
10929 if (!initializers.IsEmpty)
10930 initializers.Emit (ec);
10935 public override object Accept (StructuralVisitor visitor)
10937 return visitor.Visit (this);
10941 public class NewAnonymousType : New
10943 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
10945 List<AnonymousTypeParameter> parameters;
10946 readonly TypeContainer parent;
10947 AnonymousTypeClass anonymous_type;
10949 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
10950 : base (null, null, loc)
10952 this.parameters = parameters;
10953 this.parent = parent;
10956 public List<AnonymousTypeParameter> Parameters {
10958 return this.parameters;
10962 protected override void CloneTo (CloneContext clonectx, Expression target)
10964 if (parameters == null)
10967 NewAnonymousType t = (NewAnonymousType) target;
10968 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
10969 foreach (AnonymousTypeParameter atp in parameters)
10970 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
10973 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
10975 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
10979 type = AnonymousTypeClass.Create (parent, parameters, loc);
10983 int errors = ec.Report.Errors;
10984 type.CreateContainer ();
10985 type.DefineContainer ();
10987 if ((ec.Report.Errors - errors) == 0) {
10988 parent.Module.AddAnonymousType (type);
10994 public override Expression CreateExpressionTree (ResolveContext ec)
10996 if (parameters == null)
10997 return base.CreateExpressionTree (ec);
10999 var init = new ArrayInitializer (parameters.Count, loc);
11000 foreach (var m in anonymous_type.Members) {
11001 var p = m as Property;
11003 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
11006 var ctor_args = new ArrayInitializer (arguments.Count, loc);
11007 foreach (Argument a in arguments)
11008 ctor_args.Add (a.CreateExpressionTree (ec));
11010 Arguments args = new Arguments (3);
11011 args.Add (new Argument (new TypeOfMethod (method, loc)));
11012 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
11013 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
11015 return CreateExpressionFactoryCall (ec, "New", args);
11018 protected override Expression DoResolve (ResolveContext ec)
11020 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
11021 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
11025 if (parameters == null) {
11026 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
11027 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
11028 return base.DoResolve (ec);
11031 bool error = false;
11032 arguments = new Arguments (parameters.Count);
11033 var t_args = new TypeSpec [parameters.Count];
11034 for (int i = 0; i < parameters.Count; ++i) {
11035 Expression e = parameters [i].Resolve (ec);
11041 arguments.Add (new Argument (e));
11042 t_args [i] = e.Type;
11048 anonymous_type = CreateAnonymousType (ec, parameters);
11049 if (anonymous_type == null)
11052 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
11053 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
11054 eclass = ExprClass.Value;
11058 public override void EmitStatement (EmitContext ec)
11060 base.EmitStatement (ec);
11063 public override object Accept (StructuralVisitor visitor)
11065 return visitor.Visit (this);
11069 public class AnonymousTypeParameter : ShimExpression
11071 public readonly string Name;
11073 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
11074 : base (initializer)
11080 public AnonymousTypeParameter (Parameter parameter)
11081 : base (new SimpleName (parameter.Name, parameter.Location))
11083 this.Name = parameter.Name;
11084 this.loc = parameter.Location;
11087 public override bool Equals (object o)
11089 AnonymousTypeParameter other = o as AnonymousTypeParameter;
11090 return other != null && Name == other.Name;
11093 public override int GetHashCode ()
11095 return Name.GetHashCode ();
11098 protected override Expression DoResolve (ResolveContext ec)
11100 Expression e = expr.Resolve (ec);
11104 if (e.eclass == ExprClass.MethodGroup) {
11105 Error_InvalidInitializer (ec, e.ExprClassName);
11110 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
11111 Error_InvalidInitializer (ec, type.GetSignatureForError ());
11118 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
11120 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
11121 Name, initializer);