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);
2756 expr = ResolveUserOperator (rc, left, right);
2761 bool lenum = l.IsEnum;
2762 bool renum = r.IsEnum;
2763 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2767 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2768 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
2773 if ((oper & Operator.BitwiseMask) != 0) {
2774 expr = EmptyCast.Create (expr, type);
2775 AddEnumResultCast (type);
2777 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
2778 expr = OptimizeAndOperation (expr);
2782 left = ConvertEnumOperandToUnderlyingType (rc, left);
2783 right = ConvertEnumOperandToUnderlyingType (rc, right);
2786 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
2787 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2791 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
2794 // We cannot break here there is also Enum + String possible match
2795 // which is not ambiguous with predefined enum operators
2798 left = ConvertEnumOperandToUnderlyingType (rc, left);
2799 right = ConvertEnumOperandToUnderlyingType (rc, right);
2803 } else if (l.IsDelegate || r.IsDelegate) {
2807 expr = ResolveOperatorDelegate (rc, l, r);
2809 // TODO: Can this be ambiguous
2817 // Equality operators are more complicated
2819 if ((oper & Operator.EqualityMask) != 0) {
2820 return ResolveEquality (rc, l, r, primitives_only);
2823 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
2827 if (primitives_only)
2831 // Lifted operators have lower priority
2833 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
2836 static bool IsEnumOrNullableEnum (TypeSpec type)
2838 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
2842 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2843 // if 'left' is not an enumeration constant, create one from the type of 'right'
2844 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2847 case Operator.BitwiseOr:
2848 case Operator.BitwiseAnd:
2849 case Operator.ExclusiveOr:
2850 case Operator.Equality:
2851 case Operator.Inequality:
2852 case Operator.LessThan:
2853 case Operator.LessThanOrEqual:
2854 case Operator.GreaterThan:
2855 case Operator.GreaterThanOrEqual:
2856 if (left.Type.IsEnum)
2859 if (left.IsZeroInteger)
2860 return left.Reduce (ec, right.Type);
2864 case Operator.Addition:
2865 case Operator.Subtraction:
2868 case Operator.Multiply:
2869 case Operator.Division:
2870 case Operator.Modulus:
2871 case Operator.LeftShift:
2872 case Operator.RightShift:
2873 if (right.Type.IsEnum || left.Type.IsEnum)
2882 // The `|' operator used on types which were extended is dangerous
2884 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2886 OpcodeCast lcast = left as OpcodeCast;
2887 if (lcast != null) {
2888 if (IsUnsigned (lcast.UnderlyingType))
2892 OpcodeCast rcast = right as OpcodeCast;
2893 if (rcast != null) {
2894 if (IsUnsigned (rcast.UnderlyingType))
2898 if (lcast == null && rcast == null)
2901 // FIXME: consider constants
2903 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
2904 ec.Report.Warning (675, 3, loc,
2905 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2906 ltype.GetSignatureForError ());
2909 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
2911 return new PredefinedOperator[] {
2913 // Pointer arithmetic:
2915 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2916 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2917 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2918 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2920 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
2921 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
2922 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
2923 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
2926 // T* operator + (int y, T* x);
2927 // T* operator + (uint y, T *x);
2928 // T* operator + (long y, T *x);
2929 // T* operator + (ulong y, T *x);
2931 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
2932 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
2933 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
2934 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
2937 // long operator - (T* x, T *y)
2939 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
2943 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
2945 TypeSpec bool_type = types.Bool;
2948 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
2949 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
2950 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
2951 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
2952 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
2953 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
2954 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
2956 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
2957 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
2958 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
2959 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
2960 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
2961 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
2962 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
2964 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
2965 // Remaining string operators are in lifted tables
2967 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
2969 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
2970 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
2971 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
2975 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
2977 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
2978 if (nullable == null)
2979 return new PredefinedOperator [0];
2981 var types = module.Compiler.BuiltinTypes;
2982 var bool_type = types.Bool;
2984 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
2985 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
2986 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
2987 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
2988 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
2989 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
2990 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
2991 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
2994 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
2995 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
2996 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
2997 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
2998 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
2999 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3000 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3002 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3003 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3004 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3005 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3006 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3007 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3008 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3010 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3012 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3013 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3014 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3017 // Not strictly lifted but need to be in second group otherwise expressions like
3018 // int + null would resolve to +(object, string) instead of +(int?, int?)
3020 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3021 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3026 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3028 TypeSpec bool_type = types.Bool;
3031 new PredefinedEqualityOperator (types.String, bool_type),
3032 new PredefinedEqualityOperator (types.Delegate, bool_type),
3033 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3034 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3035 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3036 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3037 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3038 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3039 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3040 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3044 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3046 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3048 if (nullable == null)
3049 return new PredefinedOperator [0];
3051 var types = module.Compiler.BuiltinTypes;
3052 var bool_type = types.Bool;
3053 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3054 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3055 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3056 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3057 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3058 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3059 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3060 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3063 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3064 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3065 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3066 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3067 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3068 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3069 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3070 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3075 // 7.2.6.2 Binary numeric promotions
3077 bool DoBinaryOperatorPromotion (ResolveContext rc)
3079 TypeSpec ltype = left.Type;
3080 if (ltype.IsNullableType) {
3081 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
3085 // This is numeric promotion code only
3087 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
3090 TypeSpec rtype = right.Type;
3091 if (rtype.IsNullableType) {
3092 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
3095 var lb = ltype.BuiltinType;
3096 var rb = rtype.BuiltinType;
3100 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
3101 type = rc.BuiltinTypes.Decimal;
3102 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
3103 type = rc.BuiltinTypes.Double;
3104 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
3105 type = rc.BuiltinTypes.Float;
3106 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
3107 type = rc.BuiltinTypes.ULong;
3109 if (IsSignedType (lb)) {
3110 expr = ConvertSignedConstant (left, type);
3114 } else if (IsSignedType (rb)) {
3115 expr = ConvertSignedConstant (right, type);
3121 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
3122 type = rc.BuiltinTypes.Long;
3123 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
3124 type = rc.BuiltinTypes.UInt;
3126 if (IsSignedType (lb)) {
3127 expr = ConvertSignedConstant (left, type);
3129 type = rc.BuiltinTypes.Long;
3130 } else if (IsSignedType (rb)) {
3131 expr = ConvertSignedConstant (right, type);
3133 type = rc.BuiltinTypes.Long;
3136 type = rc.BuiltinTypes.Int;
3139 if (ltype != type) {
3140 expr = PromoteExpression (rc, left, type);
3147 if (rtype != type) {
3148 expr = PromoteExpression (rc, right, type);
3158 static bool IsSignedType (BuiltinTypeSpec.Type type)
3161 case BuiltinTypeSpec.Type.Int:
3162 case BuiltinTypeSpec.Type.Short:
3163 case BuiltinTypeSpec.Type.SByte:
3164 case BuiltinTypeSpec.Type.Long:
3171 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
3173 var c = expr as Constant;
3177 return c.ConvertImplicitly (type);
3180 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
3182 if (expr.Type.IsNullableType) {
3183 return Convert.ImplicitConversionStandard (rc, expr,
3184 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
3187 var c = expr as Constant;
3189 return c.ConvertImplicitly (type);
3191 return Convert.ImplicitNumericConversion (expr, type);
3194 protected override Expression DoResolve (ResolveContext ec)
3199 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
3200 left = ((ParenthesizedExpression) left).Expr;
3201 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
3205 if (left.eclass == ExprClass.Type) {
3206 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
3210 left = left.Resolve (ec);
3215 Constant lc = left as Constant;
3217 if (lc != null && lc.Type.BuiltinType == BuiltinTypeSpec.Type.Bool &&
3218 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
3219 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
3221 // FIXME: resolve right expression as unreachable
3222 // right.Resolve (ec);
3224 ec.Report.Warning (429, 4, right.StartLocation, "Unreachable expression code detected");
3228 right = right.Resolve (ec);
3232 Constant rc = right as Constant;
3234 // The conversion rules are ignored in enum context but why
3235 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
3236 lc = EnumLiftUp (ec, lc, rc, loc);
3238 rc = EnumLiftUp (ec, rc, lc, loc);
3241 if (rc != null && lc != null) {
3242 int prev_e = ec.Report.Errors;
3243 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
3244 if (e != null || ec.Report.Errors != prev_e)
3248 // Comparison warnings
3249 if ((oper & Operator.ComparisonMask) != 0) {
3250 if (left.Equals (right)) {
3251 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
3253 CheckOutOfRangeComparison (ec, lc, right.Type);
3254 CheckOutOfRangeComparison (ec, rc, left.Type);
3257 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3259 var rt = right.Type;
3260 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
3261 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
3262 Error_OperatorCannotBeApplied (ec, left, right);
3269 // Special handling for logical boolean operators which require rhs not to be
3270 // evaluated based on lhs value
3272 if ((oper & Operator.LogicalMask) != 0) {
3273 Expression cond_left, cond_right, expr;
3275 args = new Arguments (2);
3277 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3278 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, ec.CurrentBlock, loc);
3280 var cond_args = new Arguments (1);
3281 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left).Resolve (ec)));
3284 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
3285 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
3287 left = temp.CreateReferenceExpression (ec, loc);
3288 if (oper == Operator.LogicalAnd) {
3289 expr = DynamicUnaryConversion.CreateIsFalse (ec, cond_args, loc);
3292 expr = DynamicUnaryConversion.CreateIsTrue (ec, cond_args, loc);
3296 args.Add (new Argument (left));
3297 args.Add (new Argument (right));
3298 cond_right = new DynamicExpressionStatement (this, args, loc);
3300 LocalVariable temp = LocalVariable.CreateCompilerGenerated (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
3302 args.Add (new Argument (temp.CreateReferenceExpression (ec, loc).Resolve (ec)));
3303 args.Add (new Argument (right));
3304 right = new DynamicExpressionStatement (this, args, loc);
3307 // bool && dynamic => (temp = left) ? temp && right : temp;
3308 // bool || dynamic => (temp = left) ? temp : temp || right;
3310 if (oper == Operator.LogicalAnd) {
3312 cond_right = temp.CreateReferenceExpression (ec, loc);
3314 cond_left = temp.CreateReferenceExpression (ec, loc);
3318 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left));
3321 return new Conditional (expr, cond_left, cond_right, loc).Resolve (ec);
3324 args = new Arguments (2);
3325 args.Add (new Argument (left));
3326 args.Add (new Argument (right));
3327 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
3330 return DoResolveCore (ec, left, right);
3333 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3335 Expression expr = ResolveOperator (ec);
3337 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3339 if (left == null || right == null)
3340 throw new InternalErrorException ("Invalid conversion");
3342 if (oper == Operator.BitwiseOr)
3343 CheckBitwiseOrOnSignExtended (ec);
3348 public override SLE.Expression MakeExpression (BuilderContext ctx)
3350 return MakeExpression (ctx, left, right);
3353 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
3355 Console.WriteLine ("{0} x {1}", left.Type.GetSignatureForError (), right.Type.GetSignatureForError ());
3357 var le = left.MakeExpression (ctx);
3358 var re = right.MakeExpression (ctx);
3359 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3362 case Operator.Addition:
3363 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3364 case Operator.BitwiseAnd:
3365 return SLE.Expression.And (le, re);
3366 case Operator.BitwiseOr:
3367 return SLE.Expression.Or (le, re);
3368 case Operator.Division:
3369 return SLE.Expression.Divide (le, re);
3370 case Operator.Equality:
3371 return SLE.Expression.Equal (le, re);
3372 case Operator.ExclusiveOr:
3373 return SLE.Expression.ExclusiveOr (le, re);
3374 case Operator.GreaterThan:
3375 return SLE.Expression.GreaterThan (le, re);
3376 case Operator.GreaterThanOrEqual:
3377 return SLE.Expression.GreaterThanOrEqual (le, re);
3378 case Operator.Inequality:
3379 return SLE.Expression.NotEqual (le, re);
3380 case Operator.LeftShift:
3381 return SLE.Expression.LeftShift (le, re);
3382 case Operator.LessThan:
3383 return SLE.Expression.LessThan (le, re);
3384 case Operator.LessThanOrEqual:
3385 return SLE.Expression.LessThanOrEqual (le, re);
3386 case Operator.LogicalAnd:
3387 return SLE.Expression.AndAlso (le, re);
3388 case Operator.LogicalOr:
3389 return SLE.Expression.OrElse (le, re);
3390 case Operator.Modulus:
3391 return SLE.Expression.Modulo (le, re);
3392 case Operator.Multiply:
3393 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3394 case Operator.RightShift:
3395 return SLE.Expression.RightShift (le, re);
3396 case Operator.Subtraction:
3397 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3399 throw new NotImplementedException (oper.ToString ());
3404 // D operator + (D x, D y)
3405 // D operator - (D x, D y)
3407 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3409 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3411 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3412 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3417 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3418 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3428 MethodSpec method = null;
3429 Arguments args = new Arguments (2);
3430 args.Add (new Argument (left));
3431 args.Add (new Argument (right));
3433 if (oper == Operator.Addition) {
3434 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3435 } else if (oper == Operator.Subtraction) {
3436 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3440 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3442 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
3443 return new ClassCast (expr, l);
3447 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
3449 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
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);
3457 // bool operator >= (E x, E y);
3459 // E operator & (E x, E y);
3460 // E operator | (E x, E y);
3461 // E operator ^ (E x, E y);
3464 if ((oper & Operator.ComparisonMask) != 0) {
3465 type = rc.BuiltinTypes.Bool;
3471 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3477 if (ltype == rtype) {
3481 var lifted = new Nullable.LiftedBinaryOperator (this);
3483 lifted.Right = right;
3484 return lifted.Resolve (rc);
3487 if (renum && !ltype.IsNullableType) {
3488 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
3493 } else if (lenum && !rtype.IsNullableType) {
3494 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
3502 // Now try lifted version of predefined operator
3504 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
3505 if (nullable_type != null) {
3506 if (renum && !ltype.IsNullableType) {
3507 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
3509 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3512 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3515 if ((oper & Operator.BitwiseMask) != 0)
3519 if ((oper & Operator.BitwiseMask) != 0)
3520 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3522 return CreateLiftedValueTypeResult (rc, rtype);
3526 var lifted = new Nullable.LiftedBinaryOperator (this);
3528 lifted.Right = right;
3529 return lifted.Resolve (rc);
3531 } else if (lenum && !rtype.IsNullableType) {
3532 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
3534 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3537 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3540 if ((oper & Operator.BitwiseMask) != 0)
3544 if ((oper & Operator.BitwiseMask) != 0)
3545 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3547 return CreateLiftedValueTypeResult (rc, ltype);
3551 var lifted = new Nullable.LiftedBinaryOperator (this);
3553 lifted.Right = expr;
3554 return lifted.Resolve (rc);
3556 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
3558 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3559 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
3561 if ((oper & Operator.RelationalMask) != 0)
3562 return CreateLiftedValueTypeResult (rc, rtype);
3564 if ((oper & Operator.BitwiseMask) != 0)
3565 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3567 // Equality operators are valid between E? and null
3570 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
3576 var lifted = new Nullable.LiftedBinaryOperator (this);
3578 lifted.Right = right;
3579 return lifted.Resolve (rc);
3581 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
3583 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3584 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
3586 if ((oper & Operator.RelationalMask) != 0)
3587 return CreateLiftedValueTypeResult (rc, ltype);
3589 if ((oper & Operator.BitwiseMask) != 0)
3590 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3592 // Equality operators are valid between E? and null
3595 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
3601 var lifted = new Nullable.LiftedBinaryOperator (this);
3603 lifted.Right = expr;
3604 return lifted.Resolve (rc);
3612 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr)
3614 TypeSpec underlying_type;
3615 if (expr.Type.IsNullableType) {
3616 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
3618 underlying_type = EnumSpec.GetUnderlyingType (nt);
3620 underlying_type = nt;
3621 } else if (expr.Type.IsEnum) {
3622 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
3624 underlying_type = expr.Type;
3627 switch (underlying_type.BuiltinType) {
3628 case BuiltinTypeSpec.Type.SByte:
3629 case BuiltinTypeSpec.Type.Byte:
3630 case BuiltinTypeSpec.Type.Short:
3631 case BuiltinTypeSpec.Type.UShort:
3632 underlying_type = rc.BuiltinTypes.Int;
3636 if (expr.Type.IsNullableType)
3637 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
3639 if (expr.Type == underlying_type)
3642 return EmptyCast.Create (expr, underlying_type);
3645 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3648 // U operator - (E e, E f)
3649 // E operator - (E e, U x) // Internal decomposition operator
3650 // E operator - (U x, E e) // Internal decomposition operator
3652 // E operator + (E e, U x)
3653 // E operator + (U x, E e)
3662 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3668 if (!enum_type.IsNullableType) {
3669 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
3671 if (oper == Operator.Subtraction)
3672 expr = ConvertEnumSubtractionResult (rc, expr);
3674 expr = ConvertEnumAdditionalResult (expr, enum_type);
3676 AddEnumResultCast (expr.Type);
3681 enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
3684 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
3686 if (oper == Operator.Subtraction)
3687 expr = ConvertEnumSubtractionResult (rc, expr);
3689 expr = ConvertEnumAdditionalResult (expr, enum_type);
3691 AddEnumResultCast (expr.Type);
3697 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
3699 return EmptyCast.Create (expr, enumType);
3702 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
3705 // Enumeration subtraction has different result type based on
3708 TypeSpec result_type;
3709 if (left.Type == right.Type) {
3710 var c = right as EnumConstant;
3711 if (c != null && c.IsZeroInteger) {
3713 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
3714 // E which is not what expressions E - 1 or 0 - E return
3716 result_type = left.Type;
3718 result_type = left.Type.IsNullableType ?
3719 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
3720 EnumSpec.GetUnderlyingType (left.Type);
3722 } else if (IsEnumOrNullableEnum (left.Type)) {
3723 result_type = left.Type;
3725 result_type = right.Type;
3728 return EmptyCast.Create (expr, result_type);
3731 void AddEnumResultCast (TypeSpec type)
3733 if (type.IsNullableType)
3734 type = Nullable.NullableInfo.GetUnderlyingType (type);
3737 type = EnumSpec.GetUnderlyingType (type);
3739 switch (type.BuiltinType) {
3740 case BuiltinTypeSpec.Type.SByte:
3741 enum_conversion = ConvCast.Mode.I4_I1;
3743 case BuiltinTypeSpec.Type.Byte:
3744 enum_conversion = ConvCast.Mode.I4_U1;
3746 case BuiltinTypeSpec.Type.Short:
3747 enum_conversion = ConvCast.Mode.I4_I2;
3749 case BuiltinTypeSpec.Type.UShort:
3750 enum_conversion = ConvCast.Mode.I4_U2;
3756 // Equality operators rules
3758 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
3761 type = ec.BuiltinTypes.Bool;
3762 bool no_arg_conv = false;
3764 if (!primitives_only) {
3767 // a, Both operands are reference-type values or the value null
3768 // b, One operand is a value of type T where T is a type-parameter and
3769 // the other operand is the value null. Furthermore T does not have the
3770 // value type constraint
3772 // LAMESPEC: Very confusing details in the specification, basically any
3773 // reference like type-parameter is allowed
3775 var tparam_l = l as TypeParameterSpec;
3776 var tparam_r = r as TypeParameterSpec;
3777 if (tparam_l != null) {
3778 if (right is NullLiteral) {
3779 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3782 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3786 if (!tparam_l.IsReferenceType)
3789 l = tparam_l.GetEffectiveBase ();
3790 left = new BoxedCast (left, l);
3791 } else if (left is NullLiteral && tparam_r == null) {
3792 if (TypeSpec.IsReferenceType (r))
3795 if (r.Kind == MemberKind.InternalCompilerType)
3799 if (tparam_r != null) {
3800 if (left is NullLiteral) {
3801 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3804 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3808 if (!tparam_r.IsReferenceType)
3811 r = tparam_r.GetEffectiveBase ();
3812 right = new BoxedCast (right, r);
3813 } else if (right is NullLiteral) {
3814 if (TypeSpec.IsReferenceType (l))
3817 if (l.Kind == MemberKind.InternalCompilerType)
3822 // LAMESPEC: method groups can be compared when they convert to other side delegate
3825 if (right.eclass == ExprClass.MethodGroup) {
3826 result = Convert.ImplicitConversion (ec, right, l, loc);
3832 } else if (r.IsDelegate && l != r) {
3835 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3836 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3843 no_arg_conv = l == r && !l.IsStruct;
3848 // bool operator != (string a, string b)
3849 // bool operator == (string a, string b)
3851 // bool operator != (Delegate a, Delegate b)
3852 // bool operator == (Delegate a, Delegate b)
3854 // bool operator != (bool a, bool b)
3855 // bool operator == (bool a, bool b)
3857 // LAMESPEC: Reference equality comparison can apply to value/reference types when
3858 // they implement an implicit conversion to any of types above. This does
3859 // not apply when both operands are of same reference type
3861 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3862 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
3867 // Now try lifted version of predefined operators
3869 if (no_arg_conv && !l.IsNullableType) {
3871 // Optimizes cases which won't match
3874 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
3880 // The == and != operators permit one operand to be a value of a nullable
3881 // type and the other to be the null literal, even if no predefined or user-defined
3882 // operator (in unlifted or lifted form) exists for the operation.
3884 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
3885 var lifted = new Nullable.LiftedBinaryOperator (this);
3887 lifted.Right = right;
3888 return lifted.Resolve (ec);
3893 // bool operator != (object a, object b)
3894 // bool operator == (object a, object b)
3896 // An explicit reference conversion exists from the
3897 // type of either operand to the type of the other operand.
3900 // Optimize common path
3902 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3905 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3906 !Convert.ExplicitReferenceConversionExists (r, l))
3909 // Reject allowed explicit conversions like int->object
3910 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
3913 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3914 ec.Report.Warning (253, 2, loc,
3915 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3916 l.GetSignatureForError ());
3918 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3919 ec.Report.Warning (252, 2, loc,
3920 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3921 r.GetSignatureForError ());
3927 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3930 // bool operator == (void* x, void* y);
3931 // bool operator != (void* x, void* y);
3932 // bool operator < (void* x, void* y);
3933 // bool operator > (void* x, void* y);
3934 // bool operator <= (void* x, void* y);
3935 // bool operator >= (void* x, void* y);
3937 if ((oper & Operator.ComparisonMask) != 0) {
3940 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3947 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3953 type = ec.BuiltinTypes.Bool;
3957 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
3961 // Build-in operators method overloading
3963 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
3965 PredefinedOperator best_operator = null;
3966 TypeSpec l = left.Type;
3967 TypeSpec r = right.Type;
3968 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3970 foreach (PredefinedOperator po in operators) {
3971 if ((po.OperatorsMask & oper_mask) == 0)
3974 if (primitives_only) {
3975 if (!po.IsPrimitiveApplicable (l, r))
3978 if (!po.IsApplicable (ec, left, right))
3982 if (best_operator == null) {
3984 if (primitives_only)
3990 best_operator = po.ResolveBetterOperator (ec, best_operator);
3992 if (best_operator == null) {
3993 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3994 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4001 if (best_operator == null)
4004 var expr = best_operator.ConvertResult (ec, this);
4006 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) && !best_operator.IsLifted) {
4007 expr = OptimizeAndOperation (expr);
4014 // Optimize &/&& constant expressions with 0 value
4016 Expression OptimizeAndOperation (Expression expr)
4018 Constant rc = right as Constant;
4019 Constant lc = left as Constant;
4020 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4022 // The result is a constant with side-effect
4024 Constant side_effect = rc == null ?
4025 new SideEffectConstant (lc, right, loc) :
4026 new SideEffectConstant (rc, left, loc);
4028 return ReducedExpression.Create (side_effect, expr);
4035 // Value types can be compared with the null literal because of the lifting
4036 // language rules. However the result is always true or false.
4038 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4040 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4041 type = rc.BuiltinTypes.Bool;
4045 // FIXME: Handle side effect constants
4046 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4048 if ((Oper & Operator.EqualityMask) != 0) {
4049 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4050 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4052 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4053 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4060 // Performs user-operator overloading
4062 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4064 Expression oper_expr;
4066 var op = ConvertBinaryToUserOperator (oper);
4068 if (l.IsNullableType)
4069 l = Nullable.NullableInfo.GetUnderlyingType (l);
4071 if (r.IsNullableType)
4072 r = Nullable.NullableInfo.GetUnderlyingType (r);
4074 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
4075 IList<MemberSpec> right_operators = null;
4078 right_operators = MemberCache.GetUserOperator (r, op, false);
4079 if (right_operators == null && left_operators == null)
4081 } else if (left_operators == null) {
4085 Arguments args = new Arguments (2);
4086 Argument larg = new Argument (left);
4088 Argument rarg = new Argument (right);
4092 // User-defined operator implementations always take precedence
4093 // over predefined operator implementations
4095 if (left_operators != null && right_operators != null) {
4096 left_operators = CombineUserOperators (left_operators, right_operators);
4097 } else if (right_operators != null) {
4098 left_operators = right_operators;
4101 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
4102 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
4104 var res = new OverloadResolver (left_operators, restr, loc);
4106 var oper_method = res.ResolveOperator (rc, ref args);
4107 if (oper_method == null) {
4109 // Logical && and || cannot be lifted
4111 if ((oper & Operator.LogicalMask) != 0)
4115 // Apply lifted user operators only for liftable types. Implicit conversion
4116 // to nullable types is not allowed
4118 if (!IsLiftedOperatorApplicable ())
4121 // TODO: Cache the result in module container
4122 var lifted_methods = CreateLiftedOperators (rc, left_operators);
4123 if (lifted_methods == null)
4126 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
4128 oper_method = res.ResolveOperator (rc, ref args);
4129 if (oper_method == null)
4132 MethodSpec best_original = null;
4133 foreach (MethodSpec ms in left_operators) {
4134 if (ms.MemberDefinition == oper_method.MemberDefinition) {
4140 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4142 // Expression trees use lifted notation in this case
4144 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
4145 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
4148 var ptypes = best_original.Parameters.Types;
4150 if (left.IsNull || right.IsNull) {
4152 // The lifted operator produces the value false if one or both operands are null for
4153 // relational operators.
4155 if ((oper & Operator.ComparisonMask) != 0) {
4157 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
4158 // because return type is actually bool
4160 // For some reason CSC does not report this warning for equality operators
4162 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
4165 // The lifted operator produces a null value if one or both operands are null
4167 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
4168 type = oper_method.ReturnType;
4169 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4173 type = oper_method.ReturnType;
4174 var lifted = new Nullable.LiftedBinaryOperator (this);
4175 lifted.UserOperator = best_original;
4177 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
4178 lifted.UnwrapLeft = new Nullable.Unwrap (left);
4181 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
4182 lifted.UnwrapRight = new Nullable.Unwrap (right);
4185 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
4186 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
4188 return lifted.Resolve (rc);
4191 if ((oper & Operator.LogicalMask) != 0) {
4192 // TODO: CreateExpressionTree is allocated every time
4193 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
4194 oper == Operator.LogicalAnd, loc).Resolve (rc);
4196 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
4199 this.left = larg.Expr;
4200 this.right = rarg.Expr;
4205 bool IsLiftedOperatorApplicable ()
4207 if (left.Type.IsNullableType) {
4208 if ((oper & Operator.EqualityMask) != 0)
4209 return !right.IsNull;
4214 if (right.Type.IsNullableType) {
4215 if ((oper & Operator.EqualityMask) != 0)
4216 return !left.IsNull;
4221 if (TypeSpec.IsValueType (left.Type))
4222 return right.IsNull;
4224 if (TypeSpec.IsValueType (right.Type))
4230 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
4232 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4233 if (nullable_type == null)
4237 // Lifted operators permit predefined and user-defined operators that operate
4238 // on non-nullable value types to also be used with nullable forms of those types.
4239 // Lifted operators are constructed from predefined and user-defined operators
4240 // that meet certain requirements
4242 List<MemberSpec> lifted = null;
4243 foreach (MethodSpec oper in operators) {
4245 if ((Oper & Operator.ComparisonMask) != 0) {
4247 // Result type must be of type bool for lifted comparison operators
4249 rt = oper.ReturnType;
4250 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
4253 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
4259 var ptypes = oper.Parameters.Types;
4260 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
4264 // LAMESPEC: I am not sure why but for equality operators to be lifted
4265 // both types have to match
4267 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
4271 lifted = new List<MemberSpec> ();
4274 // The lifted form is constructed by adding a single ? modifier to each operand and
4275 // result type except for comparison operators where return type is bool
4278 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
4280 var parameters = ParametersCompiled.CreateFullyResolved (
4281 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
4282 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
4284 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
4285 rt, parameters, oper.Modifiers);
4287 lifted.Add (lifted_op);
4294 // Merge two sets of user operators into one, they are mostly distinguish
4295 // except when they share base type and it contains an operator
4297 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
4299 var combined = new List<MemberSpec> (left.Count + right.Count);
4300 combined.AddRange (left);
4301 foreach (var r in right) {
4303 foreach (var l in left) {
4304 if (l.DeclaringType == r.DeclaringType) {
4317 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
4319 if (c is IntegralConstant || c is CharConstant) {
4321 c.ConvertExplicitly (true, type);
4322 } catch (OverflowException) {
4323 ec.Report.Warning (652, 2, loc,
4324 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
4325 type.GetSignatureForError ());
4331 /// EmitBranchable is called from Statement.EmitBoolExpression in the
4332 /// context of a conditional bool expression. This function will return
4333 /// false if it is was possible to use EmitBranchable, or true if it was.
4335 /// The expression's code is generated, and we will generate a branch to `target'
4336 /// if the resulting expression value is equal to isTrue
4338 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
4341 // This is more complicated than it looks, but its just to avoid
4342 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
4343 // but on top of that we want for == and != to use a special path
4344 // if we are comparing against null
4346 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
4347 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
4350 // put the constant on the rhs, for simplicity
4352 if (left is Constant) {
4353 Expression swap = right;
4359 // brtrue/brfalse works with native int only
4361 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
4362 left.EmitBranchable (ec, target, my_on_true);
4365 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
4366 // right is a boolean, and it's not 'false' => it is 'true'
4367 left.EmitBranchable (ec, target, !my_on_true);
4371 } else if (oper == Operator.LogicalAnd) {
4374 Label tests_end = ec.DefineLabel ();
4376 left.EmitBranchable (ec, tests_end, false);
4377 right.EmitBranchable (ec, target, true);
4378 ec.MarkLabel (tests_end);
4381 // This optimizes code like this
4382 // if (true && i > 4)
4384 if (!(left is Constant))
4385 left.EmitBranchable (ec, target, false);
4387 if (!(right is Constant))
4388 right.EmitBranchable (ec, target, false);
4393 } else if (oper == Operator.LogicalOr){
4395 left.EmitBranchable (ec, target, true);
4396 right.EmitBranchable (ec, target, true);
4399 Label tests_end = ec.DefineLabel ();
4400 left.EmitBranchable (ec, tests_end, true);
4401 right.EmitBranchable (ec, target, false);
4402 ec.MarkLabel (tests_end);
4407 } else if ((oper & Operator.ComparisonMask) == 0) {
4408 base.EmitBranchable (ec, target, on_true);
4415 TypeSpec t = left.Type;
4416 bool is_float = IsFloat (t);
4417 bool is_unsigned = is_float || IsUnsigned (t);
4420 case Operator.Equality:
4422 ec.Emit (OpCodes.Beq, target);
4424 ec.Emit (OpCodes.Bne_Un, target);
4427 case Operator.Inequality:
4429 ec.Emit (OpCodes.Bne_Un, target);
4431 ec.Emit (OpCodes.Beq, target);
4434 case Operator.LessThan:
4436 if (is_unsigned && !is_float)
4437 ec.Emit (OpCodes.Blt_Un, target);
4439 ec.Emit (OpCodes.Blt, target);
4442 ec.Emit (OpCodes.Bge_Un, target);
4444 ec.Emit (OpCodes.Bge, target);
4447 case Operator.GreaterThan:
4449 if (is_unsigned && !is_float)
4450 ec.Emit (OpCodes.Bgt_Un, target);
4452 ec.Emit (OpCodes.Bgt, target);
4455 ec.Emit (OpCodes.Ble_Un, target);
4457 ec.Emit (OpCodes.Ble, target);
4460 case Operator.LessThanOrEqual:
4462 if (is_unsigned && !is_float)
4463 ec.Emit (OpCodes.Ble_Un, target);
4465 ec.Emit (OpCodes.Ble, target);
4468 ec.Emit (OpCodes.Bgt_Un, target);
4470 ec.Emit (OpCodes.Bgt, target);
4474 case Operator.GreaterThanOrEqual:
4476 if (is_unsigned && !is_float)
4477 ec.Emit (OpCodes.Bge_Un, target);
4479 ec.Emit (OpCodes.Bge, target);
4482 ec.Emit (OpCodes.Blt_Un, target);
4484 ec.Emit (OpCodes.Blt, target);
4487 throw new InternalErrorException (oper.ToString ());
4491 public override void Emit (EmitContext ec)
4493 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4494 left = left.EmitToField (ec);
4496 if ((oper & Operator.LogicalMask) == 0) {
4497 right = right.EmitToField (ec);
4502 // Handle short-circuit operators differently
4505 if ((oper & Operator.LogicalMask) != 0) {
4506 Label load_result = ec.DefineLabel ();
4507 Label end = ec.DefineLabel ();
4509 bool is_or = oper == Operator.LogicalOr;
4510 left.EmitBranchable (ec, load_result, is_or);
4512 ec.Emit (OpCodes.Br_S, end);
4514 ec.MarkLabel (load_result);
4515 ec.EmitInt (is_or ? 1 : 0);
4521 // Optimize zero-based operations which cannot be optimized at expression level
4523 if (oper == Operator.Subtraction) {
4524 var lc = left as IntegralConstant;
4525 if (lc != null && lc.IsDefaultValue) {
4527 ec.Emit (OpCodes.Neg);
4532 EmitOperator (ec, left, right);
4535 public void EmitOperator (EmitContext ec, Expression left, Expression right)
4540 EmitOperatorOpcode (ec, oper, left.Type, right);
4543 // Emit result enumerable conversion this way because it's quite complicated get it
4544 // to resolved tree because expression tree cannot see it.
4546 if (enum_conversion != 0)
4547 ConvCast.Emit (ec, enum_conversion);
4550 public override void EmitSideEffect (EmitContext ec)
4552 if ((oper & Operator.LogicalMask) != 0 ||
4553 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
4554 base.EmitSideEffect (ec);
4556 left.EmitSideEffect (ec);
4557 right.EmitSideEffect (ec);
4561 public override Expression EmitToField (EmitContext ec)
4563 if ((oper & Operator.LogicalMask) == 0) {
4564 var await_expr = left as Await;
4565 if (await_expr != null && right.IsSideEffectFree) {
4566 await_expr.Statement.EmitPrologue (ec);
4567 left = await_expr.Statement.GetResultExpression (ec);
4571 await_expr = right as Await;
4572 if (await_expr != null && left.IsSideEffectFree) {
4573 await_expr.Statement.EmitPrologue (ec);
4574 right = await_expr.Statement.GetResultExpression (ec);
4579 return base.EmitToField (ec);
4582 protected override void CloneTo (CloneContext clonectx, Expression t)
4584 Binary target = (Binary) t;
4586 target.left = left.Clone (clonectx);
4587 target.right = right.Clone (clonectx);
4590 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
4592 Arguments binder_args = new Arguments (4);
4594 MemberAccess sle = new MemberAccess (new MemberAccess (
4595 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
4597 CSharpBinderFlags flags = 0;
4598 if (ec.HasSet (ResolveContext.Options.CheckedScope))
4599 flags = CSharpBinderFlags.CheckedContext;
4601 if ((oper & Operator.LogicalMask) != 0)
4602 flags |= CSharpBinderFlags.BinaryOperationLogical;
4604 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
4605 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
4606 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
4607 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
4609 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
4612 public override Expression CreateExpressionTree (ResolveContext ec)
4614 return CreateExpressionTree (ec, null);
4617 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
4620 bool lift_arg = false;
4623 case Operator.Addition:
4624 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4625 method_name = "AddChecked";
4627 method_name = "Add";
4629 case Operator.BitwiseAnd:
4630 method_name = "And";
4632 case Operator.BitwiseOr:
4635 case Operator.Division:
4636 method_name = "Divide";
4638 case Operator.Equality:
4639 method_name = "Equal";
4642 case Operator.ExclusiveOr:
4643 method_name = "ExclusiveOr";
4645 case Operator.GreaterThan:
4646 method_name = "GreaterThan";
4649 case Operator.GreaterThanOrEqual:
4650 method_name = "GreaterThanOrEqual";
4653 case Operator.Inequality:
4654 method_name = "NotEqual";
4657 case Operator.LeftShift:
4658 method_name = "LeftShift";
4660 case Operator.LessThan:
4661 method_name = "LessThan";
4664 case Operator.LessThanOrEqual:
4665 method_name = "LessThanOrEqual";
4668 case Operator.LogicalAnd:
4669 method_name = "AndAlso";
4671 case Operator.LogicalOr:
4672 method_name = "OrElse";
4674 case Operator.Modulus:
4675 method_name = "Modulo";
4677 case Operator.Multiply:
4678 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4679 method_name = "MultiplyChecked";
4681 method_name = "Multiply";
4683 case Operator.RightShift:
4684 method_name = "RightShift";
4686 case Operator.Subtraction:
4687 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4688 method_name = "SubtractChecked";
4690 method_name = "Subtract";
4694 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4697 Arguments args = new Arguments (2);
4698 args.Add (new Argument (left.CreateExpressionTree (ec)));
4699 args.Add (new Argument (right.CreateExpressionTree (ec)));
4700 if (method != null) {
4702 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4704 args.Add (new Argument (method));
4707 return CreateExpressionFactoryCall (ec, method_name, args);
4710 public override object Accept (StructuralVisitor visitor)
4712 return visitor.Visit (this);
4718 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4719 // b, c, d... may be strings or objects.
4721 public class StringConcat : Expression
4723 Arguments arguments;
4725 StringConcat (Location loc)
4728 arguments = new Arguments (2);
4731 public override bool ContainsEmitWithAwait ()
4733 return arguments.ContainsEmitWithAwait ();
4736 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4738 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4739 throw new ArgumentException ();
4741 var s = new StringConcat (loc);
4742 s.type = rc.BuiltinTypes.String;
4743 s.eclass = ExprClass.Value;
4745 s.Append (rc, left);
4746 s.Append (rc, right);
4750 public override Expression CreateExpressionTree (ResolveContext ec)
4752 Argument arg = arguments [0];
4753 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4757 // Creates nested calls tree from an array of arguments used for IL emit
4759 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4761 Arguments concat_args = new Arguments (2);
4762 Arguments add_args = new Arguments (3);
4764 concat_args.Add (left);
4765 add_args.Add (new Argument (left_etree));
4767 concat_args.Add (arguments [pos]);
4768 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4770 var methods = GetConcatMethodCandidates ();
4771 if (methods == null)
4774 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4775 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4779 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4781 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4782 if (++pos == arguments.Count)
4785 left = new Argument (new EmptyExpression (method.ReturnType));
4786 return CreateExpressionAddCall (ec, left, expr, pos);
4789 protected override Expression DoResolve (ResolveContext ec)
4794 void Append (ResolveContext rc, Expression operand)
4799 StringConstant sc = operand as StringConstant;
4801 if (arguments.Count != 0) {
4802 Argument last_argument = arguments [arguments.Count - 1];
4803 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4804 if (last_expr_constant != null) {
4805 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4811 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4813 StringConcat concat_oper = operand as StringConcat;
4814 if (concat_oper != null) {
4815 arguments.AddRange (concat_oper.arguments);
4820 arguments.Add (new Argument (operand));
4823 IList<MemberSpec> GetConcatMethodCandidates ()
4825 return MemberCache.FindMembers (type, "Concat", true);
4828 public override void Emit (EmitContext ec)
4830 // Optimize by removing any extra null arguments, they are no-op
4831 for (int i = 0; i < arguments.Count; ++i) {
4832 if (arguments[i].Expr is NullConstant)
4833 arguments.RemoveAt (i--);
4836 var members = GetConcatMethodCandidates ();
4837 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4838 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4839 if (method != null) {
4840 var call = new CallEmitter ();
4841 call.EmitPredefined (ec, method, arguments);
4845 public override SLE.Expression MakeExpression (BuilderContext ctx)
4847 if (arguments.Count != 2)
4848 throw new NotImplementedException ("arguments.Count != 2");
4850 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4851 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4856 // User-defined conditional logical operator
4858 public class ConditionalLogicalOperator : UserOperatorCall
4860 readonly bool is_and;
4861 Expression oper_expr;
4863 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4864 : base (oper, arguments, expr_tree, loc)
4866 this.is_and = is_and;
4867 eclass = ExprClass.Unresolved;
4870 protected override Expression DoResolve (ResolveContext ec)
4872 AParametersCollection pd = oper.Parameters;
4873 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4874 ec.Report.Error (217, loc,
4875 "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",
4876 oper.GetSignatureForError ());
4880 Expression left_dup = new EmptyExpression (type);
4881 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4882 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4883 if (op_true == null || op_false == null) {
4884 ec.Report.Error (218, loc,
4885 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4886 type.GetSignatureForError (), oper.GetSignatureForError ());
4890 oper_expr = is_and ? op_false : op_true;
4891 eclass = ExprClass.Value;
4895 public override void Emit (EmitContext ec)
4897 Label end_target = ec.DefineLabel ();
4900 // Emit and duplicate left argument
4902 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
4903 if (right_contains_await) {
4904 arguments[0] = arguments[0].EmitToField (ec, false);
4905 arguments[0].Expr.Emit (ec);
4907 arguments[0].Expr.Emit (ec);
4908 ec.Emit (OpCodes.Dup);
4909 arguments.RemoveAt (0);
4912 oper_expr.EmitBranchable (ec, end_target, true);
4916 if (right_contains_await) {
4918 // Special handling when right expression contains await and left argument
4919 // could not be left on stack before logical branch
4921 Label skip_left_load = ec.DefineLabel ();
4922 ec.Emit (OpCodes.Br_S, skip_left_load);
4923 ec.MarkLabel (end_target);
4924 arguments[0].Expr.Emit (ec);
4925 ec.MarkLabel (skip_left_load);
4927 ec.MarkLabel (end_target);
4932 public class PointerArithmetic : Expression {
4933 Expression left, right;
4937 // We assume that `l' is always a pointer
4939 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4948 public override bool ContainsEmitWithAwait ()
4950 throw new NotImplementedException ();
4953 public override Expression CreateExpressionTree (ResolveContext ec)
4955 Error_PointerInsideExpressionTree (ec);
4959 protected override Expression DoResolve (ResolveContext ec)
4961 eclass = ExprClass.Variable;
4963 var pc = left.Type as PointerContainer;
4964 if (pc != null && pc.Element.Kind == MemberKind.Void) {
4965 Error_VoidPointerOperation (ec);
4972 public override void Emit (EmitContext ec)
4974 TypeSpec op_type = left.Type;
4976 // It must be either array or fixed buffer
4978 if (TypeManager.HasElementType (op_type)) {
4979 element = TypeManager.GetElementType (op_type);
4981 FieldExpr fe = left as FieldExpr;
4983 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
4988 int size = BuiltinTypeSpec.GetSize(element);
4989 TypeSpec rtype = right.Type;
4991 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4993 // handle (pointer - pointer)
4997 ec.Emit (OpCodes.Sub);
5001 ec.Emit (OpCodes.Sizeof, element);
5004 ec.Emit (OpCodes.Div);
5006 ec.Emit (OpCodes.Conv_I8);
5009 // handle + and - on (pointer op int)
5011 Constant left_const = left as Constant;
5012 if (left_const != null) {
5014 // Optimize ((T*)null) pointer operations
5016 if (left_const.IsDefaultValue) {
5017 left = EmptyExpression.Null;
5025 var right_const = right as Constant;
5026 if (right_const != null) {
5028 // Optimize 0-based arithmetic
5030 if (right_const.IsDefaultValue)
5034 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5036 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5038 // TODO: Should be the checks resolve context sensitive?
5039 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5040 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5046 switch (rtype.BuiltinType) {
5047 case BuiltinTypeSpec.Type.SByte:
5048 case BuiltinTypeSpec.Type.Byte:
5049 case BuiltinTypeSpec.Type.Short:
5050 case BuiltinTypeSpec.Type.UShort:
5051 ec.Emit (OpCodes.Conv_I);
5053 case BuiltinTypeSpec.Type.UInt:
5054 ec.Emit (OpCodes.Conv_U);
5058 if (right_const == null && size != 1){
5060 ec.Emit (OpCodes.Sizeof, element);
5063 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5064 ec.Emit (OpCodes.Conv_I8);
5066 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
5069 if (left_const == null) {
5070 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
5071 ec.Emit (OpCodes.Conv_I);
5072 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5073 ec.Emit (OpCodes.Conv_U);
5075 Binary.EmitOperatorOpcode (ec, op, op_type, right);
5082 // A boolean-expression is an expression that yields a result
5085 public class BooleanExpression : ShimExpression
5087 public BooleanExpression (Expression expr)
5090 this.loc = expr.Location;
5093 public override Expression CreateExpressionTree (ResolveContext ec)
5095 // TODO: We should emit IsTrue (v4) instead of direct user operator
5096 // call but that would break csc compatibility
5097 return base.CreateExpressionTree (ec);
5100 protected override Expression DoResolve (ResolveContext ec)
5102 // A boolean-expression is required to be of a type
5103 // that can be implicitly converted to bool or of
5104 // a type that implements operator true
5106 expr = expr.Resolve (ec);
5110 Assign ass = expr as Assign;
5111 if (ass != null && ass.Source is Constant) {
5112 ec.Report.Warning (665, 3, loc,
5113 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
5116 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
5119 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5120 Arguments args = new Arguments (1);
5121 args.Add (new Argument (expr));
5122 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
5125 type = ec.BuiltinTypes.Bool;
5126 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
5127 if (converted != null)
5131 // If no implicit conversion to bool exists, try using `operator true'
5133 converted = GetOperatorTrue (ec, expr, loc);
5134 if (converted == null) {
5135 expr.Error_ValueCannotBeConverted (ec, type, false);
5142 public override object Accept (StructuralVisitor visitor)
5144 return visitor.Visit (this);
5148 public class BooleanExpressionFalse : Unary
5150 public BooleanExpressionFalse (Expression expr)
5151 : base (Operator.LogicalNot, expr, expr.Location)
5155 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
5157 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
5162 /// Implements the ternary conditional operator (?:)
5164 public class Conditional : Expression {
5165 Expression expr, true_expr, false_expr;
5167 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
5170 this.true_expr = true_expr;
5171 this.false_expr = false_expr;
5177 public Expression Expr {
5183 public Expression TrueExpr {
5189 public Expression FalseExpr {
5197 public override bool ContainsEmitWithAwait ()
5199 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
5202 public override Expression CreateExpressionTree (ResolveContext ec)
5204 Arguments args = new Arguments (3);
5205 args.Add (new Argument (expr.CreateExpressionTree (ec)));
5206 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
5207 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
5208 return CreateExpressionFactoryCall (ec, "Condition", args);
5211 protected override Expression DoResolve (ResolveContext ec)
5213 expr = expr.Resolve (ec);
5216 // Unreachable code needs different resolve path. For instance for await
5217 // expression to not generate unreachable resumable statement
5219 Constant c = expr as Constant;
5220 if (c != null && ec.CurrentBranching != null) {
5221 bool unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
5223 if (c.IsDefaultValue) {
5224 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
5225 true_expr = true_expr.Resolve (ec);
5226 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
5228 false_expr = false_expr.Resolve (ec);
5230 true_expr = true_expr.Resolve (ec);
5232 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
5233 false_expr = false_expr.Resolve (ec);
5234 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
5237 true_expr = true_expr.Resolve (ec);
5238 false_expr = false_expr.Resolve (ec);
5241 if (true_expr == null || false_expr == null || expr == null)
5244 eclass = ExprClass.Value;
5245 TypeSpec true_type = true_expr.Type;
5246 TypeSpec false_type = false_expr.Type;
5250 // First, if an implicit conversion exists from true_expr
5251 // to false_expr, then the result type is of type false_expr.Type
5253 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
5254 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
5255 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5257 // Check if both can convert implicitly to each other's type
5261 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5262 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
5264 // LAMESPEC: There seems to be hardcoded promotition to int type when
5265 // both sides are numeric constants and one side is int constant and
5266 // other side is numeric constant convertible to int.
5268 // var res = condition ? (short)1 : 1;
5270 // Type of res is int even if according to the spec the conversion is
5271 // ambiguous because 1 literal can be converted to short.
5273 if (conv_false_expr != null) {
5274 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
5276 conv_false_expr = null;
5277 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
5278 conv_false_expr = null;
5282 if (conv_false_expr != null) {
5283 ec.Report.Error (172, true_expr.Location,
5284 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
5285 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5290 if (true_expr.Type != type)
5291 true_expr = EmptyCast.Create (true_expr, type);
5292 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
5295 ec.Report.Error (173, true_expr.Location,
5296 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
5297 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5303 bool is_false = c.IsDefaultValue;
5306 // Don't issue the warning for constant expressions
5308 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
5309 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location,
5310 "Unreachable expression code detected");
5313 return ReducedExpression.Create (
5314 is_false ? false_expr : true_expr, this,
5315 false_expr is Constant && true_expr is Constant).Resolve (ec);
5321 public override void Emit (EmitContext ec)
5323 Label false_target = ec.DefineLabel ();
5324 Label end_target = ec.DefineLabel ();
5326 expr.EmitBranchable (ec, false_target, false);
5327 true_expr.Emit (ec);
5330 // Verifier doesn't support interface merging. When there are two types on
5331 // the stack without common type hint and the common type is an interface.
5332 // Use temporary local to give verifier hint on what type to unify the stack
5334 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
5335 var temp = ec.GetTemporaryLocal (type);
5336 ec.Emit (OpCodes.Stloc, temp);
5337 ec.Emit (OpCodes.Ldloc, temp);
5338 ec.FreeTemporaryLocal (temp, type);
5341 ec.Emit (OpCodes.Br, end_target);
5342 ec.MarkLabel (false_target);
5343 false_expr.Emit (ec);
5344 ec.MarkLabel (end_target);
5347 protected override void CloneTo (CloneContext clonectx, Expression t)
5349 Conditional target = (Conditional) t;
5351 target.expr = expr.Clone (clonectx);
5352 target.true_expr = true_expr.Clone (clonectx);
5353 target.false_expr = false_expr.Clone (clonectx);
5357 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
5359 LocalTemporary temp;
5362 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
5363 public abstract void SetHasAddressTaken ();
5364 public abstract void VerifyAssigned (ResolveContext rc);
5366 public abstract bool IsLockedByStatement { get; set; }
5368 public abstract bool IsFixed { get; }
5369 public abstract bool IsRef { get; }
5370 public abstract string Name { get; }
5373 // Variable IL data, it has to be protected to encapsulate hoisted variables
5375 protected abstract ILocalVariable Variable { get; }
5378 // Variable flow-analysis data
5380 public abstract VariableInfo VariableInfo { get; }
5383 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5385 HoistedVariable hv = GetHoistedVariable (ec);
5387 hv.AddressOf (ec, mode);
5391 Variable.EmitAddressOf (ec);
5394 public override bool ContainsEmitWithAwait ()
5399 public override Expression CreateExpressionTree (ResolveContext ec)
5401 HoistedVariable hv = GetHoistedVariable (ec);
5403 return hv.CreateExpressionTree ();
5405 Arguments arg = new Arguments (1);
5406 arg.Add (new Argument (this));
5407 return CreateExpressionFactoryCall (ec, "Constant", arg);
5410 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
5412 if (IsLockedByStatement) {
5413 rc.Report.Warning (728, 2, loc,
5414 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
5421 public override void Emit (EmitContext ec)
5426 public override void EmitSideEffect (EmitContext ec)
5432 // This method is used by parameters that are references, that are
5433 // being passed as references: we only want to pass the pointer (that
5434 // is already stored in the parameter, not the address of the pointer,
5435 // and not the value of the variable).
5437 public void EmitLoad (EmitContext ec)
5442 public void Emit (EmitContext ec, bool leave_copy)
5444 HoistedVariable hv = GetHoistedVariable (ec);
5446 hv.Emit (ec, leave_copy);
5454 // If we are a reference, we loaded on the stack a pointer
5455 // Now lets load the real value
5457 ec.EmitLoadFromPtr (type);
5461 ec.Emit (OpCodes.Dup);
5464 temp = new LocalTemporary (Type);
5470 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
5471 bool prepare_for_load)
5473 HoistedVariable hv = GetHoistedVariable (ec);
5475 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
5479 New n_source = source as New;
5480 if (n_source != null) {
5481 if (!n_source.Emit (ec, this)) {
5485 ec.EmitLoadFromPtr (type);
5497 ec.Emit (OpCodes.Dup);
5499 temp = new LocalTemporary (Type);
5505 ec.EmitStoreFromPtr (type);
5507 Variable.EmitAssign (ec);
5515 public override Expression EmitToField (EmitContext ec)
5517 HoistedVariable hv = GetHoistedVariable (ec);
5519 return hv.EmitToField (ec);
5522 return base.EmitToField (ec);
5525 public HoistedVariable GetHoistedVariable (ResolveContext rc)
5527 return GetHoistedVariable (rc.CurrentAnonymousMethod);
5530 public HoistedVariable GetHoistedVariable (EmitContext ec)
5532 return GetHoistedVariable (ec.CurrentAnonymousMethod);
5535 public override string GetSignatureForError ()
5540 public bool IsHoisted {
5541 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
5546 // Resolved reference to a local variable
5548 public class LocalVariableReference : VariableReference
5550 public LocalVariable local_info;
5552 public LocalVariableReference (LocalVariable li, Location l)
5554 this.local_info = li;
5558 public override VariableInfo VariableInfo {
5559 get { return local_info.VariableInfo; }
5562 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5564 return local_info.HoistedVariant;
5570 // A local variable is always fixed
5572 public override bool IsFixed {
5578 public override bool IsLockedByStatement {
5580 return local_info.IsLocked;
5583 local_info.IsLocked = value;
5587 public override bool IsRef {
5588 get { return false; }
5591 public override string Name {
5592 get { return local_info.Name; }
5597 public override void VerifyAssigned (ResolveContext rc)
5599 VariableInfo variable_info = local_info.VariableInfo;
5600 if (variable_info == null)
5603 if (variable_info.IsAssigned (rc))
5606 rc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
5607 variable_info.SetAssigned (rc);
5610 public override void SetHasAddressTaken ()
5612 local_info.SetHasAddressTaken ();
5615 void DoResolveBase (ResolveContext ec)
5618 // If we are referencing a variable from the external block
5619 // flag it for capturing
5621 if (ec.MustCaptureVariable (local_info)) {
5622 if (local_info.AddressTaken) {
5623 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5624 } else if (local_info.IsFixed) {
5625 ec.Report.Error (1764, loc,
5626 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
5627 GetSignatureForError ());
5630 if (ec.IsVariableCapturingRequired) {
5631 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
5632 storey.CaptureLocalVariable (ec, local_info);
5636 eclass = ExprClass.Variable;
5637 type = local_info.Type;
5640 protected override Expression DoResolve (ResolveContext ec)
5642 local_info.SetIsUsed ();
5644 VerifyAssigned (ec);
5650 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5653 // Don't be too pedantic when variable is used as out param or for some broken code
5654 // which uses property/indexer access to run some initialization
5656 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5657 local_info.SetIsUsed ();
5659 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5662 if (rhs == EmptyExpression.OutAccess) {
5663 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5664 } else if (rhs == EmptyExpression.LValueMemberAccess) {
5665 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
5666 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5667 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5668 } else if (rhs == EmptyExpression.UnaryAddress) {
5669 code = 459; msg = "Cannot take the address of {1} `{0}'";
5671 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5673 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5674 } else if (VariableInfo != null) {
5675 VariableInfo.SetAssigned (ec);
5678 if (eclass == ExprClass.Unresolved)
5681 return base.DoResolveLValue (ec, rhs);
5684 public override int GetHashCode ()
5686 return local_info.GetHashCode ();
5689 public override bool Equals (object obj)
5691 LocalVariableReference lvr = obj as LocalVariableReference;
5695 return local_info == lvr.local_info;
5698 protected override ILocalVariable Variable {
5699 get { return local_info; }
5702 public override string ToString ()
5704 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5707 protected override void CloneTo (CloneContext clonectx, Expression t)
5714 /// This represents a reference to a parameter in the intermediate
5717 public class ParameterReference : VariableReference
5719 protected ParametersBlock.ParameterInfo pi;
5721 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5729 public override bool IsLockedByStatement {
5734 pi.IsLocked = value;
5738 public override bool IsRef {
5739 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5742 bool HasOutModifier {
5743 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5746 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5748 return pi.Parameter.HoistedVariant;
5752 // A ref or out parameter is classified as a moveable variable, even
5753 // if the argument given for the parameter is a fixed variable
5755 public override bool IsFixed {
5756 get { return !IsRef; }
5759 public override string Name {
5760 get { return Parameter.Name; }
5763 public Parameter Parameter {
5764 get { return pi.Parameter; }
5767 public override VariableInfo VariableInfo {
5768 get { return pi.VariableInfo; }
5771 protected override ILocalVariable Variable {
5772 get { return Parameter; }
5777 public override void AddressOf (EmitContext ec, AddressOp mode)
5780 // ParameterReferences might already be a reference
5787 base.AddressOf (ec, mode);
5790 public override void SetHasAddressTaken ()
5792 Parameter.HasAddressTaken = true;
5795 void SetAssigned (ResolveContext ec)
5797 if (Parameter.HoistedVariant != null)
5798 Parameter.HoistedVariant.IsAssigned = true;
5800 if (HasOutModifier && ec.DoFlowAnalysis)
5801 ec.CurrentBranching.SetAssigned (VariableInfo);
5804 bool DoResolveBase (ResolveContext ec)
5806 if (eclass != ExprClass.Unresolved)
5809 type = pi.ParameterType;
5810 eclass = ExprClass.Variable;
5813 // If we are referencing a parameter from the external block
5814 // flag it for capturing
5816 if (ec.MustCaptureVariable (pi)) {
5817 if (Parameter.HasAddressTaken)
5818 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5821 ec.Report.Error (1628, loc,
5822 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5823 Name, ec.CurrentAnonymousMethod.ContainerType);
5826 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5827 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5828 storey.CaptureParameter (ec, pi, this);
5835 public override int GetHashCode ()
5837 return Name.GetHashCode ();
5840 public override bool Equals (object obj)
5842 ParameterReference pr = obj as ParameterReference;
5846 return Name == pr.Name;
5849 protected override void CloneTo (CloneContext clonectx, Expression target)
5855 public override Expression CreateExpressionTree (ResolveContext ec)
5857 HoistedVariable hv = GetHoistedVariable (ec);
5859 return hv.CreateExpressionTree ();
5861 return Parameter.ExpressionTreeVariableReference ();
5865 // Notice that for ref/out parameters, the type exposed is not the
5866 // same type exposed externally.
5869 // externally we expose "int&"
5870 // here we expose "int".
5872 // We record this in "is_ref". This means that the type system can treat
5873 // the type as it is expected, but when we generate the code, we generate
5874 // the alternate kind of code.
5876 protected override Expression DoResolve (ResolveContext ec)
5878 if (!DoResolveBase (ec))
5881 VerifyAssigned (ec);
5885 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5887 if (!DoResolveBase (ec))
5891 return base.DoResolveLValue (ec, right_side);
5894 public override void VerifyAssigned (ResolveContext rc)
5896 // HACK: Variables are not captured in probing mode
5897 if (rc.IsInProbingMode)
5900 if (HasOutModifier && !VariableInfo.IsAssigned (rc)) {
5901 rc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
5907 /// Invocation of methods or delegates.
5909 public class Invocation : ExpressionStatement
5911 protected Arguments arguments;
5912 protected Expression expr;
5913 protected MethodGroupExpr mg;
5915 public Invocation (Expression expr, Arguments arguments)
5918 this.arguments = arguments;
5920 loc = expr.Location;
5925 public Arguments Arguments {
5931 public Expression Exp {
5937 public MethodGroupExpr MethodGroup {
5943 public override Location StartLocation {
5945 return expr.StartLocation;
5951 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
5953 if (MethodGroup == null)
5956 var candidate = MethodGroup.BestCandidate;
5957 if (candidate == null || !(candidate.IsStatic || Exp is This))
5960 var args_count = arguments == null ? 0 : arguments.Count;
5961 if (args_count != body.Parameters.Count)
5964 var lambda_parameters = body.Block.Parameters.FixedParameters;
5965 for (int i = 0; i < args_count; ++i) {
5966 var pr = arguments[i].Expr as ParameterReference;
5970 if (lambda_parameters[i] != pr.Parameter)
5973 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
5977 var emg = MethodGroup as ExtensionMethodGroupExpr;
5979 return MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
5985 protected override void CloneTo (CloneContext clonectx, Expression t)
5987 Invocation target = (Invocation) t;
5989 if (arguments != null)
5990 target.arguments = arguments.Clone (clonectx);
5992 target.expr = expr.Clone (clonectx);
5995 public override bool ContainsEmitWithAwait ()
5997 if (arguments != null && arguments.ContainsEmitWithAwait ())
6000 return mg.ContainsEmitWithAwait ();
6003 public override Expression CreateExpressionTree (ResolveContext ec)
6005 Expression instance = mg.IsInstance ?
6006 mg.InstanceExpression.CreateExpressionTree (ec) :
6007 new NullLiteral (loc);
6009 var args = Arguments.CreateForExpressionTree (ec, arguments,
6011 mg.CreateExpressionTree (ec));
6013 return CreateExpressionFactoryCall (ec, "Call", args);
6016 protected override Expression DoResolve (ResolveContext ec)
6018 Expression member_expr;
6019 var atn = expr as ATypeNameExpression;
6021 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
6022 if (member_expr != null)
6023 member_expr = member_expr.Resolve (ec);
6025 member_expr = expr.Resolve (ec);
6028 if (member_expr == null)
6032 // Next, evaluate all the expressions in the argument list
6034 bool dynamic_arg = false;
6035 if (arguments != null)
6036 arguments.Resolve (ec, out dynamic_arg);
6038 TypeSpec expr_type = member_expr.Type;
6039 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6040 return DoResolveDynamic (ec, member_expr);
6042 mg = member_expr as MethodGroupExpr;
6043 Expression invoke = null;
6046 if (expr_type != null && expr_type.IsDelegate) {
6047 invoke = new DelegateInvocation (member_expr, arguments, loc);
6048 invoke = invoke.Resolve (ec);
6049 if (invoke == null || !dynamic_arg)
6052 if (member_expr is RuntimeValueExpression) {
6053 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
6054 member_expr.Type.GetSignatureForError ()); ;
6058 MemberExpr me = member_expr as MemberExpr;
6060 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
6064 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
6065 member_expr.GetSignatureForError ());
6070 if (invoke == null) {
6071 mg = DoResolveOverload (ec);
6077 return DoResolveDynamic (ec, member_expr);
6079 var method = mg.BestCandidate;
6080 type = mg.BestCandidateReturnType;
6082 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
6084 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
6086 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
6090 IsSpecialMethodInvocation (ec, method, loc);
6092 eclass = ExprClass.Value;
6096 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
6099 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
6101 args = dmb.Arguments;
6102 if (arguments != null)
6103 args.AddRange (arguments);
6104 } else if (mg == null) {
6105 if (arguments == null)
6106 args = new Arguments (1);
6110 args.Insert (0, new Argument (memberExpr));
6114 ec.Report.Error (1971, loc,
6115 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
6120 if (arguments == null)
6121 args = new Arguments (1);
6125 MemberAccess ma = expr as MemberAccess;
6127 var left_type = ma.LeftExpression as TypeExpr;
6128 if (left_type != null) {
6129 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6132 // Any value type has to be pass as by-ref to get back the same
6133 // instance on which the member was called
6135 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
6136 Argument.AType.Ref : Argument.AType.None;
6137 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
6139 } else { // is SimpleName
6141 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6143 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
6148 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
6151 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
6153 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
6156 public override string GetSignatureForError ()
6158 return mg.GetSignatureForError ();
6162 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
6163 // or the type dynamic, then the member is invocable
6165 public static bool IsMemberInvocable (MemberSpec member)
6167 switch (member.Kind) {
6168 case MemberKind.Event:
6170 case MemberKind.Field:
6171 case MemberKind.Property:
6172 var m = member as IInterfaceMemberSpec;
6173 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
6179 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
6181 if (!method.IsReservedMethod)
6184 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
6187 ec.Report.SymbolRelatedToPreviousError (method);
6188 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
6189 method.GetSignatureForError ());
6194 public override void Emit (EmitContext ec)
6196 mg.EmitCall (ec, arguments);
6199 public override void EmitStatement (EmitContext ec)
6204 // Pop the return value if there is one
6206 if (type.Kind != MemberKind.Void)
6207 ec.Emit (OpCodes.Pop);
6210 public override SLE.Expression MakeExpression (BuilderContext ctx)
6212 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
6215 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
6218 throw new NotSupportedException ();
6220 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
6221 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
6225 public override object Accept (StructuralVisitor visitor)
6227 return visitor.Visit (this);
6232 // Implements simple new expression
6234 public class New : ExpressionStatement, IMemoryLocation
6236 protected Arguments arguments;
6239 // During bootstrap, it contains the RequestedType,
6240 // but if `type' is not null, it *might* contain a NewDelegate
6241 // (because of field multi-initialization)
6243 protected Expression RequestedType;
6245 protected MethodSpec method;
6247 public New (Expression requested_type, Arguments arguments, Location l)
6249 RequestedType = requested_type;
6250 this.arguments = arguments;
6255 public Arguments Arguments {
6262 // Returns true for resolved `new S()'
6264 public bool IsDefaultStruct {
6266 return arguments == null && type.IsStruct && GetType () == typeof (New);
6270 public Expression TypeExpression {
6272 return RequestedType;
6279 /// Converts complex core type syntax like 'new int ()' to simple constant
6281 public static Constant Constantify (TypeSpec t, Location loc)
6283 switch (t.BuiltinType) {
6284 case BuiltinTypeSpec.Type.Int:
6285 return new IntConstant (t, 0, loc);
6286 case BuiltinTypeSpec.Type.UInt:
6287 return new UIntConstant (t, 0, loc);
6288 case BuiltinTypeSpec.Type.Long:
6289 return new LongConstant (t, 0, loc);
6290 case BuiltinTypeSpec.Type.ULong:
6291 return new ULongConstant (t, 0, loc);
6292 case BuiltinTypeSpec.Type.Float:
6293 return new FloatConstant (t, 0, loc);
6294 case BuiltinTypeSpec.Type.Double:
6295 return new DoubleConstant (t, 0, loc);
6296 case BuiltinTypeSpec.Type.Short:
6297 return new ShortConstant (t, 0, loc);
6298 case BuiltinTypeSpec.Type.UShort:
6299 return new UShortConstant (t, 0, loc);
6300 case BuiltinTypeSpec.Type.SByte:
6301 return new SByteConstant (t, 0, loc);
6302 case BuiltinTypeSpec.Type.Byte:
6303 return new ByteConstant (t, 0, loc);
6304 case BuiltinTypeSpec.Type.Char:
6305 return new CharConstant (t, '\0', loc);
6306 case BuiltinTypeSpec.Type.Bool:
6307 return new BoolConstant (t, false, loc);
6308 case BuiltinTypeSpec.Type.Decimal:
6309 return new DecimalConstant (t, 0, loc);
6313 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
6315 if (t.IsNullableType)
6316 return Nullable.LiftedNull.Create (t, loc);
6321 public override bool ContainsEmitWithAwait ()
6323 return arguments != null && arguments.ContainsEmitWithAwait ();
6327 // Checks whether the type is an interface that has the
6328 // [ComImport, CoClass] attributes and must be treated
6331 public Expression CheckComImport (ResolveContext ec)
6333 if (!type.IsInterface)
6337 // Turn the call into:
6338 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
6340 var real_class = type.MemberDefinition.GetAttributeCoClass ();
6341 if (real_class == null)
6344 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
6345 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
6346 return cast.Resolve (ec);
6349 public override Expression CreateExpressionTree (ResolveContext ec)
6352 if (method == null) {
6353 args = new Arguments (1);
6354 args.Add (new Argument (new TypeOf (type, loc)));
6356 args = Arguments.CreateForExpressionTree (ec,
6357 arguments, new TypeOfMethod (method, loc));
6360 return CreateExpressionFactoryCall (ec, "New", args);
6363 protected override Expression DoResolve (ResolveContext ec)
6365 type = RequestedType.ResolveAsType (ec);
6369 eclass = ExprClass.Value;
6371 if (type.IsPointer) {
6372 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
6373 type.GetSignatureForError ());
6377 if (arguments == null) {
6378 Constant c = Constantify (type, RequestedType.Location);
6380 return ReducedExpression.Create (c, this);
6383 if (type.IsDelegate) {
6384 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
6387 var tparam = type as TypeParameterSpec;
6388 if (tparam != null) {
6390 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
6391 // where type parameter constraint is inflated to struct
6393 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
6394 ec.Report.Error (304, loc,
6395 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
6396 type.GetSignatureForError ());
6399 if ((arguments != null) && (arguments.Count != 0)) {
6400 ec.Report.Error (417, loc,
6401 "`{0}': cannot provide arguments when creating an instance of a variable type",
6402 type.GetSignatureForError ());
6408 if (type.IsStatic) {
6409 ec.Report.SymbolRelatedToPreviousError (type);
6410 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
6414 if (type.IsInterface || type.IsAbstract){
6415 if (!TypeManager.IsGenericType (type)) {
6416 RequestedType = CheckComImport (ec);
6417 if (RequestedType != null)
6418 return RequestedType;
6421 ec.Report.SymbolRelatedToPreviousError (type);
6422 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
6427 // Any struct always defines parameterless constructor
6429 if (type.IsStruct && arguments == null)
6433 if (arguments != null) {
6434 arguments.Resolve (ec, out dynamic);
6439 method = ConstructorLookup (ec, type, ref arguments, loc);
6442 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6443 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
6449 bool DoEmitTypeParameter (EmitContext ec)
6451 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
6455 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
6456 var tparam = (TypeParameterSpec) type;
6458 if (tparam.IsReferenceType) {
6459 ec.Emit (OpCodes.Call, ctor_factory);
6463 // Allow DoEmit() to be called multiple times.
6464 // We need to create a new LocalTemporary each time since
6465 // you can't share LocalBuilders among ILGeneators.
6466 LocalTemporary temp = new LocalTemporary (type);
6468 Label label_activator = ec.DefineLabel ();
6469 Label label_end = ec.DefineLabel ();
6471 temp.AddressOf (ec, AddressOp.Store);
6472 ec.Emit (OpCodes.Initobj, type);
6475 ec.Emit (OpCodes.Box, type);
6476 ec.Emit (OpCodes.Brfalse, label_activator);
6478 temp.AddressOf (ec, AddressOp.Store);
6479 ec.Emit (OpCodes.Initobj, type);
6482 ec.Emit (OpCodes.Br_S, label_end);
6484 ec.MarkLabel (label_activator);
6486 ec.Emit (OpCodes.Call, ctor_factory);
6487 ec.MarkLabel (label_end);
6492 // This Emit can be invoked in two contexts:
6493 // * As a mechanism that will leave a value on the stack (new object)
6494 // * As one that wont (init struct)
6496 // If we are dealing with a ValueType, we have a few
6497 // situations to deal with:
6499 // * The target is a ValueType, and we have been provided
6500 // the instance (this is easy, we are being assigned).
6502 // * The target of New is being passed as an argument,
6503 // to a boxing operation or a function that takes a
6506 // In this case, we need to create a temporary variable
6507 // that is the argument of New.
6509 // Returns whether a value is left on the stack
6511 // *** Implementation note ***
6513 // To benefit from this optimization, each assignable expression
6514 // has to manually cast to New and call this Emit.
6516 // TODO: It's worth to implement it for arrays and fields
6518 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
6520 bool is_value_type = TypeSpec.IsValueType (type);
6521 VariableReference vr = target as VariableReference;
6523 if (target != null && is_value_type && (vr != null || method == null)) {
6524 target.AddressOf (ec, AddressOp.Store);
6525 } else if (vr != null && vr.IsRef) {
6529 if (arguments != null) {
6530 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
6531 arguments = arguments.Emit (ec, false, true);
6533 arguments.Emit (ec);
6536 if (is_value_type) {
6537 if (method == null) {
6538 ec.Emit (OpCodes.Initobj, type);
6543 ec.MarkCallEntry (loc);
6544 ec.Emit (OpCodes.Call, method);
6549 if (type is TypeParameterSpec)
6550 return DoEmitTypeParameter (ec);
6552 ec.MarkCallEntry (loc);
6553 ec.Emit (OpCodes.Newobj, method);
6557 public override void Emit (EmitContext ec)
6559 LocalTemporary v = null;
6560 if (method == null && TypeSpec.IsValueType (type)) {
6561 // TODO: Use temporary variable from pool
6562 v = new LocalTemporary (type);
6569 public override void EmitStatement (EmitContext ec)
6571 LocalTemporary v = null;
6572 if (method == null && TypeSpec.IsValueType (type)) {
6573 // TODO: Use temporary variable from pool
6574 v = new LocalTemporary (type);
6578 ec.Emit (OpCodes.Pop);
6581 public void AddressOf (EmitContext ec, AddressOp mode)
6583 EmitAddressOf (ec, mode);
6586 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
6588 LocalTemporary value_target = new LocalTemporary (type);
6590 if (type is TypeParameterSpec) {
6591 DoEmitTypeParameter (ec);
6592 value_target.Store (ec);
6593 value_target.AddressOf (ec, mode);
6594 return value_target;
6597 value_target.AddressOf (ec, AddressOp.Store);
6599 if (method == null) {
6600 ec.Emit (OpCodes.Initobj, type);
6602 if (arguments != null)
6603 arguments.Emit (ec);
6605 ec.Emit (OpCodes.Call, method);
6608 value_target.AddressOf (ec, mode);
6609 return value_target;
6612 protected override void CloneTo (CloneContext clonectx, Expression t)
6614 New target = (New) t;
6616 target.RequestedType = RequestedType.Clone (clonectx);
6617 if (arguments != null){
6618 target.arguments = arguments.Clone (clonectx);
6622 public override SLE.Expression MakeExpression (BuilderContext ctx)
6625 return base.MakeExpression (ctx);
6627 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
6631 public override object Accept (StructuralVisitor visitor)
6633 return visitor.Visit (this);
6638 // Array initializer expression, the expression is allowed in
6639 // variable or field initialization only which makes it tricky as
6640 // the type has to be infered based on the context either from field
6641 // type or variable type (think of multiple declarators)
6643 public class ArrayInitializer : Expression
6645 List<Expression> elements;
6646 BlockVariable variable;
6648 public ArrayInitializer (List<Expression> init, Location loc)
6654 public ArrayInitializer (int count, Location loc)
6655 : this (new List<Expression> (count), loc)
6659 public ArrayInitializer (Location loc)
6667 get { return elements.Count; }
6670 public List<Expression> Elements {
6676 public Expression this [int index] {
6678 return elements [index];
6682 public BlockVariable VariableDeclaration {
6693 public void Add (Expression expr)
6695 elements.Add (expr);
6698 public override bool ContainsEmitWithAwait ()
6700 throw new NotSupportedException ();
6703 public override Expression CreateExpressionTree (ResolveContext ec)
6705 throw new NotSupportedException ("ET");
6708 protected override void CloneTo (CloneContext clonectx, Expression t)
6710 var target = (ArrayInitializer) t;
6712 target.elements = new List<Expression> (elements.Count);
6713 foreach (var element in elements)
6714 target.elements.Add (element.Clone (clonectx));
6717 protected override Expression DoResolve (ResolveContext rc)
6719 var current_field = rc.CurrentMemberDefinition as FieldBase;
6720 TypeExpression type;
6721 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6722 type = new TypeExpression (current_field.MemberType, current_field.Location);
6723 } else if (variable != null) {
6724 if (variable.TypeExpression is VarExpr) {
6725 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6726 return EmptyExpression.Null;
6729 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6731 throw new NotImplementedException ("Unexpected array initializer context");
6734 return new ArrayCreation (type, this).Resolve (rc);
6737 public override void Emit (EmitContext ec)
6739 throw new InternalErrorException ("Missing Resolve call");
6742 public override object Accept (StructuralVisitor visitor)
6744 return visitor.Visit (this);
6749 /// 14.5.10.2: Represents an array creation expression.
6753 /// There are two possible scenarios here: one is an array creation
6754 /// expression that specifies the dimensions and optionally the
6755 /// initialization data and the other which does not need dimensions
6756 /// specified but where initialization data is mandatory.
6758 public class ArrayCreation : Expression
6760 FullNamedExpression requested_base_type;
6761 ArrayInitializer initializers;
6764 // The list of Argument types.
6765 // This is used to construct the `newarray' or constructor signature
6767 protected List<Expression> arguments;
6769 protected TypeSpec array_element_type;
6770 int num_arguments = 0;
6771 protected int dimensions;
6772 protected readonly ComposedTypeSpecifier rank;
6773 Expression first_emit;
6774 LocalTemporary first_emit_temp;
6776 protected List<Expression> array_data;
6778 Dictionary<int, int> bounds;
6781 // The number of constants in array initializers
6782 int const_initializers_count;
6783 bool only_constant_initializers;
6785 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6786 : this (requested_base_type, rank, initializers, l)
6788 arguments = new List<Expression> (exprs);
6789 num_arguments = arguments.Count;
6793 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6795 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6797 this.requested_base_type = requested_base_type;
6799 this.initializers = initializers;
6803 num_arguments = rank.Dimension;
6807 // For compiler generated single dimensional arrays only
6809 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6810 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6815 // For expressions like int[] foo = { 1, 2, 3 };
6817 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6818 : this (requested_base_type, null, initializers, initializers.Location)
6822 public ComposedTypeSpecifier Rank {
6828 public FullNamedExpression TypeExpression {
6830 return this.requested_base_type;
6834 public ArrayInitializer Initializers {
6836 return this.initializers;
6840 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6842 if (initializers != null && bounds == null) {
6844 // We use this to store all the data values in the order in which we
6845 // will need to store them in the byte blob later
6847 array_data = new List<Expression> (probe.Count);
6848 bounds = new Dictionary<int, int> ();
6851 if (specified_dims) {
6852 Expression a = arguments [idx];
6857 a = ConvertExpressionToArrayIndex (ec, a);
6863 if (initializers != null) {
6864 Constant c = a as Constant;
6865 if (c == null && a is ArrayIndexCast)
6866 c = ((ArrayIndexCast) a).Child as Constant;
6869 ec.Report.Error (150, a.Location, "A constant value is expected");
6875 value = System.Convert.ToInt32 (c.GetValue ());
6877 ec.Report.Error (150, a.Location, "A constant value is expected");
6881 // TODO: probe.Count does not fit ulong in
6882 if (value != probe.Count) {
6883 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6887 bounds[idx] = value;
6891 if (initializers == null)
6894 for (int i = 0; i < probe.Count; ++i) {
6896 if (o is ArrayInitializer) {
6897 var sub_probe = o as ArrayInitializer;
6898 if (idx + 1 >= dimensions){
6899 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6903 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
6904 if (!bounds.ContainsKey(idx + 1))
6905 bounds[idx + 1] = sub_probe.Count;
6907 if (bounds[idx + 1] != sub_probe.Count) {
6908 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
6912 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6915 } else if (child_bounds > 1) {
6916 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6918 Expression element = ResolveArrayElement (ec, o);
6919 if (element == null)
6922 // Initializers with the default values can be ignored
6923 Constant c = element as Constant;
6925 if (!c.IsDefaultInitializer (array_element_type)) {
6926 ++const_initializers_count;
6929 only_constant_initializers = false;
6932 array_data.Add (element);
6939 public override bool ContainsEmitWithAwait ()
6941 foreach (var arg in arguments) {
6942 if (arg.ContainsEmitWithAwait ())
6946 return InitializersContainAwait ();
6949 public override Expression CreateExpressionTree (ResolveContext ec)
6953 if (array_data == null) {
6954 args = new Arguments (arguments.Count + 1);
6955 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6956 foreach (Expression a in arguments)
6957 args.Add (new Argument (a.CreateExpressionTree (ec)));
6959 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6962 if (dimensions > 1) {
6963 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6967 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6968 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6969 if (array_data != null) {
6970 for (int i = 0; i < array_data.Count; ++i) {
6971 Expression e = array_data [i];
6972 args.Add (new Argument (e.CreateExpressionTree (ec)));
6976 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6979 void UpdateIndices (ResolveContext rc)
6982 for (var probe = initializers; probe != null;) {
6983 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
6985 bounds[i++] = probe.Count;
6987 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
6988 probe = (ArrayInitializer) probe[0];
6989 } else if (dimensions > i) {
6997 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
6999 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
7002 bool InitializersContainAwait ()
7004 if (array_data == null)
7007 foreach (var expr in array_data) {
7008 if (expr.ContainsEmitWithAwait ())
7015 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
7017 element = element.Resolve (ec);
7018 if (element == null)
7021 if (element is CompoundAssign.TargetExpression) {
7022 if (first_emit != null)
7023 throw new InternalErrorException ("Can only handle one mutator at a time");
7024 first_emit = element;
7025 element = first_emit_temp = new LocalTemporary (element.Type);
7028 return Convert.ImplicitConversionRequired (
7029 ec, element, array_element_type, loc);
7032 protected bool ResolveInitializers (ResolveContext ec)
7035 only_constant_initializers = true;
7038 if (arguments != null) {
7040 for (int i = 0; i < arguments.Count; ++i) {
7041 res &= CheckIndices (ec, initializers, i, true, dimensions);
7042 if (initializers != null)
7049 arguments = new List<Expression> ();
7051 if (!CheckIndices (ec, initializers, 0, false, dimensions))
7060 // Resolved the type of the array
7062 bool ResolveArrayType (ResolveContext ec)
7067 FullNamedExpression array_type_expr;
7068 if (num_arguments > 0) {
7069 array_type_expr = new ComposedCast (requested_base_type, rank);
7071 array_type_expr = requested_base_type;
7074 type = array_type_expr.ResolveAsType (ec);
7075 if (array_type_expr == null)
7078 var ac = type as ArrayContainer;
7080 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
7084 array_element_type = ac.Element;
7085 dimensions = ac.Rank;
7090 protected override Expression DoResolve (ResolveContext ec)
7095 if (!ResolveArrayType (ec))
7099 // validate the initializers and fill in any missing bits
7101 if (!ResolveInitializers (ec))
7104 eclass = ExprClass.Value;
7108 byte [] MakeByteBlob ()
7113 int count = array_data.Count;
7115 TypeSpec element_type = array_element_type;
7116 if (element_type.IsEnum)
7117 element_type = EnumSpec.GetUnderlyingType (element_type);
7119 factor = BuiltinTypeSpec.GetSize (element_type);
7121 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
7123 data = new byte [(count * factor + 3) & ~3];
7126 for (int i = 0; i < count; ++i) {
7127 var c = array_data[i] as Constant;
7133 object v = c.GetValue ();
7135 switch (element_type.BuiltinType) {
7136 case BuiltinTypeSpec.Type.Long:
7137 long lval = (long) v;
7139 for (int j = 0; j < factor; ++j) {
7140 data[idx + j] = (byte) (lval & 0xFF);
7144 case BuiltinTypeSpec.Type.ULong:
7145 ulong ulval = (ulong) v;
7147 for (int j = 0; j < factor; ++j) {
7148 data[idx + j] = (byte) (ulval & 0xFF);
7149 ulval = (ulval >> 8);
7152 case BuiltinTypeSpec.Type.Float:
7153 var fval = SingleConverter.SingleToInt32Bits((float) v);
7155 data[idx] = (byte) (fval & 0xff);
7156 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
7157 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
7158 data[idx + 3] = (byte) (fval >> 24);
7160 case BuiltinTypeSpec.Type.Double:
7161 element = BitConverter.GetBytes ((double) v);
7163 for (int j = 0; j < factor; ++j)
7164 data[idx + j] = element[j];
7166 // FIXME: Handle the ARM float format.
7167 if (!BitConverter.IsLittleEndian)
7168 System.Array.Reverse (data, idx, 8);
7170 case BuiltinTypeSpec.Type.Char:
7171 int chval = (int) ((char) v);
7173 data[idx] = (byte) (chval & 0xff);
7174 data[idx + 1] = (byte) (chval >> 8);
7176 case BuiltinTypeSpec.Type.Short:
7177 int sval = (int) ((short) v);
7179 data[idx] = (byte) (sval & 0xff);
7180 data[idx + 1] = (byte) (sval >> 8);
7182 case BuiltinTypeSpec.Type.UShort:
7183 int usval = (int) ((ushort) v);
7185 data[idx] = (byte) (usval & 0xff);
7186 data[idx + 1] = (byte) (usval >> 8);
7188 case BuiltinTypeSpec.Type.Int:
7191 data[idx] = (byte) (val & 0xff);
7192 data[idx + 1] = (byte) ((val >> 8) & 0xff);
7193 data[idx + 2] = (byte) ((val >> 16) & 0xff);
7194 data[idx + 3] = (byte) (val >> 24);
7196 case BuiltinTypeSpec.Type.UInt:
7197 uint uval = (uint) v;
7199 data[idx] = (byte) (uval & 0xff);
7200 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
7201 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
7202 data[idx + 3] = (byte) (uval >> 24);
7204 case BuiltinTypeSpec.Type.SByte:
7205 data[idx] = (byte) (sbyte) v;
7207 case BuiltinTypeSpec.Type.Byte:
7208 data[idx] = (byte) v;
7210 case BuiltinTypeSpec.Type.Bool:
7211 data[idx] = (byte) ((bool) v ? 1 : 0);
7213 case BuiltinTypeSpec.Type.Decimal:
7214 int[] bits = Decimal.GetBits ((decimal) v);
7217 // FIXME: For some reason, this doesn't work on the MS runtime.
7218 int[] nbits = new int[4];
7224 for (int j = 0; j < 4; j++) {
7225 data[p++] = (byte) (nbits[j] & 0xff);
7226 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
7227 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
7228 data[p++] = (byte) (nbits[j] >> 24);
7232 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
7241 #if NET_4_0 || MONODROID
7242 public override SLE.Expression MakeExpression (BuilderContext ctx)
7245 return base.MakeExpression (ctx);
7247 var initializers = new SLE.Expression [array_data.Count];
7248 for (var i = 0; i < initializers.Length; i++) {
7249 if (array_data [i] == null)
7250 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
7252 initializers [i] = array_data [i].MakeExpression (ctx);
7255 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
7261 // Emits the initializers for the array
7263 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
7265 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
7270 // First, the static data
7272 byte [] data = MakeByteBlob ();
7273 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
7275 if (stackArray == null) {
7276 ec.Emit (OpCodes.Dup);
7278 stackArray.Emit (ec);
7281 ec.Emit (OpCodes.Ldtoken, fb);
7282 ec.Emit (OpCodes.Call, m);
7287 // Emits pieces of the array that can not be computed at compile
7288 // time (variables and string locations).
7290 // This always expect the top value on the stack to be the array
7292 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
7294 int dims = bounds.Count;
7295 var current_pos = new int [dims];
7297 for (int i = 0; i < array_data.Count; i++){
7299 Expression e = array_data [i];
7300 var c = e as Constant;
7302 // Constant can be initialized via StaticInitializer
7303 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
7307 if (stackArray != null) {
7308 if (e.ContainsEmitWithAwait ()) {
7309 e = e.EmitToField (ec);
7312 stackArray.Emit (ec);
7314 ec.Emit (OpCodes.Dup);
7317 for (int idx = 0; idx < dims; idx++)
7318 ec.EmitInt (current_pos [idx]);
7321 // If we are dealing with a struct, get the
7322 // address of it, so we can store it.
7324 if (dims == 1 && etype.IsStruct) {
7325 switch (etype.BuiltinType) {
7326 case BuiltinTypeSpec.Type.Byte:
7327 case BuiltinTypeSpec.Type.SByte:
7328 case BuiltinTypeSpec.Type.Bool:
7329 case BuiltinTypeSpec.Type.Short:
7330 case BuiltinTypeSpec.Type.UShort:
7331 case BuiltinTypeSpec.Type.Char:
7332 case BuiltinTypeSpec.Type.Int:
7333 case BuiltinTypeSpec.Type.UInt:
7334 case BuiltinTypeSpec.Type.Long:
7335 case BuiltinTypeSpec.Type.ULong:
7336 case BuiltinTypeSpec.Type.Float:
7337 case BuiltinTypeSpec.Type.Double:
7340 ec.Emit (OpCodes.Ldelema, etype);
7347 ec.EmitArrayStore ((ArrayContainer) type);
7353 for (int j = dims - 1; j >= 0; j--){
7355 if (current_pos [j] < bounds [j])
7357 current_pos [j] = 0;
7362 public override void Emit (EmitContext ec)
7364 EmitToFieldSource (ec);
7367 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
7369 if (first_emit != null) {
7370 first_emit.Emit (ec);
7371 first_emit_temp.Store (ec);
7374 FieldExpr await_stack_field;
7375 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
7376 await_stack_field = ec.GetTemporaryField (type);
7379 await_stack_field = null;
7382 EmitExpressionsList (ec, arguments);
7384 ec.EmitArrayNew ((ArrayContainer) type);
7386 if (initializers == null)
7387 return await_stack_field;
7389 if (await_stack_field != null)
7390 await_stack_field.EmitAssignFromStack (ec);
7394 // Emit static initializer for arrays which contain more than 2 items and
7395 // the static initializer will initialize at least 25% of array values or there
7396 // is more than 10 items to be initialized
7398 // NOTE: const_initializers_count does not contain default constant values.
7400 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
7401 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
7402 EmitStaticInitializers (ec, await_stack_field);
7404 if (!only_constant_initializers)
7405 EmitDynamicInitializers (ec, false, await_stack_field);
7409 EmitDynamicInitializers (ec, true, await_stack_field);
7412 if (first_emit_temp != null)
7413 first_emit_temp.Release (ec);
7415 return await_stack_field;
7418 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7420 // no multi dimensional or jagged arrays
7421 if (arguments.Count != 1 || array_element_type.IsArray) {
7422 base.EncodeAttributeValue (rc, enc, targetType);
7426 // No array covariance, except for array -> object
7427 if (type != targetType) {
7428 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
7429 base.EncodeAttributeValue (rc, enc, targetType);
7433 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
7434 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7439 // Single dimensional array of 0 size
7440 if (array_data == null) {
7441 IntConstant ic = arguments[0] as IntConstant;
7442 if (ic == null || !ic.IsDefaultValue) {
7443 base.EncodeAttributeValue (rc, enc, targetType);
7451 enc.Encode (array_data.Count);
7452 foreach (var element in array_data) {
7453 element.EncodeAttributeValue (rc, enc, array_element_type);
7457 protected override void CloneTo (CloneContext clonectx, Expression t)
7459 ArrayCreation target = (ArrayCreation) t;
7461 if (requested_base_type != null)
7462 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
7464 if (arguments != null){
7465 target.arguments = new List<Expression> (arguments.Count);
7466 foreach (Expression e in arguments)
7467 target.arguments.Add (e.Clone (clonectx));
7470 if (initializers != null)
7471 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
7474 public override object Accept (StructuralVisitor visitor)
7476 return visitor.Visit (this);
7481 // Represents an implicitly typed array epxression
7483 class ImplicitlyTypedArrayCreation : ArrayCreation
7485 TypeInferenceContext best_type_inference;
7487 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7488 : base (null, rank, initializers, loc)
7492 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
7493 : base (null, initializers, loc)
7497 protected override Expression DoResolve (ResolveContext ec)
7502 dimensions = rank.Dimension;
7504 best_type_inference = new TypeInferenceContext ();
7506 if (!ResolveInitializers (ec))
7509 best_type_inference.FixAllTypes (ec);
7510 array_element_type = best_type_inference.InferredTypeArguments[0];
7511 best_type_inference = null;
7513 if (array_element_type == null ||
7514 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
7515 arguments.Count != rank.Dimension) {
7516 ec.Report.Error (826, loc,
7517 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
7522 // At this point we found common base type for all initializer elements
7523 // but we have to be sure that all static initializer elements are of
7526 UnifyInitializerElement (ec);
7528 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
7529 eclass = ExprClass.Value;
7534 // Converts static initializer only
7536 void UnifyInitializerElement (ResolveContext ec)
7538 for (int i = 0; i < array_data.Count; ++i) {
7539 Expression e = array_data[i];
7541 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
7545 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
7547 element = element.Resolve (ec);
7548 if (element != null)
7549 best_type_inference.AddCommonTypeBound (element.Type);
7555 sealed class CompilerGeneratedThis : This
7557 public CompilerGeneratedThis (TypeSpec type, Location loc)
7561 eclass = ExprClass.Variable;
7564 protected override Expression DoResolve (ResolveContext ec)
7569 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7576 /// Represents the `this' construct
7579 public class This : VariableReference
7581 sealed class ThisVariable : ILocalVariable
7583 public static readonly ILocalVariable Instance = new ThisVariable ();
7585 public void Emit (EmitContext ec)
7590 public void EmitAssign (EmitContext ec)
7592 throw new InvalidOperationException ();
7595 public void EmitAddressOf (EmitContext ec)
7601 VariableInfo variable_info;
7603 public This (Location loc)
7610 public override string Name {
7611 get { return "this"; }
7614 public override bool IsLockedByStatement {
7622 public override bool IsRef {
7623 get { return type.IsStruct; }
7626 public override bool IsSideEffectFree {
7632 protected override ILocalVariable Variable {
7633 get { return ThisVariable.Instance; }
7636 public override VariableInfo VariableInfo {
7637 get { return variable_info; }
7640 public override bool IsFixed {
7641 get { return false; }
7646 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
7649 // It's null for all cases when we don't need to check `this'
7650 // definitive assignment
7652 if (variable_info == null)
7655 if (rc.OmitStructFlowAnalysis)
7658 if (!variable_info.IsAssigned (rc)) {
7659 rc.Report.Error (188, loc,
7660 "The `this' object cannot be used before all of its fields are assigned to");
7664 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7666 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7667 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7668 } else if (ec.CurrentAnonymousMethod != null) {
7669 ec.Report.Error (1673, loc,
7670 "Anonymous methods inside structs cannot access instance members of `this'. " +
7671 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7673 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7677 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7682 AnonymousMethodStorey storey = ae.Storey;
7683 return storey != null ? storey.HoistedThis : null;
7686 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7688 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7691 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7694 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7700 public virtual void ResolveBase (ResolveContext ec)
7702 eclass = ExprClass.Variable;
7703 type = ec.CurrentType;
7705 if (!IsThisAvailable (ec, false)) {
7706 Error_ThisNotAvailable (ec);
7710 var block = ec.CurrentBlock;
7711 if (block != null) {
7712 var top = block.ParametersBlock.TopBlock;
7713 if (top.ThisVariable != null)
7714 variable_info = top.ThisVariable.VariableInfo;
7716 AnonymousExpression am = ec.CurrentAnonymousMethod;
7717 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7719 // Hoisted this is almost like hoisted variable but not exactly. When
7720 // there is no variable hoisted we can simply emit an instance method
7721 // without lifting this into a storey. Unfotunatelly this complicates
7722 // things in other cases because we don't know where this will be hoisted
7723 // until top-level block is fully resolved
7725 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7726 am.SetHasThisAccess ();
7731 protected override Expression DoResolve (ResolveContext ec)
7735 CheckStructThisDefiniteAssignment (ec);
7740 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7742 if (eclass == ExprClass.Unresolved)
7745 if (variable_info != null)
7746 variable_info.SetAssigned (ec);
7749 if (right_side == EmptyExpression.UnaryAddress)
7750 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7751 else if (right_side == EmptyExpression.OutAccess)
7752 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7754 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7760 public override int GetHashCode()
7762 throw new NotImplementedException ();
7765 public override bool Equals (object obj)
7767 This t = obj as This;
7774 protected override void CloneTo (CloneContext clonectx, Expression t)
7779 public override void SetHasAddressTaken ()
7784 public override void VerifyAssigned (ResolveContext rc)
7788 public override object Accept (StructuralVisitor visitor)
7790 return visitor.Visit (this);
7795 /// Represents the `__arglist' construct
7797 public class ArglistAccess : Expression
7799 public ArglistAccess (Location loc)
7804 protected override void CloneTo (CloneContext clonectx, Expression target)
7809 public override bool ContainsEmitWithAwait ()
7814 public override Expression CreateExpressionTree (ResolveContext ec)
7816 throw new NotSupportedException ("ET");
7819 protected override Expression DoResolve (ResolveContext ec)
7821 eclass = ExprClass.Variable;
7822 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
7824 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7825 ec.Report.Error (190, loc,
7826 "The __arglist construct is valid only within a variable argument method");
7832 public override void Emit (EmitContext ec)
7834 ec.Emit (OpCodes.Arglist);
7837 public override object Accept (StructuralVisitor visitor)
7839 return visitor.Visit (this);
7844 /// Represents the `__arglist (....)' construct
7846 public class Arglist : Expression
7848 Arguments arguments;
7850 public Arglist (Location loc)
7855 public Arglist (Arguments args, Location l)
7861 public Arguments Arguments {
7867 public MetaType[] ArgumentTypes {
7869 if (arguments == null)
7870 return MetaType.EmptyTypes;
7872 var retval = new MetaType[arguments.Count];
7873 for (int i = 0; i < retval.Length; i++)
7874 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
7880 public override bool ContainsEmitWithAwait ()
7882 throw new NotImplementedException ();
7885 public override Expression CreateExpressionTree (ResolveContext ec)
7887 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7891 protected override Expression DoResolve (ResolveContext ec)
7893 eclass = ExprClass.Variable;
7894 type = InternalType.Arglist;
7895 if (arguments != null) {
7896 bool dynamic; // Can be ignored as there is always only 1 overload
7897 arguments.Resolve (ec, out dynamic);
7903 public override void Emit (EmitContext ec)
7905 if (arguments != null)
7906 arguments.Emit (ec);
7909 protected override void CloneTo (CloneContext clonectx, Expression t)
7911 Arglist target = (Arglist) t;
7913 if (arguments != null)
7914 target.arguments = arguments.Clone (clonectx);
7917 public override object Accept (StructuralVisitor visitor)
7919 return visitor.Visit (this);
7923 public class RefValueExpr : ShimExpression, IAssignMethod
7925 FullNamedExpression texpr;
7927 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7934 public FullNamedExpression TypeExpression {
7940 public override bool ContainsEmitWithAwait ()
7945 protected override Expression DoResolve (ResolveContext rc)
7947 expr = expr.Resolve (rc);
7948 type = texpr.ResolveAsType (rc);
7949 if (expr == null || type == null)
7952 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7953 eclass = ExprClass.Value;
7957 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7959 return DoResolve (rc);
7962 public override void Emit (EmitContext ec)
7965 ec.Emit (OpCodes.Refanyval, type);
7966 ec.EmitLoadFromPtr (type);
7969 public void Emit (EmitContext ec, bool leave_copy)
7971 throw new NotImplementedException ();
7974 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7977 ec.Emit (OpCodes.Refanyval, type);
7980 LocalTemporary temporary = null;
7982 ec.Emit (OpCodes.Dup);
7983 temporary = new LocalTemporary (source.Type);
7984 temporary.Store (ec);
7987 ec.EmitStoreFromPtr (type);
7989 if (temporary != null) {
7990 temporary.Emit (ec);
7991 temporary.Release (ec);
7995 public override object Accept (StructuralVisitor visitor)
7997 return visitor.Visit (this);
8001 public class RefTypeExpr : ShimExpression
8003 public RefTypeExpr (Expression expr, Location loc)
8009 protected override Expression DoResolve (ResolveContext rc)
8011 expr = expr.Resolve (rc);
8015 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8019 type = rc.BuiltinTypes.Type;
8020 eclass = ExprClass.Value;
8024 public override void Emit (EmitContext ec)
8027 ec.Emit (OpCodes.Refanytype);
8028 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8030 ec.Emit (OpCodes.Call, m);
8033 public override object Accept (StructuralVisitor visitor)
8035 return visitor.Visit (this);
8039 public class MakeRefExpr : ShimExpression
8041 public MakeRefExpr (Expression expr, Location loc)
8047 public override bool ContainsEmitWithAwait ()
8049 throw new NotImplementedException ();
8052 protected override Expression DoResolve (ResolveContext rc)
8054 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8055 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8056 eclass = ExprClass.Value;
8060 public override void Emit (EmitContext ec)
8062 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8063 ec.Emit (OpCodes.Mkrefany, expr.Type);
8066 public override object Accept (StructuralVisitor visitor)
8068 return visitor.Visit (this);
8073 /// Implements the typeof operator
8075 public class TypeOf : Expression {
8076 FullNamedExpression QueriedType;
8079 public TypeOf (FullNamedExpression queried_type, Location l)
8081 QueriedType = queried_type;
8086 // Use this constructor for any compiler generated typeof expression
8088 public TypeOf (TypeSpec type, Location loc)
8090 this.typearg = type;
8096 public override bool IsSideEffectFree {
8102 public TypeSpec TypeArgument {
8108 public FullNamedExpression TypeExpression {
8117 protected override void CloneTo (CloneContext clonectx, Expression t)
8119 TypeOf target = (TypeOf) t;
8120 if (QueriedType != null)
8121 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
8124 public override bool ContainsEmitWithAwait ()
8129 public override Expression CreateExpressionTree (ResolveContext ec)
8131 Arguments args = new Arguments (2);
8132 args.Add (new Argument (this));
8133 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8134 return CreateExpressionFactoryCall (ec, "Constant", args);
8137 protected override Expression DoResolve (ResolveContext ec)
8139 if (eclass != ExprClass.Unresolved)
8142 if (typearg == null) {
8144 // Pointer types are allowed without explicit unsafe, they are just tokens
8146 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
8147 typearg = QueriedType.ResolveAsType (ec);
8150 if (typearg == null)
8153 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8154 ec.Report.Error (1962, QueriedType.Location,
8155 "The typeof operator cannot be used on the dynamic type");
8159 type = ec.BuiltinTypes.Type;
8161 // Even though what is returned is a type object, it's treated as a value by the compiler.
8162 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
8163 eclass = ExprClass.Value;
8167 static bool ContainsDynamicType (TypeSpec type)
8169 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
8172 var element_container = type as ElementTypeSpec;
8173 if (element_container != null)
8174 return ContainsDynamicType (element_container.Element);
8176 foreach (var t in type.TypeArguments) {
8177 if (ContainsDynamicType (t)) {
8185 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
8187 // Target type is not System.Type therefore must be object
8188 // and we need to use different encoding sequence
8189 if (targetType != type)
8192 if (typearg is InflatedTypeSpec) {
8195 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
8196 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
8197 typearg.GetSignatureForError ());
8201 gt = gt.DeclaringType;
8202 } while (gt != null);
8205 if (ContainsDynamicType (typearg)) {
8206 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8210 enc.EncodeTypeName (typearg);
8213 public override void Emit (EmitContext ec)
8215 ec.Emit (OpCodes.Ldtoken, typearg);
8216 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8218 ec.Emit (OpCodes.Call, m);
8221 public override object Accept (StructuralVisitor visitor)
8223 return visitor.Visit (this);
8227 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
8229 public TypeOfMethod (MethodSpec method, Location loc)
8230 : base (method, loc)
8234 protected override Expression DoResolve (ResolveContext ec)
8236 if (member.IsConstructor) {
8237 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
8239 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
8245 return base.DoResolve (ec);
8248 public override void Emit (EmitContext ec)
8250 ec.Emit (OpCodes.Ldtoken, member);
8253 ec.Emit (OpCodes.Castclass, type);
8256 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8258 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
8261 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8263 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
8267 abstract class TypeOfMember<T> : Expression where T : MemberSpec
8269 protected readonly T member;
8271 protected TypeOfMember (T member, Location loc)
8273 this.member = member;
8277 public override bool IsSideEffectFree {
8283 public override bool ContainsEmitWithAwait ()
8288 public override Expression CreateExpressionTree (ResolveContext ec)
8290 Arguments args = new Arguments (2);
8291 args.Add (new Argument (this));
8292 args.Add (new Argument (new TypeOf (type, loc)));
8293 return CreateExpressionFactoryCall (ec, "Constant", args);
8296 protected override Expression DoResolve (ResolveContext ec)
8298 eclass = ExprClass.Value;
8302 public override void Emit (EmitContext ec)
8304 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
8305 PredefinedMember<MethodSpec> p;
8307 p = GetTypeFromHandleGeneric (ec);
8308 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
8310 p = GetTypeFromHandle (ec);
8313 var mi = p.Resolve (loc);
8315 ec.Emit (OpCodes.Call, mi);
8318 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
8319 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
8322 sealed class TypeOfField : TypeOfMember<FieldSpec>
8324 public TypeOfField (FieldSpec field, Location loc)
8329 protected override Expression DoResolve (ResolveContext ec)
8331 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
8335 return base.DoResolve (ec);
8338 public override void Emit (EmitContext ec)
8340 ec.Emit (OpCodes.Ldtoken, member);
8344 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8346 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
8349 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8351 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
8356 /// Implements the sizeof expression
8358 public class SizeOf : Expression {
8359 readonly Expression texpr;
8360 TypeSpec type_queried;
8362 public SizeOf (Expression queried_type, Location l)
8364 this.texpr = queried_type;
8368 public override bool IsSideEffectFree {
8374 public Expression TypeExpression {
8380 public override bool ContainsEmitWithAwait ()
8385 public override Expression CreateExpressionTree (ResolveContext ec)
8387 Error_PointerInsideExpressionTree (ec);
8391 protected override Expression DoResolve (ResolveContext ec)
8393 type_queried = texpr.ResolveAsType (ec);
8394 if (type_queried == null)
8397 if (type_queried.IsEnum)
8398 type_queried = EnumSpec.GetUnderlyingType (type_queried);
8400 int size_of = BuiltinTypeSpec.GetSize (type_queried);
8402 return new IntConstant (ec.BuiltinTypes, size_of, loc);
8405 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
8410 ec.Report.Error (233, loc,
8411 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
8412 type_queried.GetSignatureForError ());
8415 type = ec.BuiltinTypes.Int;
8416 eclass = ExprClass.Value;
8420 public override void Emit (EmitContext ec)
8422 ec.Emit (OpCodes.Sizeof, type_queried);
8425 protected override void CloneTo (CloneContext clonectx, Expression t)
8429 public override object Accept (StructuralVisitor visitor)
8431 return visitor.Visit (this);
8436 /// Implements the qualified-alias-member (::) expression.
8438 public class QualifiedAliasMember : MemberAccess
8440 readonly string alias;
8441 public static readonly string GlobalAlias = "global";
8443 public QualifiedAliasMember (string alias, string identifier, Location l)
8444 : base (null, identifier, l)
8449 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
8450 : base (null, identifier, targs, l)
8455 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
8456 : base (null, identifier, arity, l)
8461 public string Alias {
8467 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
8469 if (alias == GlobalAlias) {
8470 expr = ec.Module.GlobalRootNamespace;
8471 return base.ResolveAsTypeOrNamespace (ec);
8474 int errors = ec.Module.Compiler.Report.Errors;
8475 expr = ec.LookupNamespaceAlias (alias);
8477 if (errors == ec.Module.Compiler.Report.Errors)
8478 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
8482 return base.ResolveAsTypeOrNamespace (ec);
8485 protected override Expression DoResolve (ResolveContext ec)
8487 return ResolveAsTypeOrNamespace (ec);
8490 public override string GetSignatureForError ()
8493 if (targs != null) {
8494 name = Name + "<" + targs.GetSignatureForError () + ">";
8497 return alias + "::" + name;
8500 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8502 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
8503 rc.Module.Compiler.Report.Error (687, loc,
8504 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
8505 GetSignatureForError ());
8510 return DoResolve (rc);
8513 protected override void CloneTo (CloneContext clonectx, Expression t)
8518 public override object Accept (StructuralVisitor visitor)
8520 return visitor.Visit (this);
8525 /// Implements the member access expression
8527 public class MemberAccess : ATypeNameExpression
8529 protected Expression expr;
8531 public MemberAccess (Expression expr, string id)
8532 : base (id, expr.Location)
8537 public MemberAccess (Expression expr, string identifier, Location loc)
8538 : base (identifier, loc)
8543 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
8544 : base (identifier, args, loc)
8549 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
8550 : base (identifier, arity, loc)
8555 public Expression LeftExpression {
8561 public override Location StartLocation {
8563 return expr == null ? loc : expr.StartLocation;
8567 protected override Expression DoResolve (ResolveContext rc)
8569 var e = DoResolveName (rc, null);
8571 if (!rc.OmitStructFlowAnalysis) {
8572 var fe = e as FieldExpr;
8574 fe.VerifyAssignedStructField (rc, null);
8581 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
8583 var e = DoResolveName (rc, rhs);
8585 if (!rc.OmitStructFlowAnalysis) {
8586 var fe = e as FieldExpr;
8587 if (fe != null && fe.InstanceExpression is FieldExpr) {
8588 fe = (FieldExpr) fe.InstanceExpression;
8589 fe.VerifyAssignedStructField (rc, rhs);
8596 Expression DoResolveName (ResolveContext rc, Expression right_side)
8598 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
8602 if (right_side != null) {
8603 if (e is TypeExpr) {
8604 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8608 e = e.ResolveLValue (rc, right_side);
8610 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
8616 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8618 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8619 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8621 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8624 public static bool IsValidDotExpression (TypeSpec type)
8626 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8627 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8629 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8632 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8634 var sn = expr as SimpleName;
8635 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8638 // Resolve the expression with flow analysis turned off, we'll do the definite
8639 // assignment checks later. This is because we don't know yet what the expression
8640 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
8641 // definite assignment check on the actual field and not on the whole struct.
8643 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
8645 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8648 // Resolve expression which does have type set as we need expression type
8649 // with disable flow analysis as we don't know whether left side expression
8650 // is used as variable or type
8652 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8653 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
8654 expr = expr.Resolve (rc);
8656 } else if (expr is TypeParameterExpr) {
8657 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8661 expr = expr.Resolve (rc, flags);
8668 Namespace ns = expr as Namespace;
8670 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8672 if (retval == null) {
8673 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8677 if (HasTypeArguments)
8678 return new GenericTypeExpr (retval.Type, targs, loc);
8684 TypeSpec expr_type = expr.Type;
8685 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8686 me = expr as MemberExpr;
8688 me.ResolveInstanceExpression (rc, null);
8691 // Run defined assigned checks on expressions resolved with
8692 // disabled flow-analysis
8695 var vr = expr as VariableReference;
8697 vr.VerifyAssigned (rc);
8700 Arguments args = new Arguments (1);
8701 args.Add (new Argument (expr));
8702 return new DynamicMemberBinder (Name, args, loc);
8705 if (!IsValidDotExpression (expr_type)) {
8706 Error_OperatorCannotBeApplied (rc, expr_type);
8710 var lookup_arity = Arity;
8711 bool errorMode = false;
8712 Expression member_lookup;
8714 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8715 if (member_lookup == null) {
8717 // Try to look for extension method when member lookup failed
8719 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8720 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8721 if (methods != null) {
8722 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8723 if (HasTypeArguments) {
8724 if (!targs.Resolve (rc))
8727 emg.SetTypeArguments (rc, targs);
8731 // Run defined assigned checks on expressions resolved with
8732 // disabled flow-analysis
8734 if (sn != null && !errorMode) {
8735 var vr = expr as VariableReference;
8737 vr.VerifyAssigned (rc);
8740 // TODO: it should really skip the checks bellow
8741 return emg.Resolve (rc);
8747 if (member_lookup == null) {
8748 var dep = expr_type.GetMissingDependencies ();
8750 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8751 } else if (expr is TypeExpr) {
8752 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8754 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8760 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8761 // Leave it to overload resolution to report correct error
8762 } else if (!(member_lookup is TypeExpr)) {
8763 // TODO: rc.SymbolRelatedToPreviousError
8764 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8769 if (member_lookup != null)
8773 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8777 TypeExpr texpr = member_lookup as TypeExpr;
8778 if (texpr != null) {
8779 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8780 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8781 Name, texpr.GetSignatureForError ());
8784 if (!texpr.Type.IsAccessible (rc)) {
8785 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8786 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8790 if (HasTypeArguments) {
8791 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8794 return member_lookup;
8797 me = member_lookup as MemberExpr;
8799 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8803 me = me.ResolveMemberAccess (rc, expr, sn);
8806 if (!targs.Resolve (rc))
8809 me.SetTypeArguments (rc, targs);
8813 // Run defined assigned checks on expressions resolved with
8814 // disabled flow-analysis
8816 if (sn != null && !(me is FieldExpr && TypeSpec.IsValueType (expr_type))) {
8817 var vr = expr as VariableReference;
8819 vr.VerifyAssigned (rc);
8825 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8827 FullNamedExpression fexpr = expr as FullNamedExpression;
8828 if (fexpr == null) {
8829 expr.ResolveAsType (rc);
8833 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8835 if (expr_resolved == null)
8838 Namespace ns = expr_resolved as Namespace;
8840 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8842 if (retval == null) {
8843 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8844 } else if (HasTypeArguments) {
8845 retval = new GenericTypeExpr (retval.Type, targs, loc);
8846 if (retval.ResolveAsType (rc) == null)
8853 var tnew_expr = expr_resolved.ResolveAsType (rc);
8854 if (tnew_expr == null)
8857 TypeSpec expr_type = tnew_expr;
8858 if (TypeManager.IsGenericParameter (expr_type)) {
8859 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8860 tnew_expr.GetSignatureForError ());
8864 var qam = this as QualifiedAliasMember;
8866 rc.Module.Compiler.Report.Error (431, loc,
8867 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8872 TypeSpec nested = null;
8873 while (expr_type != null) {
8874 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8875 if (nested == null) {
8876 if (expr_type == tnew_expr) {
8877 Error_IdentifierNotFound (rc, expr_type, Name);
8881 expr_type = tnew_expr;
8882 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8883 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
8887 if (nested.IsAccessible (rc))
8891 // Keep looking after inaccessible candidate but only if
8892 // we are not in same context as the definition itself
8894 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
8897 expr_type = expr_type.BaseType;
8902 if (HasTypeArguments) {
8903 texpr = new GenericTypeExpr (nested, targs, loc);
8905 texpr = new GenericOpenTypeExpr (nested, loc);
8908 texpr = new TypeExpression (nested, loc);
8911 if (texpr.ResolveAsType (rc) == null)
8917 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
8919 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
8921 if (nested != null) {
8922 Error_TypeArgumentsCannotBeUsed (rc, nested, Arity, expr.Location);
8926 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
8927 if (any_other_member != null) {
8928 any_other_member.Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
8932 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
8933 Name, expr_type.GetSignatureForError ());
8936 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
8938 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
8941 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
8943 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8944 ec.Report.SymbolRelatedToPreviousError (type);
8946 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, type, name, Arity);
8948 // a using directive or an assembly reference
8950 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
8952 missing = "an assembly reference";
8955 ec.Report.Error (1061, loc,
8956 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
8957 type.GetSignatureForError (), name, missing);
8961 base.Error_TypeDoesNotContainDefinition (ec, type, name);
8964 public override string GetSignatureForError ()
8966 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
8969 protected override void CloneTo (CloneContext clonectx, Expression t)
8971 MemberAccess target = (MemberAccess) t;
8973 target.expr = expr.Clone (clonectx);
8976 public override object Accept (StructuralVisitor visitor)
8978 return visitor.Visit (this);
8983 /// Implements checked expressions
8985 public class CheckedExpr : Expression {
8987 public Expression Expr;
8989 public CheckedExpr (Expression e, Location l)
8995 public override bool ContainsEmitWithAwait ()
8997 return Expr.ContainsEmitWithAwait ();
9000 public override Expression CreateExpressionTree (ResolveContext ec)
9002 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9003 return Expr.CreateExpressionTree (ec);
9006 protected override Expression DoResolve (ResolveContext ec)
9008 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9009 Expr = Expr.Resolve (ec);
9014 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9017 eclass = Expr.eclass;
9022 public override void Emit (EmitContext ec)
9024 using (ec.With (EmitContext.Options.CheckedScope, true))
9028 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9030 using (ec.With (EmitContext.Options.CheckedScope, true))
9031 Expr.EmitBranchable (ec, target, on_true);
9034 public override SLE.Expression MakeExpression (BuilderContext ctx)
9036 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9037 return Expr.MakeExpression (ctx);
9041 protected override void CloneTo (CloneContext clonectx, Expression t)
9043 CheckedExpr target = (CheckedExpr) t;
9045 target.Expr = Expr.Clone (clonectx);
9048 public override object Accept (StructuralVisitor visitor)
9050 return visitor.Visit (this);
9055 /// Implements the unchecked expression
9057 public class UnCheckedExpr : Expression {
9059 public Expression Expr;
9061 public UnCheckedExpr (Expression e, Location l)
9067 public override bool ContainsEmitWithAwait ()
9069 return Expr.ContainsEmitWithAwait ();
9072 public override Expression CreateExpressionTree (ResolveContext ec)
9074 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9075 return Expr.CreateExpressionTree (ec);
9078 protected override Expression DoResolve (ResolveContext ec)
9080 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9081 Expr = Expr.Resolve (ec);
9086 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9089 eclass = Expr.eclass;
9094 public override void Emit (EmitContext ec)
9096 using (ec.With (EmitContext.Options.CheckedScope, false))
9100 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9102 using (ec.With (EmitContext.Options.CheckedScope, false))
9103 Expr.EmitBranchable (ec, target, on_true);
9106 protected override void CloneTo (CloneContext clonectx, Expression t)
9108 UnCheckedExpr target = (UnCheckedExpr) t;
9110 target.Expr = Expr.Clone (clonectx);
9113 public override object Accept (StructuralVisitor visitor)
9115 return visitor.Visit (this);
9120 /// An Element Access expression.
9122 /// During semantic analysis these are transformed into
9123 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
9125 public class ElementAccess : Expression
9127 public Arguments Arguments;
9128 public Expression Expr;
9130 public ElementAccess (Expression e, Arguments args, Location loc)
9134 this.Arguments = args;
9137 public override Location StartLocation {
9139 return Expr.StartLocation;
9143 public override bool ContainsEmitWithAwait ()
9145 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
9149 // We perform some simple tests, and then to "split" the emit and store
9150 // code we create an instance of a different class, and return that.
9152 Expression CreateAccessExpression (ResolveContext ec)
9155 return (new ArrayAccess (this, loc));
9158 return MakePointerAccess (ec, type);
9160 FieldExpr fe = Expr as FieldExpr;
9162 var ff = fe.Spec as FixedFieldSpec;
9164 return MakePointerAccess (ec, ff.ElementType);
9168 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
9169 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9170 return new IndexerExpr (indexers, type, this);
9173 if (type != InternalType.ErrorType) {
9174 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
9175 type.GetSignatureForError ());
9181 public override Expression CreateExpressionTree (ResolveContext ec)
9183 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
9184 Expr.CreateExpressionTree (ec));
9186 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
9189 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
9191 if (Arguments.Count != 1){
9192 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
9196 if (Arguments [0] is NamedArgument)
9197 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
9199 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
9200 return new Indirection (p, loc);
9203 protected override Expression DoResolve (ResolveContext ec)
9205 Expr = Expr.Resolve (ec);
9211 // TODO: Create 1 result for Resolve and ResolveLValue ?
9212 var res = CreateAccessExpression (ec);
9216 return res.Resolve (ec);
9219 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
9221 Expr = Expr.Resolve (ec);
9227 var res = CreateAccessExpression (ec);
9231 return res.ResolveLValue (ec, rhs);
9234 public override void Emit (EmitContext ec)
9236 throw new Exception ("Should never be reached");
9239 public static void Error_NamedArgument (NamedArgument na, Report Report)
9241 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
9244 public override string GetSignatureForError ()
9246 return Expr.GetSignatureForError ();
9249 protected override void CloneTo (CloneContext clonectx, Expression t)
9251 ElementAccess target = (ElementAccess) t;
9253 target.Expr = Expr.Clone (clonectx);
9254 if (Arguments != null)
9255 target.Arguments = Arguments.Clone (clonectx);
9258 public override object Accept (StructuralVisitor visitor)
9260 return visitor.Visit (this);
9265 /// Implements array access
9267 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
9269 // Points to our "data" repository
9273 LocalTemporary temp;
9275 bool? has_await_args;
9277 public ArrayAccess (ElementAccess ea_data, Location l)
9283 public void AddressOf (EmitContext ec, AddressOp mode)
9285 var ac = (ArrayContainer) ea.Expr.Type;
9287 LoadInstanceAndArguments (ec, false, false);
9289 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
9290 ec.Emit (OpCodes.Readonly);
9292 ec.EmitArrayAddress (ac);
9295 public override Expression CreateExpressionTree (ResolveContext ec)
9297 return ea.CreateExpressionTree (ec);
9300 public override bool ContainsEmitWithAwait ()
9302 return ea.ContainsEmitWithAwait ();
9305 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9307 return DoResolve (ec);
9310 protected override Expression DoResolve (ResolveContext ec)
9312 // dynamic is used per argument in ConvertExpressionToArrayIndex case
9314 ea.Arguments.Resolve (ec, out dynamic);
9316 var ac = ea.Expr.Type as ArrayContainer;
9317 int rank = ea.Arguments.Count;
9318 if (ac.Rank != rank) {
9319 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
9320 rank.ToString (), ac.Rank.ToString ());
9325 if (type.IsPointer && !ec.IsUnsafe) {
9326 UnsafeError (ec, ea.Location);
9329 foreach (Argument a in ea.Arguments) {
9330 if (a is NamedArgument)
9331 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
9333 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
9336 eclass = ExprClass.Variable;
9341 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
9343 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
9347 // Load the array arguments into the stack.
9349 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
9352 ea.Expr = ea.Expr.EmitToField (ec);
9353 } else if (duplicateArguments) {
9355 ec.Emit (OpCodes.Dup);
9357 var copy = new LocalTemporary (ea.Expr.Type);
9364 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
9365 if (dup_args != null)
9366 ea.Arguments = dup_args;
9369 public void Emit (EmitContext ec, bool leave_copy)
9371 var ac = ea.Expr.Type as ArrayContainer;
9374 ec.EmitLoadFromPtr (type);
9376 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
9377 LoadInstanceAndArguments (ec, false, true);
9380 LoadInstanceAndArguments (ec, false, false);
9381 ec.EmitArrayLoad (ac);
9385 ec.Emit (OpCodes.Dup);
9386 temp = new LocalTemporary (this.type);
9391 public override void Emit (EmitContext ec)
9396 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9398 var ac = (ArrayContainer) ea.Expr.Type;
9399 TypeSpec t = source.Type;
9401 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
9404 // When we are dealing with a struct, get the address of it to avoid value copy
9405 // Same cannot be done for reference type because array covariance and the
9406 // check in ldelema requires to specify the type of array element stored at the index
9408 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
9409 LoadInstanceAndArguments (ec, false, has_await_args.Value);
9411 if (has_await_args.Value) {
9412 if (source.ContainsEmitWithAwait ()) {
9413 source = source.EmitToField (ec);
9418 LoadInstanceAndArguments (ec, isCompound, false);
9423 ec.EmitArrayAddress (ac);
9426 ec.Emit (OpCodes.Dup);
9430 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
9432 if (has_await_args.Value) {
9433 if (source.ContainsEmitWithAwait ())
9434 source = source.EmitToField (ec);
9436 LoadInstanceAndArguments (ec, false, false);
9443 var lt = ea.Expr as LocalTemporary;
9449 ec.Emit (OpCodes.Dup);
9450 temp = new LocalTemporary (this.type);
9455 ec.EmitStoreFromPtr (t);
9457 ec.EmitArrayStore (ac);
9466 public override Expression EmitToField (EmitContext ec)
9469 // Have to be specialized for arrays to get access to
9470 // underlying element. Instead of another result copy we
9471 // need direct access to element
9475 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
9477 ea.Expr = ea.Expr.EmitToField (ec);
9481 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9483 #if NET_4_0 || MONODROID
9484 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9486 throw new NotImplementedException ();
9490 public override SLE.Expression MakeExpression (BuilderContext ctx)
9492 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9495 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
9497 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9498 return Arguments.MakeExpression (ea.Arguments, ctx);
9504 // Indexer access expression
9506 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
9508 IList<MemberSpec> indexers;
9509 Arguments arguments;
9510 TypeSpec queried_type;
9512 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
9513 : base (ea.Location)
9515 this.indexers = indexers;
9516 this.queried_type = queriedType;
9517 this.InstanceExpression = ea.Expr;
9518 this.arguments = ea.Arguments;
9523 protected override Arguments Arguments {
9532 protected override TypeSpec DeclaringType {
9534 return best_candidate.DeclaringType;
9538 public override bool IsInstance {
9544 public override bool IsStatic {
9550 public override string KindName {
9551 get { return "indexer"; }
9554 public override string Name {
9562 public override bool ContainsEmitWithAwait ()
9564 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
9567 public override Expression CreateExpressionTree (ResolveContext ec)
9569 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
9570 InstanceExpression.CreateExpressionTree (ec),
9571 new TypeOfMethod (Getter, loc));
9573 return CreateExpressionFactoryCall (ec, "Call", args);
9576 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9578 LocalTemporary await_source_arg = null;
9581 emitting_compound_assignment = true;
9582 if (source is DynamicExpressionStatement) {
9587 emitting_compound_assignment = false;
9589 if (has_await_arguments) {
9590 await_source_arg = new LocalTemporary (Type);
9591 await_source_arg.Store (ec);
9593 arguments.Add (new Argument (await_source_arg));
9596 temp = await_source_arg;
9599 has_await_arguments = false;
9604 ec.Emit (OpCodes.Dup);
9605 temp = new LocalTemporary (Type);
9611 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9612 source = source.EmitToField (ec);
9614 temp = new LocalTemporary (Type);
9621 arguments.Add (new Argument (source));
9624 var call = new CallEmitter ();
9625 call.InstanceExpression = InstanceExpression;
9626 if (arguments == null)
9627 call.InstanceExpressionOnStack = true;
9629 call.Emit (ec, Setter, arguments, loc);
9634 } else if (leave_copy) {
9638 if (await_source_arg != null) {
9639 await_source_arg.Release (ec);
9643 public override string GetSignatureForError ()
9645 return best_candidate.GetSignatureForError ();
9648 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9651 throw new NotSupportedException ();
9653 var value = new[] { source.MakeExpression (ctx) };
9654 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9655 #if NET_4_0 || MONODROID
9656 return SLE.Expression.Block (
9657 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9660 return args.First ();
9665 public override SLE.Expression MakeExpression (BuilderContext ctx)
9668 return base.MakeExpression (ctx);
9670 var args = Arguments.MakeExpression (arguments, ctx);
9671 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9675 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9677 if (best_candidate != null)
9680 eclass = ExprClass.IndexerAccess;
9683 arguments.Resolve (rc, out dynamic);
9685 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9688 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9689 res.BaseMembersProvider = this;
9690 res.InstanceQualifier = this;
9692 // TODO: Do I need 2 argument sets?
9693 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9694 if (best_candidate != null)
9695 type = res.BestCandidateReturnType;
9696 else if (!res.BestCandidateIsDynamic)
9701 // It has dynamic arguments
9704 Arguments args = new Arguments (arguments.Count + 1);
9706 rc.Report.Error (1972, loc,
9707 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9709 args.Add (new Argument (InstanceExpression));
9711 args.AddRange (arguments);
9713 best_candidate = null;
9714 return new DynamicIndexBinder (args, loc);
9718 // Try to avoid resolving left expression again
9720 if (right_side != null)
9721 ResolveInstanceExpression (rc, right_side);
9726 protected override void CloneTo (CloneContext clonectx, Expression t)
9728 IndexerExpr target = (IndexerExpr) t;
9730 if (arguments != null)
9731 target.arguments = arguments.Clone (clonectx);
9734 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9736 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9739 #region IBaseMembersProvider Members
9741 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9743 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9746 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9748 if (queried_type == member.DeclaringType)
9751 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9752 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9755 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9764 // A base access expression
9766 public class BaseThis : This
9768 public BaseThis (Location loc)
9773 public BaseThis (TypeSpec type, Location loc)
9777 eclass = ExprClass.Variable;
9782 public override string Name {
9790 public override Expression CreateExpressionTree (ResolveContext ec)
9792 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9793 return base.CreateExpressionTree (ec);
9796 public override void Emit (EmitContext ec)
9800 var context_type = ec.CurrentType;
9801 if (context_type.IsStruct) {
9802 ec.Emit (OpCodes.Ldobj, context_type);
9803 ec.Emit (OpCodes.Box, context_type);
9807 protected override void Error_ThisNotAvailable (ResolveContext ec)
9810 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9812 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9816 public override void ResolveBase (ResolveContext ec)
9818 base.ResolveBase (ec);
9819 type = ec.CurrentType.BaseType;
9822 public override object Accept (StructuralVisitor visitor)
9824 return visitor.Visit (this);
9829 /// This class exists solely to pass the Type around and to be a dummy
9830 /// that can be passed to the conversion functions (this is used by
9831 /// foreach implementation to typecast the object return value from
9832 /// get_Current into the proper type. All code has been generated and
9833 /// we only care about the side effect conversions to be performed
9835 /// This is also now used as a placeholder where a no-action expression
9836 /// is needed (the `New' class).
9838 public class EmptyExpression : Expression
9840 sealed class OutAccessExpression : EmptyExpression
9842 public OutAccessExpression (TypeSpec t)
9847 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9849 rc.Report.Error (206, right_side.Location,
9850 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
9856 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
9857 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
9858 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
9859 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
9860 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
9861 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
9862 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
9863 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
9865 public EmptyExpression (TypeSpec t)
9868 eclass = ExprClass.Value;
9869 loc = Location.Null;
9872 public override bool ContainsEmitWithAwait ()
9877 public override Expression CreateExpressionTree (ResolveContext ec)
9879 throw new NotSupportedException ("ET");
9882 protected override Expression DoResolve (ResolveContext ec)
9887 public override void Emit (EmitContext ec)
9889 // nothing, as we only exist to not do anything.
9892 public override void EmitSideEffect (EmitContext ec)
9896 public override object Accept (StructuralVisitor visitor)
9898 return visitor.Visit (this);
9902 sealed class EmptyAwaitExpression : EmptyExpression
9904 public EmptyAwaitExpression (TypeSpec type)
9909 public override bool ContainsEmitWithAwait ()
9916 // Empty statement expression
9918 public sealed class EmptyExpressionStatement : ExpressionStatement
9920 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
9922 private EmptyExpressionStatement ()
9924 loc = Location.Null;
9927 public override bool ContainsEmitWithAwait ()
9932 public override Expression CreateExpressionTree (ResolveContext ec)
9937 public override void EmitStatement (EmitContext ec)
9942 protected override Expression DoResolve (ResolveContext ec)
9944 eclass = ExprClass.Value;
9945 type = ec.BuiltinTypes.Object;
9949 public override void Emit (EmitContext ec)
9954 public override object Accept (StructuralVisitor visitor)
9956 return visitor.Visit (this);
9960 public class ErrorExpression : EmptyExpression
9962 public static readonly ErrorExpression Instance = new ErrorExpression ();
9964 private ErrorExpression ()
9965 : base (InternalType.ErrorType)
9969 public override Expression CreateExpressionTree (ResolveContext ec)
9974 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9979 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
9983 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
9987 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
9991 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
9995 public override object Accept (StructuralVisitor visitor)
9997 return visitor.Visit (this);
10001 public class UserCast : Expression {
10005 public UserCast (MethodSpec method, Expression source, Location l)
10007 if (source == null)
10008 throw new ArgumentNullException ("source");
10010 this.method = method;
10011 this.source = source;
10012 type = method.ReturnType;
10016 public Expression Source {
10022 public override bool ContainsEmitWithAwait ()
10024 return source.ContainsEmitWithAwait ();
10027 public override Expression CreateExpressionTree (ResolveContext ec)
10029 Arguments args = new Arguments (3);
10030 args.Add (new Argument (source.CreateExpressionTree (ec)));
10031 args.Add (new Argument (new TypeOf (type, loc)));
10032 args.Add (new Argument (new TypeOfMethod (method, loc)));
10033 return CreateExpressionFactoryCall (ec, "Convert", args);
10036 protected override Expression DoResolve (ResolveContext ec)
10038 ObsoleteAttribute oa = method.GetAttributeObsolete ();
10040 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
10042 eclass = ExprClass.Value;
10046 public override void Emit (EmitContext ec)
10049 ec.MarkCallEntry (loc);
10050 ec.Emit (OpCodes.Call, method);
10053 public override string GetSignatureForError ()
10055 return TypeManager.CSharpSignature (method);
10058 public override SLE.Expression MakeExpression (BuilderContext ctx)
10061 return base.MakeExpression (ctx);
10063 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
10069 // Holds additional type specifiers like ?, *, []
10071 public class ComposedTypeSpecifier
10073 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
10075 public readonly int Dimension;
10076 public readonly Location Location;
10078 public ComposedTypeSpecifier (int specifier, Location loc)
10080 this.Dimension = specifier;
10081 this.Location = loc;
10085 public bool IsNullable {
10087 return Dimension == -1;
10091 public bool IsPointer {
10093 return Dimension == -2;
10097 public ComposedTypeSpecifier Next { get; set; }
10101 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
10103 return new ComposedTypeSpecifier (dimension, loc);
10106 public static ComposedTypeSpecifier CreateNullable (Location loc)
10108 return new ComposedTypeSpecifier (-1, loc);
10111 public static ComposedTypeSpecifier CreatePointer (Location loc)
10113 return new ComposedTypeSpecifier (-2, loc);
10116 public string GetSignatureForError ()
10121 ArrayContainer.GetPostfixSignature (Dimension);
10123 return Next != null ? s + Next.GetSignatureForError () : s;
10128 // This class is used to "construct" the type during a typecast
10129 // operation. Since the Type.GetType class in .NET can parse
10130 // the type specification, we just use this to construct the type
10131 // one bit at a time.
10133 public class ComposedCast : TypeExpr {
10134 FullNamedExpression left;
10135 ComposedTypeSpecifier spec;
10137 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
10140 throw new ArgumentNullException ("spec");
10144 this.loc = left.Location;
10147 public override TypeSpec ResolveAsType (IMemberContext ec)
10149 type = left.ResolveAsType (ec);
10153 eclass = ExprClass.Type;
10155 var single_spec = spec;
10157 if (single_spec.IsNullable) {
10158 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
10162 single_spec = single_spec.Next;
10163 } else if (single_spec.IsPointer) {
10164 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
10167 if (!ec.IsUnsafe) {
10168 UnsafeError (ec.Module.Compiler.Report, loc);
10172 type = PointerContainer.MakeType (ec.Module, type);
10173 single_spec = single_spec.Next;
10174 } while (single_spec != null && single_spec.IsPointer);
10177 if (single_spec != null && single_spec.Dimension > 0) {
10178 if (type.IsSpecialRuntimeType) {
10179 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
10180 } else if (type.IsStatic) {
10181 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
10182 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
10183 type.GetSignatureForError ());
10185 MakeArray (ec.Module, single_spec);
10192 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
10194 if (spec.Next != null)
10195 MakeArray (module, spec.Next);
10197 type = ArrayContainer.MakeType (module, type, spec.Dimension);
10200 public override string GetSignatureForError ()
10202 return left.GetSignatureForError () + spec.GetSignatureForError ();
10205 public override object Accept (StructuralVisitor visitor)
10207 return visitor.Visit (this);
10211 class FixedBufferPtr : Expression
10213 readonly Expression array;
10215 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
10217 this.type = array_type;
10218 this.array = array;
10222 public override bool ContainsEmitWithAwait ()
10224 throw new NotImplementedException ();
10227 public override Expression CreateExpressionTree (ResolveContext ec)
10229 Error_PointerInsideExpressionTree (ec);
10233 public override void Emit(EmitContext ec)
10238 protected override Expression DoResolve (ResolveContext ec)
10240 type = PointerContainer.MakeType (ec.Module, type);
10241 eclass = ExprClass.Value;
10248 // This class is used to represent the address of an array, used
10249 // only by the Fixed statement, this generates "&a [0]" construct
10250 // for fixed (char *pa = a)
10252 class ArrayPtr : FixedBufferPtr
10254 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
10255 base (array, array_type, l)
10259 public override void Emit (EmitContext ec)
10264 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
10269 // Encapsulates a conversion rules required for array indexes
10271 public class ArrayIndexCast : TypeCast
10273 public ArrayIndexCast (Expression expr, TypeSpec returnType)
10274 : base (expr, returnType)
10276 if (expr.Type == returnType) // int -> int
10277 throw new ArgumentException ("unnecessary array index conversion");
10280 public override Expression CreateExpressionTree (ResolveContext ec)
10282 using (ec.Set (ResolveContext.Options.CheckedScope)) {
10283 return base.CreateExpressionTree (ec);
10287 public override void Emit (EmitContext ec)
10291 switch (child.Type.BuiltinType) {
10292 case BuiltinTypeSpec.Type.UInt:
10293 ec.Emit (OpCodes.Conv_U);
10295 case BuiltinTypeSpec.Type.Long:
10296 ec.Emit (OpCodes.Conv_Ovf_I);
10298 case BuiltinTypeSpec.Type.ULong:
10299 ec.Emit (OpCodes.Conv_Ovf_I_Un);
10302 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
10308 // Implements the `stackalloc' keyword
10310 public class StackAlloc : Expression {
10315 public StackAlloc (Expression type, Expression count, Location l)
10318 this.count = count;
10322 public Expression TypeExpression {
10328 public Expression CountExpression {
10334 public override bool ContainsEmitWithAwait ()
10339 public override Expression CreateExpressionTree (ResolveContext ec)
10341 throw new NotSupportedException ("ET");
10344 protected override Expression DoResolve (ResolveContext ec)
10346 count = count.Resolve (ec);
10350 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
10351 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
10356 Constant c = count as Constant;
10357 if (c != null && c.IsNegative) {
10358 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
10361 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
10362 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
10365 otype = t.ResolveAsType (ec);
10369 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
10372 type = PointerContainer.MakeType (ec.Module, otype);
10373 eclass = ExprClass.Value;
10378 public override void Emit (EmitContext ec)
10380 int size = BuiltinTypeSpec.GetSize (otype);
10385 ec.Emit (OpCodes.Sizeof, otype);
10389 ec.Emit (OpCodes.Mul_Ovf_Un);
10390 ec.Emit (OpCodes.Localloc);
10393 protected override void CloneTo (CloneContext clonectx, Expression t)
10395 StackAlloc target = (StackAlloc) t;
10396 target.count = count.Clone (clonectx);
10397 target.t = t.Clone (clonectx);
10400 public override object Accept (StructuralVisitor visitor)
10402 return visitor.Visit (this);
10407 // An object initializer expression
10409 public class ElementInitializer : Assign
10411 public readonly string Name;
10413 public ElementInitializer (string name, Expression initializer, Location loc)
10414 : base (null, initializer, loc)
10419 protected override void CloneTo (CloneContext clonectx, Expression t)
10421 ElementInitializer target = (ElementInitializer) t;
10422 target.source = source.Clone (clonectx);
10425 public override Expression CreateExpressionTree (ResolveContext ec)
10427 Arguments args = new Arguments (2);
10428 FieldExpr fe = target as FieldExpr;
10430 args.Add (new Argument (fe.CreateTypeOfExpression ()));
10432 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
10435 Expression arg_expr;
10436 var cinit = source as CollectionOrObjectInitializers;
10437 if (cinit == null) {
10439 arg_expr = source.CreateExpressionTree (ec);
10441 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
10442 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
10445 args.Add (new Argument (arg_expr));
10446 return CreateExpressionFactoryCall (ec, mname, args);
10449 protected override Expression DoResolve (ResolveContext ec)
10451 if (source == null)
10452 return EmptyExpressionStatement.Instance;
10454 var t = ec.CurrentInitializerVariable.Type;
10455 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10456 Arguments args = new Arguments (1);
10457 args.Add (new Argument (ec.CurrentInitializerVariable));
10458 target = new DynamicMemberBinder (Name, args, loc);
10461 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10462 if (member == null) {
10463 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10465 if (member != null) {
10466 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
10467 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
10472 if (member == null) {
10473 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
10477 if (!(member is PropertyExpr || member is FieldExpr)) {
10478 ec.Report.Error (1913, loc,
10479 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
10480 member.GetSignatureForError ());
10485 var me = member as MemberExpr;
10487 ec.Report.Error (1914, loc,
10488 "Static field or property `{0}' cannot be assigned in an object initializer",
10489 me.GetSignatureForError ());
10493 me.InstanceExpression = ec.CurrentInitializerVariable;
10496 if (source is CollectionOrObjectInitializers) {
10497 Expression previous = ec.CurrentInitializerVariable;
10498 ec.CurrentInitializerVariable = target;
10499 source = source.Resolve (ec);
10500 ec.CurrentInitializerVariable = previous;
10501 if (source == null)
10504 eclass = source.eclass;
10505 type = source.Type;
10509 return base.DoResolve (ec);
10512 public override void EmitStatement (EmitContext ec)
10514 if (source is CollectionOrObjectInitializers)
10517 base.EmitStatement (ec);
10522 // A collection initializer expression
10524 class CollectionElementInitializer : Invocation
10526 public class ElementInitializerArgument : Argument
10528 public ElementInitializerArgument (Expression e)
10534 sealed class AddMemberAccess : MemberAccess
10536 public AddMemberAccess (Expression expr, Location loc)
10537 : base (expr, "Add", loc)
10541 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10543 if (TypeManager.HasElementType (type))
10546 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10550 public CollectionElementInitializer (Expression argument)
10551 : base (null, new Arguments (1))
10553 base.arguments.Add (new ElementInitializerArgument (argument));
10554 this.loc = argument.Location;
10557 public CollectionElementInitializer (List<Expression> arguments, Location loc)
10558 : base (null, new Arguments (arguments.Count))
10560 foreach (Expression e in arguments)
10561 base.arguments.Add (new ElementInitializerArgument (e));
10566 public override Expression CreateExpressionTree (ResolveContext ec)
10568 Arguments args = new Arguments (2);
10569 args.Add (new Argument (mg.CreateExpressionTree (ec)));
10571 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
10572 foreach (Argument a in arguments)
10573 expr_initializers.Add (a.CreateExpressionTree (ec));
10575 args.Add (new Argument (new ArrayCreation (
10576 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
10577 return CreateExpressionFactoryCall (ec, "ElementInit", args);
10580 protected override void CloneTo (CloneContext clonectx, Expression t)
10582 CollectionElementInitializer target = (CollectionElementInitializer) t;
10583 if (arguments != null)
10584 target.arguments = arguments.Clone (clonectx);
10587 protected override Expression DoResolve (ResolveContext ec)
10589 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
10591 return base.DoResolve (ec);
10596 // A block of object or collection initializers
10598 public class CollectionOrObjectInitializers : ExpressionStatement
10600 IList<Expression> initializers;
10601 bool is_collection_initialization;
10603 public CollectionOrObjectInitializers (Location loc)
10604 : this (new Expression[0], loc)
10608 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10610 this.initializers = initializers;
10614 public IList<Expression> Initializers {
10616 return initializers;
10620 public bool IsEmpty {
10622 return initializers.Count == 0;
10626 public bool IsCollectionInitializer {
10628 return is_collection_initialization;
10632 protected override void CloneTo (CloneContext clonectx, Expression target)
10634 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10636 t.initializers = new List<Expression> (initializers.Count);
10637 foreach (var e in initializers)
10638 t.initializers.Add (e.Clone (clonectx));
10641 public override bool ContainsEmitWithAwait ()
10643 foreach (var e in initializers) {
10644 if (e.ContainsEmitWithAwait ())
10651 public override Expression CreateExpressionTree (ResolveContext ec)
10653 return CreateExpressionTree (ec, false);
10656 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10658 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10659 foreach (Expression e in initializers) {
10660 Expression expr = e.CreateExpressionTree (ec);
10662 expr_initializers.Add (expr);
10666 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10668 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10671 protected override Expression DoResolve (ResolveContext ec)
10673 List<string> element_names = null;
10674 for (int i = 0; i < initializers.Count; ++i) {
10675 Expression initializer = initializers [i];
10676 ElementInitializer element_initializer = initializer as ElementInitializer;
10679 if (element_initializer != null) {
10680 element_names = new List<string> (initializers.Count);
10681 element_names.Add (element_initializer.Name);
10682 } else if (initializer is CompletingExpression){
10683 initializer.Resolve (ec);
10684 throw new InternalErrorException ("This line should never be reached");
10686 var t = ec.CurrentInitializerVariable.Type;
10687 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10688 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10689 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10690 "object initializer because type `{1}' does not implement `{2}' interface",
10691 ec.CurrentInitializerVariable.GetSignatureForError (),
10692 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10693 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10696 is_collection_initialization = true;
10699 if (is_collection_initialization != (element_initializer == null)) {
10700 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10701 is_collection_initialization ? "collection initializer" : "object initializer");
10705 if (!is_collection_initialization) {
10706 if (element_names.Contains (element_initializer.Name)) {
10707 ec.Report.Error (1912, element_initializer.Location,
10708 "An object initializer includes more than one member `{0}' initialization",
10709 element_initializer.Name);
10711 element_names.Add (element_initializer.Name);
10716 Expression e = initializer.Resolve (ec);
10717 if (e == EmptyExpressionStatement.Instance)
10718 initializers.RemoveAt (i--);
10720 initializers [i] = e;
10723 type = ec.CurrentInitializerVariable.Type;
10724 if (is_collection_initialization) {
10725 if (TypeManager.HasElementType (type)) {
10726 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10727 type.GetSignatureForError ());
10731 eclass = ExprClass.Variable;
10735 public override void Emit (EmitContext ec)
10737 EmitStatement (ec);
10740 public override void EmitStatement (EmitContext ec)
10742 foreach (ExpressionStatement e in initializers) {
10743 // TODO: need location region
10744 ec.Mark (e.Location);
10745 e.EmitStatement (ec);
10751 // New expression with element/object initializers
10753 public class NewInitialize : New
10756 // This class serves as a proxy for variable initializer target instances.
10757 // A real variable is assigned later when we resolve left side of an
10760 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10762 NewInitialize new_instance;
10764 public InitializerTargetExpression (NewInitialize newInstance)
10766 this.type = newInstance.type;
10767 this.loc = newInstance.loc;
10768 this.eclass = newInstance.eclass;
10769 this.new_instance = newInstance;
10772 public override bool ContainsEmitWithAwait ()
10777 public override Expression CreateExpressionTree (ResolveContext ec)
10779 // Should not be reached
10780 throw new NotSupportedException ("ET");
10783 protected override Expression DoResolve (ResolveContext ec)
10788 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10793 public override void Emit (EmitContext ec)
10795 Expression e = (Expression) new_instance.instance;
10799 public override Expression EmitToField (EmitContext ec)
10801 return (Expression) new_instance.instance;
10804 #region IMemoryLocation Members
10806 public void AddressOf (EmitContext ec, AddressOp mode)
10808 new_instance.instance.AddressOf (ec, mode);
10814 CollectionOrObjectInitializers initializers;
10815 IMemoryLocation instance;
10816 DynamicExpressionStatement dynamic;
10818 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10819 : base (requested_type, arguments, l)
10821 this.initializers = initializers;
10824 public CollectionOrObjectInitializers Initializers {
10826 return initializers;
10830 protected override void CloneTo (CloneContext clonectx, Expression t)
10832 base.CloneTo (clonectx, t);
10834 NewInitialize target = (NewInitialize) t;
10835 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
10838 public override bool ContainsEmitWithAwait ()
10840 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
10843 public override Expression CreateExpressionTree (ResolveContext ec)
10845 Arguments args = new Arguments (2);
10846 args.Add (new Argument (base.CreateExpressionTree (ec)));
10847 if (!initializers.IsEmpty)
10848 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
10850 return CreateExpressionFactoryCall (ec,
10851 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
10855 protected override Expression DoResolve (ResolveContext ec)
10857 Expression e = base.DoResolve (ec);
10861 if (type.IsDelegate) {
10862 ec.Report.Error (1958, Initializers.Location,
10863 "Object and collection initializers cannot be used to instantiate a delegate");
10866 Expression previous = ec.CurrentInitializerVariable;
10867 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
10868 initializers.Resolve (ec);
10869 ec.CurrentInitializerVariable = previous;
10871 dynamic = e as DynamicExpressionStatement;
10872 if (dynamic != null)
10878 public override bool Emit (EmitContext ec, IMemoryLocation target)
10880 bool left_on_stack;
10881 if (dynamic != null) {
10883 left_on_stack = true;
10885 left_on_stack = base.Emit (ec, target);
10888 if (initializers.IsEmpty)
10889 return left_on_stack;
10891 LocalTemporary temp = null;
10893 instance = target as LocalTemporary;
10895 if (instance == null) {
10896 if (!left_on_stack) {
10897 VariableReference vr = target as VariableReference;
10899 // FIXME: This still does not work correctly for pre-set variables
10900 if (vr != null && vr.IsRef)
10901 target.AddressOf (ec, AddressOp.Load);
10903 ((Expression) target).Emit (ec);
10904 left_on_stack = true;
10907 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
10908 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
10910 temp = new LocalTemporary (type);
10915 if (left_on_stack && temp != null)
10918 initializers.Emit (ec);
10920 if (left_on_stack) {
10921 if (temp != null) {
10925 ((Expression) instance).Emit (ec);
10929 return left_on_stack;
10932 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
10934 instance = base.EmitAddressOf (ec, Mode);
10936 if (!initializers.IsEmpty)
10937 initializers.Emit (ec);
10942 public override object Accept (StructuralVisitor visitor)
10944 return visitor.Visit (this);
10948 public class NewAnonymousType : New
10950 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
10952 List<AnonymousTypeParameter> parameters;
10953 readonly TypeContainer parent;
10954 AnonymousTypeClass anonymous_type;
10956 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
10957 : base (null, null, loc)
10959 this.parameters = parameters;
10960 this.parent = parent;
10963 public List<AnonymousTypeParameter> Parameters {
10965 return this.parameters;
10969 protected override void CloneTo (CloneContext clonectx, Expression target)
10971 if (parameters == null)
10974 NewAnonymousType t = (NewAnonymousType) target;
10975 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
10976 foreach (AnonymousTypeParameter atp in parameters)
10977 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
10980 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
10982 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
10986 type = AnonymousTypeClass.Create (parent, parameters, loc);
10990 int errors = ec.Report.Errors;
10991 type.CreateContainer ();
10992 type.DefineContainer ();
10994 if ((ec.Report.Errors - errors) == 0) {
10995 parent.Module.AddAnonymousType (type);
11001 public override Expression CreateExpressionTree (ResolveContext ec)
11003 if (parameters == null)
11004 return base.CreateExpressionTree (ec);
11006 var init = new ArrayInitializer (parameters.Count, loc);
11007 foreach (var m in anonymous_type.Members) {
11008 var p = m as Property;
11010 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
11013 var ctor_args = new ArrayInitializer (arguments.Count, loc);
11014 foreach (Argument a in arguments)
11015 ctor_args.Add (a.CreateExpressionTree (ec));
11017 Arguments args = new Arguments (3);
11018 args.Add (new Argument (new TypeOfMethod (method, loc)));
11019 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
11020 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
11022 return CreateExpressionFactoryCall (ec, "New", args);
11025 protected override Expression DoResolve (ResolveContext ec)
11027 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
11028 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
11032 if (parameters == null) {
11033 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
11034 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
11035 return base.DoResolve (ec);
11038 bool error = false;
11039 arguments = new Arguments (parameters.Count);
11040 var t_args = new TypeSpec [parameters.Count];
11041 for (int i = 0; i < parameters.Count; ++i) {
11042 Expression e = parameters [i].Resolve (ec);
11048 arguments.Add (new Argument (e));
11049 t_args [i] = e.Type;
11055 anonymous_type = CreateAnonymousType (ec, parameters);
11056 if (anonymous_type == null)
11059 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
11060 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
11061 eclass = ExprClass.Value;
11065 public override void EmitStatement (EmitContext ec)
11067 base.EmitStatement (ec);
11070 public override object Accept (StructuralVisitor visitor)
11072 return visitor.Visit (this);
11076 public class AnonymousTypeParameter : ShimExpression
11078 public readonly string Name;
11080 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
11081 : base (initializer)
11087 public AnonymousTypeParameter (Parameter parameter)
11088 : base (new SimpleName (parameter.Name, parameter.Location))
11090 this.Name = parameter.Name;
11091 this.loc = parameter.Location;
11094 public override bool Equals (object o)
11096 AnonymousTypeParameter other = o as AnonymousTypeParameter;
11097 return other != null && Name == other.Name;
11100 public override int GetHashCode ()
11102 return Name.GetHashCode ();
11105 protected override Expression DoResolve (ResolveContext ec)
11107 Expression e = expr.Resolve (ec);
11111 if (e.eclass == ExprClass.MethodGroup) {
11112 Error_InvalidInitializer (ec, e.ExprClassName);
11117 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
11118 Error_InvalidInitializer (ec, type.GetSignatureForError ());
11125 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
11127 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
11128 Name, initializer);