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 protected 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))
1510 // open generic type
1512 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1515 var tps = t as TypeParameterSpec;
1517 return ResolveGenericParameter (ec, d, tps);
1519 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1520 ec.Report.Warning (1981, 3, loc,
1521 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1522 OperatorName, t.GetSignatureForError ());
1525 if (TypeManager.IsGenericParameter (d))
1526 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1528 if (TypeSpec.IsValueType (d)) {
1529 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1530 if (d_is_nullable && !t_is_nullable) {
1531 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1535 return CreateConstantResult (ec, true);
1538 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1540 // Do not optimize for imported type
1542 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None)
1546 // Turn is check into simple null check for implicitly convertible reference types
1548 return ReducedExpression.Create (
1549 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1553 if (Convert.ExplicitReferenceConversionExists (d, t))
1557 // open generic type
1559 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1564 return CreateConstantResult (ec, false);
1567 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1569 if (t.IsReferenceType) {
1571 return CreateConstantResult (ec, false);
1574 if (expr.Type.IsGenericParameter) {
1575 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1576 return CreateConstantResult (ec, true);
1578 expr = new BoxedCast (expr, d);
1584 public override object Accept (StructuralVisitor visitor)
1586 return visitor.Visit (this);
1591 /// Implementation of the `as' operator.
1593 public class As : Probe {
1594 Expression resolved_type;
1596 public As (Expression expr, Expression probe_type, Location l)
1597 : base (expr, probe_type, l)
1601 protected override string OperatorName {
1602 get { return "as"; }
1605 public override Expression CreateExpressionTree (ResolveContext ec)
1607 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1608 expr.CreateExpressionTree (ec),
1609 new TypeOf (probe_type_expr, loc));
1611 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1614 public override void Emit (EmitContext ec)
1618 ec.Emit (OpCodes.Isinst, type);
1620 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1621 ec.Emit (OpCodes.Unbox_Any, type);
1624 protected override Expression DoResolve (ResolveContext ec)
1626 if (resolved_type == null) {
1627 resolved_type = base.DoResolve (ec);
1629 if (resolved_type == null)
1633 type = probe_type_expr;
1634 eclass = ExprClass.Value;
1635 TypeSpec etype = expr.Type;
1637 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1638 if (TypeManager.IsGenericParameter (type)) {
1639 ec.Report.Error (413, loc,
1640 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1641 probe_type_expr.GetSignatureForError ());
1643 ec.Report.Error (77, loc,
1644 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1645 type.GetSignatureForError ());
1650 if (expr.IsNull && type.IsNullableType) {
1651 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1654 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1655 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1659 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1661 e = EmptyCast.Create (e, type);
1662 return ReducedExpression.Create (e, this).Resolve (ec);
1665 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1666 if (TypeManager.IsGenericParameter (etype))
1667 expr = new BoxedCast (expr, etype);
1672 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1673 expr = new BoxedCast (expr, etype);
1677 if (etype != InternalType.ErrorType) {
1678 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1679 etype.GetSignatureForError (), type.GetSignatureForError ());
1685 public override object Accept (StructuralVisitor visitor)
1687 return visitor.Visit (this);
1692 // This represents a typecast in the source language.
1694 public class Cast : ShimExpression {
1695 Expression target_type;
1697 public Cast (Expression cast_type, Expression expr, Location loc)
1700 this.target_type = cast_type;
1704 public Expression TargetType {
1705 get { return target_type; }
1708 protected override Expression DoResolve (ResolveContext ec)
1710 expr = expr.Resolve (ec);
1714 type = target_type.ResolveAsType (ec);
1718 if (type.IsStatic) {
1719 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
1723 if (type.IsPointer && !ec.IsUnsafe) {
1724 UnsafeError (ec, loc);
1727 eclass = ExprClass.Value;
1729 Constant c = expr as Constant;
1731 c = c.Reduce (ec, type);
1736 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1738 return EmptyCast.Create (res, type);
1743 protected override void CloneTo (CloneContext clonectx, Expression t)
1745 Cast target = (Cast) t;
1747 target.target_type = target_type.Clone (clonectx);
1748 target.expr = expr.Clone (clonectx);
1751 public override object Accept (StructuralVisitor visitor)
1753 return visitor.Visit (this);
1757 public class ImplicitCast : ShimExpression
1761 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1764 this.loc = expr.Location;
1766 this.arrayAccess = arrayAccess;
1769 protected override Expression DoResolve (ResolveContext ec)
1771 expr = expr.Resolve (ec);
1776 expr = ConvertExpressionToArrayIndex (ec, expr);
1778 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1785 // C# 2.0 Default value expression
1787 public class DefaultValueExpression : Expression
1791 public DefaultValueExpression (Expression expr, Location loc)
1797 public Expression Expr {
1803 public override bool IsSideEffectFree {
1809 public override bool ContainsEmitWithAwait ()
1814 public override Expression CreateExpressionTree (ResolveContext ec)
1816 Arguments args = new Arguments (2);
1817 args.Add (new Argument (this));
1818 args.Add (new Argument (new TypeOf (type, loc)));
1819 return CreateExpressionFactoryCall (ec, "Constant", args);
1822 protected override Expression DoResolve (ResolveContext ec)
1824 type = expr.ResolveAsType (ec);
1828 if (type.IsStatic) {
1829 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1833 return new NullLiteral (Location).ConvertImplicitly (type);
1835 if (TypeSpec.IsReferenceType (type))
1836 return new NullConstant (type, loc);
1838 Constant c = New.Constantify (type, expr.Location);
1842 eclass = ExprClass.Variable;
1846 public override void Emit (EmitContext ec)
1848 LocalTemporary temp_storage = new LocalTemporary(type);
1850 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1851 ec.Emit(OpCodes.Initobj, type);
1852 temp_storage.Emit(ec);
1853 temp_storage.Release (ec);
1856 #if (NET_4_0 || MONODROID) && !STATIC
1857 public override SLE.Expression MakeExpression (BuilderContext ctx)
1859 return SLE.Expression.Default (type.GetMetaInfo ());
1863 protected override void CloneTo (CloneContext clonectx, Expression t)
1865 DefaultValueExpression target = (DefaultValueExpression) t;
1867 target.expr = expr.Clone (clonectx);
1870 public override object Accept (StructuralVisitor visitor)
1872 return visitor.Visit (this);
1877 /// Binary operators
1879 public class Binary : Expression, IDynamicBinder
1881 public class PredefinedOperator
1883 protected readonly TypeSpec left;
1884 protected readonly TypeSpec right;
1885 protected readonly TypeSpec left_unwrap;
1886 protected readonly TypeSpec right_unwrap;
1887 public readonly Operator OperatorsMask;
1888 public TypeSpec ReturnType;
1890 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1891 : this (ltype, rtype, op_mask, ltype)
1895 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1896 : this (type, type, op_mask, return_type)
1900 public PredefinedOperator (TypeSpec type, Operator op_mask)
1901 : this (type, type, op_mask, type)
1905 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1907 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1908 throw new InternalErrorException ("Only masked values can be used");
1910 if ((op_mask & Operator.NullableMask) != 0) {
1911 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
1912 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
1914 left_unwrap = ltype;
1915 right_unwrap = rtype;
1920 this.OperatorsMask = op_mask;
1921 this.ReturnType = return_type;
1924 public bool IsLifted {
1926 return (OperatorsMask & Operator.NullableMask) != 0;
1930 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
1934 var left_expr = b.left;
1935 var right_expr = b.right;
1937 b.type = ReturnType;
1940 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
1941 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1942 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1945 if (right_expr.IsNull) {
1946 if ((b.oper & Operator.EqualityMask) != 0) {
1947 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
1948 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
1949 } else if ((b.oper & Operator.BitwiseMask) != 0) {
1950 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
1951 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1953 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1954 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1956 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
1957 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1959 return b.CreateLiftedValueTypeResult (rc, left);
1961 } else if (left_expr.IsNull) {
1962 if ((b.oper & Operator.EqualityMask) != 0) {
1963 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
1964 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
1965 } else if ((b.oper & Operator.BitwiseMask) != 0) {
1966 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
1967 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1969 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1970 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1972 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
1973 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1975 return b.CreateLiftedValueTypeResult (rc, right);
1981 // A user operators does not support multiple user conversions, but decimal type
1982 // is considered to be predefined type therefore we apply predefined operators rules
1983 // and then look for decimal user-operator implementation
1985 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
1986 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1987 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1989 return b.ResolveUserOperator (rc, b.left, b.right);
1992 c = right_expr as Constant;
1994 if (c.IsDefaultValue) {
1998 // (expr + 0) to expr
1999 // (expr - 0) to expr
2000 // (bool? | false) to bool?
2002 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2003 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2004 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2005 return ReducedExpression.Create (b.left, b).Resolve (rc);
2011 // (bool? & true) to bool?
2013 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2014 return ReducedExpression.Create (b.left, b).Resolve (rc);
2018 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2019 return ReducedExpression.Create (b.left, b).Resolve (rc);
2021 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2022 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2026 c = b.left as Constant;
2028 if (c.IsDefaultValue) {
2032 // (0 + expr) to expr
2033 // (false | bool?) to bool?
2035 if (b.oper == Operator.Addition ||
2036 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2037 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2038 return ReducedExpression.Create (b.right, b).Resolve (rc);
2044 // (true & bool?) to bool?
2046 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2047 return ReducedExpression.Create (b.right, b).Resolve (rc);
2051 if (b.oper == Operator.Multiply && c.IsOneInteger)
2052 return ReducedExpression.Create (b.right, b).Resolve (rc);
2056 var lifted = new Nullable.LiftedBinaryOperator (b);
2058 TypeSpec ltype, rtype;
2059 if (b.left.Type.IsNullableType) {
2060 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2061 ltype = left_unwrap;
2066 if (b.right.Type.IsNullableType) {
2067 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2068 rtype = right_unwrap;
2073 lifted.Left = b.left.IsNull ?
2075 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2077 lifted.Right = b.right.IsNull ?
2079 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2081 return lifted.Resolve (rc);
2084 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2085 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2090 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2093 // We are dealing with primitive types only
2095 return left == ltype && ltype == rtype;
2098 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2101 if (left == lexpr.Type && right == rexpr.Type)
2104 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2105 Convert.ImplicitConversionExists (ec, rexpr, right);
2108 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2110 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2111 return best_operator;
2113 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2117 if (left != null && best_operator.left != null) {
2118 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2122 // When second argument is same as the first one, the result is same
2124 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2125 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2128 if (result == 0 || result > 2)
2131 return result == 1 ? best_operator : this;
2135 sealed class PredefinedStringOperator : PredefinedOperator
2137 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2138 : base (type, type, op_mask, retType)
2142 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2143 : base (ltype, rtype, op_mask, retType)
2147 public override Expression ConvertResult (ResolveContext ec, Binary b)
2150 // Use original expression for nullable arguments
2152 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2154 b.left = unwrap.Original;
2156 unwrap = b.right as Nullable.Unwrap;
2158 b.right = unwrap.Original;
2160 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2161 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2164 // Start a new concat expression using converted expression
2166 return StringConcat.Create (ec, b.left, b.right, b.loc);
2170 sealed class PredefinedEqualityOperator : PredefinedOperator
2172 MethodSpec equal_method, inequal_method;
2174 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
2175 : base (arg, arg, Operator.EqualityMask, retType)
2179 public override Expression ConvertResult (ResolveContext ec, Binary b)
2181 b.type = ReturnType;
2183 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2184 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2186 Arguments args = new Arguments (2);
2187 args.Add (new Argument (b.left));
2188 args.Add (new Argument (b.right));
2191 if (b.oper == Operator.Equality) {
2192 if (equal_method == null) {
2193 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2194 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2195 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2196 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2198 throw new NotImplementedException (left.GetSignatureForError ());
2201 method = equal_method;
2203 if (inequal_method == null) {
2204 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2205 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2206 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2207 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2209 throw new NotImplementedException (left.GetSignatureForError ());
2212 method = inequal_method;
2215 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2219 class PredefinedPointerOperator : PredefinedOperator
2221 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2222 : base (ltype, rtype, op_mask)
2226 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2227 : base (ltype, rtype, op_mask, retType)
2231 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2232 : base (type, op_mask, return_type)
2236 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2239 if (!lexpr.Type.IsPointer)
2242 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2246 if (right == null) {
2247 if (!rexpr.Type.IsPointer)
2250 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2257 public override Expression ConvertResult (ResolveContext ec, Binary b)
2260 b.left = EmptyCast.Create (b.left, left);
2261 } else if (right != null) {
2262 b.right = EmptyCast.Create (b.right, right);
2265 TypeSpec r_type = ReturnType;
2266 Expression left_arg, right_arg;
2267 if (r_type == null) {
2270 right_arg = b.right;
2271 r_type = b.left.Type;
2275 r_type = b.right.Type;
2279 right_arg = b.right;
2282 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2287 public enum Operator {
2288 Multiply = 0 | ArithmeticMask,
2289 Division = 1 | ArithmeticMask,
2290 Modulus = 2 | ArithmeticMask,
2291 Addition = 3 | ArithmeticMask | AdditionMask,
2292 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2294 LeftShift = 5 | ShiftMask,
2295 RightShift = 6 | ShiftMask,
2297 LessThan = 7 | ComparisonMask | RelationalMask,
2298 GreaterThan = 8 | ComparisonMask | RelationalMask,
2299 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2300 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2301 Equality = 11 | ComparisonMask | EqualityMask,
2302 Inequality = 12 | ComparisonMask | EqualityMask,
2304 BitwiseAnd = 13 | BitwiseMask,
2305 ExclusiveOr = 14 | BitwiseMask,
2306 BitwiseOr = 15 | BitwiseMask,
2308 LogicalAnd = 16 | LogicalMask,
2309 LogicalOr = 17 | LogicalMask,
2314 ValuesOnlyMask = ArithmeticMask - 1,
2315 ArithmeticMask = 1 << 5,
2317 ComparisonMask = 1 << 7,
2318 EqualityMask = 1 << 8,
2319 BitwiseMask = 1 << 9,
2320 LogicalMask = 1 << 10,
2321 AdditionMask = 1 << 11,
2322 SubtractionMask = 1 << 12,
2323 RelationalMask = 1 << 13,
2325 DecomposedMask = 1 << 19,
2326 NullableMask = 1 << 20,
2336 readonly Operator oper;
2337 Expression left, right;
2339 ConvCast.Mode enum_conversion;
2341 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
2342 : this (oper, left, right)
2345 state |= State.Compound;
2348 public Binary (Operator oper, Expression left, Expression right)
2353 this.loc = left.Location;
2358 public bool IsCompound {
2360 return (state & State.Compound) != 0;
2364 public Operator Oper {
2370 public Expression Left {
2376 public Expression Right {
2382 public override Location StartLocation {
2384 return left.StartLocation;
2391 /// Returns a stringified representation of the Operator
2393 string OperName (Operator oper)
2397 case Operator.Multiply:
2400 case Operator.Division:
2403 case Operator.Modulus:
2406 case Operator.Addition:
2409 case Operator.Subtraction:
2412 case Operator.LeftShift:
2415 case Operator.RightShift:
2418 case Operator.LessThan:
2421 case Operator.GreaterThan:
2424 case Operator.LessThanOrEqual:
2427 case Operator.GreaterThanOrEqual:
2430 case Operator.Equality:
2433 case Operator.Inequality:
2436 case Operator.BitwiseAnd:
2439 case Operator.BitwiseOr:
2442 case Operator.ExclusiveOr:
2445 case Operator.LogicalOr:
2448 case Operator.LogicalAnd:
2452 s = oper.ToString ();
2462 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2464 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2467 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2469 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
2473 l = left.Type.GetSignatureForError ();
2474 r = right.Type.GetSignatureForError ();
2476 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2480 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2482 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2486 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2488 string GetOperatorExpressionTypeName ()
2491 case Operator.Addition:
2492 return IsCompound ? "AddAssign" : "Add";
2493 case Operator.BitwiseAnd:
2494 return IsCompound ? "AndAssign" : "And";
2495 case Operator.BitwiseOr:
2496 return IsCompound ? "OrAssign" : "Or";
2497 case Operator.Division:
2498 return IsCompound ? "DivideAssign" : "Divide";
2499 case Operator.ExclusiveOr:
2500 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2501 case Operator.Equality:
2503 case Operator.GreaterThan:
2504 return "GreaterThan";
2505 case Operator.GreaterThanOrEqual:
2506 return "GreaterThanOrEqual";
2507 case Operator.Inequality:
2509 case Operator.LeftShift:
2510 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2511 case Operator.LessThan:
2513 case Operator.LessThanOrEqual:
2514 return "LessThanOrEqual";
2515 case Operator.LogicalAnd:
2517 case Operator.LogicalOr:
2519 case Operator.Modulus:
2520 return IsCompound ? "ModuloAssign" : "Modulo";
2521 case Operator.Multiply:
2522 return IsCompound ? "MultiplyAssign" : "Multiply";
2523 case Operator.RightShift:
2524 return IsCompound ? "RightShiftAssign" : "RightShift";
2525 case Operator.Subtraction:
2526 return IsCompound ? "SubtractAssign" : "Subtract";
2528 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2532 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2535 case Operator.Addition:
2536 return CSharp.Operator.OpType.Addition;
2537 case Operator.BitwiseAnd:
2538 case Operator.LogicalAnd:
2539 return CSharp.Operator.OpType.BitwiseAnd;
2540 case Operator.BitwiseOr:
2541 case Operator.LogicalOr:
2542 return CSharp.Operator.OpType.BitwiseOr;
2543 case Operator.Division:
2544 return CSharp.Operator.OpType.Division;
2545 case Operator.Equality:
2546 return CSharp.Operator.OpType.Equality;
2547 case Operator.ExclusiveOr:
2548 return CSharp.Operator.OpType.ExclusiveOr;
2549 case Operator.GreaterThan:
2550 return CSharp.Operator.OpType.GreaterThan;
2551 case Operator.GreaterThanOrEqual:
2552 return CSharp.Operator.OpType.GreaterThanOrEqual;
2553 case Operator.Inequality:
2554 return CSharp.Operator.OpType.Inequality;
2555 case Operator.LeftShift:
2556 return CSharp.Operator.OpType.LeftShift;
2557 case Operator.LessThan:
2558 return CSharp.Operator.OpType.LessThan;
2559 case Operator.LessThanOrEqual:
2560 return CSharp.Operator.OpType.LessThanOrEqual;
2561 case Operator.Modulus:
2562 return CSharp.Operator.OpType.Modulus;
2563 case Operator.Multiply:
2564 return CSharp.Operator.OpType.Multiply;
2565 case Operator.RightShift:
2566 return CSharp.Operator.OpType.RightShift;
2567 case Operator.Subtraction:
2568 return CSharp.Operator.OpType.Subtraction;
2570 throw new InternalErrorException (op.ToString ());
2574 public override bool ContainsEmitWithAwait ()
2576 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2579 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
2584 case Operator.Multiply:
2585 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2586 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2587 opcode = OpCodes.Mul_Ovf;
2588 else if (!IsFloat (l))
2589 opcode = OpCodes.Mul_Ovf_Un;
2591 opcode = OpCodes.Mul;
2593 opcode = OpCodes.Mul;
2597 case Operator.Division:
2599 opcode = OpCodes.Div_Un;
2601 opcode = OpCodes.Div;
2604 case Operator.Modulus:
2606 opcode = OpCodes.Rem_Un;
2608 opcode = OpCodes.Rem;
2611 case Operator.Addition:
2612 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2613 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2614 opcode = OpCodes.Add_Ovf;
2615 else if (!IsFloat (l))
2616 opcode = OpCodes.Add_Ovf_Un;
2618 opcode = OpCodes.Add;
2620 opcode = OpCodes.Add;
2623 case Operator.Subtraction:
2624 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2625 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2626 opcode = OpCodes.Sub_Ovf;
2627 else if (!IsFloat (l))
2628 opcode = OpCodes.Sub_Ovf_Un;
2630 opcode = OpCodes.Sub;
2632 opcode = OpCodes.Sub;
2635 case Operator.RightShift:
2636 if (!(right is IntConstant)) {
2637 ec.EmitInt (GetShiftMask (l));
2638 ec.Emit (OpCodes.And);
2642 opcode = OpCodes.Shr_Un;
2644 opcode = OpCodes.Shr;
2647 case Operator.LeftShift:
2648 if (!(right is IntConstant)) {
2649 ec.EmitInt (GetShiftMask (l));
2650 ec.Emit (OpCodes.And);
2653 opcode = OpCodes.Shl;
2656 case Operator.Equality:
2657 opcode = OpCodes.Ceq;
2660 case Operator.Inequality:
2661 ec.Emit (OpCodes.Ceq);
2664 opcode = OpCodes.Ceq;
2667 case Operator.LessThan:
2669 opcode = OpCodes.Clt_Un;
2671 opcode = OpCodes.Clt;
2674 case Operator.GreaterThan:
2676 opcode = OpCodes.Cgt_Un;
2678 opcode = OpCodes.Cgt;
2681 case Operator.LessThanOrEqual:
2682 if (IsUnsigned (l) || IsFloat (l))
2683 ec.Emit (OpCodes.Cgt_Un);
2685 ec.Emit (OpCodes.Cgt);
2688 opcode = OpCodes.Ceq;
2691 case Operator.GreaterThanOrEqual:
2692 if (IsUnsigned (l) || IsFloat (l))
2693 ec.Emit (OpCodes.Clt_Un);
2695 ec.Emit (OpCodes.Clt);
2699 opcode = OpCodes.Ceq;
2702 case Operator.BitwiseOr:
2703 opcode = OpCodes.Or;
2706 case Operator.BitwiseAnd:
2707 opcode = OpCodes.And;
2710 case Operator.ExclusiveOr:
2711 opcode = OpCodes.Xor;
2715 throw new InternalErrorException (oper.ToString ());
2721 static int GetShiftMask (TypeSpec type)
2723 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
2726 static bool IsUnsigned (TypeSpec t)
2728 switch (t.BuiltinType) {
2729 case BuiltinTypeSpec.Type.Char:
2730 case BuiltinTypeSpec.Type.UInt:
2731 case BuiltinTypeSpec.Type.ULong:
2732 case BuiltinTypeSpec.Type.UShort:
2733 case BuiltinTypeSpec.Type.Byte:
2740 static bool IsFloat (TypeSpec t)
2742 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2745 public Expression ResolveOperator (ResolveContext rc)
2747 eclass = ExprClass.Value;
2749 TypeSpec l = left.Type;
2750 TypeSpec r = right.Type;
2752 bool primitives_only = false;
2755 // Handles predefined primitive types
2757 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
2758 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
2759 if ((oper & Operator.ShiftMask) == 0) {
2760 if (!DoBinaryOperatorPromotion (rc))
2763 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
2767 if (l.IsPointer || r.IsPointer)
2768 return ResolveOperatorPointer (rc, l, r);
2771 expr = ResolveUserOperator (rc, left, right);
2776 bool lenum = l.IsEnum;
2777 bool renum = r.IsEnum;
2778 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2782 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2783 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
2788 if ((oper & Operator.BitwiseMask) != 0) {
2789 expr = EmptyCast.Create (expr, type);
2790 AddEnumResultCast (type);
2792 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
2793 expr = OptimizeAndOperation (expr);
2797 left = ConvertEnumOperandToUnderlyingType (rc, left);
2798 right = ConvertEnumOperandToUnderlyingType (rc, right);
2801 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
2802 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2806 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
2809 // We cannot break here there is also Enum + String possible match
2810 // which is not ambiguous with predefined enum operators
2813 left = ConvertEnumOperandToUnderlyingType (rc, left);
2814 right = ConvertEnumOperandToUnderlyingType (rc, right);
2818 } else if (l.IsDelegate || r.IsDelegate) {
2822 expr = ResolveOperatorDelegate (rc, l, r);
2824 // TODO: Can this be ambiguous
2832 // Equality operators are more complicated
2834 if ((oper & Operator.EqualityMask) != 0) {
2835 return ResolveEquality (rc, l, r, primitives_only);
2838 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
2842 if (primitives_only)
2846 // Lifted operators have lower priority
2848 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
2851 static bool IsEnumOrNullableEnum (TypeSpec type)
2853 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
2857 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2858 // if 'left' is not an enumeration constant, create one from the type of 'right'
2859 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
2862 case Operator.BitwiseOr:
2863 case Operator.BitwiseAnd:
2864 case Operator.ExclusiveOr:
2865 case Operator.Equality:
2866 case Operator.Inequality:
2867 case Operator.LessThan:
2868 case Operator.LessThanOrEqual:
2869 case Operator.GreaterThan:
2870 case Operator.GreaterThanOrEqual:
2871 if (left.Type.IsEnum)
2874 if (left.IsZeroInteger)
2875 return left.Reduce (ec, right.Type);
2879 case Operator.Addition:
2880 case Operator.Subtraction:
2883 case Operator.Multiply:
2884 case Operator.Division:
2885 case Operator.Modulus:
2886 case Operator.LeftShift:
2887 case Operator.RightShift:
2888 if (right.Type.IsEnum || left.Type.IsEnum)
2897 // The `|' operator used on types which were extended is dangerous
2899 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2901 OpcodeCast lcast = left as OpcodeCast;
2902 if (lcast != null) {
2903 if (IsUnsigned (lcast.UnderlyingType))
2907 OpcodeCast rcast = right as OpcodeCast;
2908 if (rcast != null) {
2909 if (IsUnsigned (rcast.UnderlyingType))
2913 if (lcast == null && rcast == null)
2916 // FIXME: consider constants
2918 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
2919 ec.Report.Warning (675, 3, loc,
2920 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2921 ltype.GetSignatureForError ());
2924 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
2926 return new PredefinedOperator[] {
2928 // Pointer arithmetic:
2930 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2931 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2932 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2933 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2935 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
2936 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
2937 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
2938 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
2941 // T* operator + (int y, T* x);
2942 // T* operator + (uint y, T *x);
2943 // T* operator + (long y, T *x);
2944 // T* operator + (ulong y, T *x);
2946 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
2947 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
2948 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
2949 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
2952 // long operator - (T* x, T *y)
2954 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
2958 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
2960 TypeSpec bool_type = types.Bool;
2963 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
2964 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
2965 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
2966 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
2967 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
2968 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
2969 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
2971 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
2972 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
2973 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
2974 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
2975 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
2976 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
2977 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
2979 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
2980 // Remaining string operators are in lifted tables
2982 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
2984 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
2985 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
2986 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
2990 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
2992 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
2993 if (nullable == null)
2994 return new PredefinedOperator [0];
2996 var types = module.Compiler.BuiltinTypes;
2997 var bool_type = types.Bool;
2999 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3000 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3001 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3002 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3003 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3004 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3005 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3006 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3009 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3010 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3011 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3012 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3013 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3014 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3015 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3017 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3018 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3019 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3020 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3021 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3022 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3023 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3025 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3027 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3028 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3029 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3032 // Not strictly lifted but need to be in second group otherwise expressions like
3033 // int + null would resolve to +(object, string) instead of +(int?, int?)
3035 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3036 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3041 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3043 TypeSpec bool_type = types.Bool;
3046 new PredefinedEqualityOperator (types.String, bool_type),
3047 new PredefinedEqualityOperator (types.Delegate, bool_type),
3048 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3049 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3050 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3051 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3052 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3053 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3054 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3055 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3059 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3061 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3063 if (nullable == null)
3064 return new PredefinedOperator [0];
3066 var types = module.Compiler.BuiltinTypes;
3067 var bool_type = types.Bool;
3068 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3069 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3070 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3071 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3072 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3073 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3074 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3075 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3078 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3079 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3080 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3081 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3082 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3083 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3084 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3085 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3090 // 7.2.6.2 Binary numeric promotions
3092 bool DoBinaryOperatorPromotion (ResolveContext rc)
3094 TypeSpec ltype = left.Type;
3095 if (ltype.IsNullableType) {
3096 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
3100 // This is numeric promotion code only
3102 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
3105 TypeSpec rtype = right.Type;
3106 if (rtype.IsNullableType) {
3107 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
3110 var lb = ltype.BuiltinType;
3111 var rb = rtype.BuiltinType;
3115 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
3116 type = rc.BuiltinTypes.Decimal;
3117 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
3118 type = rc.BuiltinTypes.Double;
3119 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
3120 type = rc.BuiltinTypes.Float;
3121 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
3122 type = rc.BuiltinTypes.ULong;
3124 if (IsSignedType (lb)) {
3125 expr = ConvertSignedConstant (left, type);
3129 } else if (IsSignedType (rb)) {
3130 expr = ConvertSignedConstant (right, type);
3136 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
3137 type = rc.BuiltinTypes.Long;
3138 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
3139 type = rc.BuiltinTypes.UInt;
3141 if (IsSignedType (lb)) {
3142 expr = ConvertSignedConstant (left, type);
3144 type = rc.BuiltinTypes.Long;
3145 } else if (IsSignedType (rb)) {
3146 expr = ConvertSignedConstant (right, type);
3148 type = rc.BuiltinTypes.Long;
3151 type = rc.BuiltinTypes.Int;
3154 if (ltype != type) {
3155 expr = PromoteExpression (rc, left, type);
3162 if (rtype != type) {
3163 expr = PromoteExpression (rc, right, type);
3173 static bool IsSignedType (BuiltinTypeSpec.Type type)
3176 case BuiltinTypeSpec.Type.Int:
3177 case BuiltinTypeSpec.Type.Short:
3178 case BuiltinTypeSpec.Type.SByte:
3179 case BuiltinTypeSpec.Type.Long:
3186 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
3188 var c = expr as Constant;
3192 return c.ConvertImplicitly (type);
3195 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
3197 if (expr.Type.IsNullableType) {
3198 return Convert.ImplicitConversionStandard (rc, expr,
3199 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
3202 var c = expr as Constant;
3204 return c.ConvertImplicitly (type);
3206 return Convert.ImplicitNumericConversion (expr, type);
3209 protected override Expression DoResolve (ResolveContext ec)
3214 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
3215 left = ((ParenthesizedExpression) left).Expr;
3216 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
3220 if (left.eclass == ExprClass.Type) {
3221 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
3225 left = left.Resolve (ec);
3230 Constant lc = left as Constant;
3232 if (lc != null && lc.Type.BuiltinType == BuiltinTypeSpec.Type.Bool &&
3233 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
3234 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
3236 // FIXME: resolve right expression as unreachable
3237 // right.Resolve (ec);
3239 ec.Report.Warning (429, 4, right.StartLocation, "Unreachable expression code detected");
3243 right = right.Resolve (ec);
3247 Constant rc = right as Constant;
3249 // The conversion rules are ignored in enum context but why
3250 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
3251 lc = EnumLiftUp (ec, lc, rc);
3253 rc = EnumLiftUp (ec, rc, lc);
3256 if (rc != null && lc != null) {
3257 int prev_e = ec.Report.Errors;
3258 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
3259 if (e != null || ec.Report.Errors != prev_e)
3263 // Comparison warnings
3264 if ((oper & Operator.ComparisonMask) != 0) {
3265 if (left.Equals (right)) {
3266 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
3268 CheckOutOfRangeComparison (ec, lc, right.Type);
3269 CheckOutOfRangeComparison (ec, rc, left.Type);
3272 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3273 return DoResolveDynamic (ec);
3275 return DoResolveCore (ec, left, right);
3278 Expression DoResolveDynamic (ResolveContext rc)
3281 var rt = right.Type;
3282 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
3283 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
3284 Error_OperatorCannotBeApplied (rc, left, right);
3291 // Special handling for logical boolean operators which require rhs not to be
3292 // evaluated based on lhs value
3294 if ((oper & Operator.LogicalMask) != 0) {
3295 Expression cond_left, cond_right, expr;
3297 args = new Arguments (2);
3299 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3300 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
3302 var cond_args = new Arguments (1);
3303 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
3306 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
3307 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
3309 left = temp.CreateReferenceExpression (rc, loc);
3310 if (oper == Operator.LogicalAnd) {
3311 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
3314 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
3318 args.Add (new Argument (left));
3319 args.Add (new Argument (right));
3320 cond_right = new DynamicExpressionStatement (this, args, loc);
3322 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
3324 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
3325 args.Add (new Argument (right));
3326 right = new DynamicExpressionStatement (this, args, loc);
3329 // bool && dynamic => (temp = left) ? temp && right : temp;
3330 // bool || dynamic => (temp = left) ? temp : temp || right;
3332 if (oper == Operator.LogicalAnd) {
3334 cond_right = temp.CreateReferenceExpression (rc, loc);
3336 cond_left = temp.CreateReferenceExpression (rc, loc);
3340 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
3343 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
3346 args = new Arguments (2);
3347 args.Add (new Argument (left));
3348 args.Add (new Argument (right));
3349 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
3352 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3354 Expression expr = ResolveOperator (ec);
3356 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3358 if (left == null || right == null)
3359 throw new InternalErrorException ("Invalid conversion");
3361 if (oper == Operator.BitwiseOr)
3362 CheckBitwiseOrOnSignExtended (ec);
3367 public override SLE.Expression MakeExpression (BuilderContext ctx)
3369 return MakeExpression (ctx, left, right);
3372 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
3374 var le = left.MakeExpression (ctx);
3375 var re = right.MakeExpression (ctx);
3376 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3379 case Operator.Addition:
3380 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3381 case Operator.BitwiseAnd:
3382 return SLE.Expression.And (le, re);
3383 case Operator.BitwiseOr:
3384 return SLE.Expression.Or (le, re);
3385 case Operator.Division:
3386 return SLE.Expression.Divide (le, re);
3387 case Operator.Equality:
3388 return SLE.Expression.Equal (le, re);
3389 case Operator.ExclusiveOr:
3390 return SLE.Expression.ExclusiveOr (le, re);
3391 case Operator.GreaterThan:
3392 return SLE.Expression.GreaterThan (le, re);
3393 case Operator.GreaterThanOrEqual:
3394 return SLE.Expression.GreaterThanOrEqual (le, re);
3395 case Operator.Inequality:
3396 return SLE.Expression.NotEqual (le, re);
3397 case Operator.LeftShift:
3398 return SLE.Expression.LeftShift (le, re);
3399 case Operator.LessThan:
3400 return SLE.Expression.LessThan (le, re);
3401 case Operator.LessThanOrEqual:
3402 return SLE.Expression.LessThanOrEqual (le, re);
3403 case Operator.LogicalAnd:
3404 return SLE.Expression.AndAlso (le, re);
3405 case Operator.LogicalOr:
3406 return SLE.Expression.OrElse (le, re);
3407 case Operator.Modulus:
3408 return SLE.Expression.Modulo (le, re);
3409 case Operator.Multiply:
3410 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3411 case Operator.RightShift:
3412 return SLE.Expression.RightShift (le, re);
3413 case Operator.Subtraction:
3414 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3416 throw new NotImplementedException (oper.ToString ());
3421 // D operator + (D x, D y)
3422 // D operator - (D x, D y)
3424 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3426 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3428 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3429 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3434 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3435 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3445 MethodSpec method = null;
3446 Arguments args = new Arguments (2);
3447 args.Add (new Argument (left));
3448 args.Add (new Argument (right));
3450 if (oper == Operator.Addition) {
3451 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3452 } else if (oper == Operator.Subtraction) {
3453 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3457 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3459 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
3460 return new ClassCast (expr, l);
3464 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
3466 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3469 // bool operator == (E x, E y);
3470 // bool operator != (E x, E y);
3471 // bool operator < (E x, E y);
3472 // bool operator > (E x, E y);
3473 // bool operator <= (E x, E y);
3474 // bool operator >= (E x, E y);
3476 // E operator & (E x, E y);
3477 // E operator | (E x, E y);
3478 // E operator ^ (E x, E y);
3481 if ((oper & Operator.ComparisonMask) != 0) {
3482 type = rc.BuiltinTypes.Bool;
3488 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3494 if (ltype == rtype) {
3498 var lifted = new Nullable.LiftedBinaryOperator (this);
3500 lifted.Right = right;
3501 return lifted.Resolve (rc);
3504 if (renum && !ltype.IsNullableType) {
3505 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
3510 } else if (lenum && !rtype.IsNullableType) {
3511 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
3519 // Now try lifted version of predefined operator
3521 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
3522 if (nullable_type != null) {
3523 if (renum && !ltype.IsNullableType) {
3524 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
3526 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3529 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3532 if ((oper & Operator.BitwiseMask) != 0)
3536 if ((oper & Operator.BitwiseMask) != 0)
3537 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3539 return CreateLiftedValueTypeResult (rc, rtype);
3543 var lifted = new Nullable.LiftedBinaryOperator (this);
3545 lifted.Right = right;
3546 return lifted.Resolve (rc);
3548 } else if (lenum && !rtype.IsNullableType) {
3549 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
3551 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3554 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3557 if ((oper & Operator.BitwiseMask) != 0)
3561 if ((oper & Operator.BitwiseMask) != 0)
3562 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3564 return CreateLiftedValueTypeResult (rc, ltype);
3568 var lifted = new Nullable.LiftedBinaryOperator (this);
3570 lifted.Right = expr;
3571 return lifted.Resolve (rc);
3573 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
3575 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3576 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
3578 if ((oper & Operator.RelationalMask) != 0)
3579 return CreateLiftedValueTypeResult (rc, rtype);
3581 if ((oper & Operator.BitwiseMask) != 0)
3582 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3584 // Equality operators are valid between E? and null
3587 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
3593 var lifted = new Nullable.LiftedBinaryOperator (this);
3595 lifted.Right = right;
3596 return lifted.Resolve (rc);
3598 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
3600 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3601 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
3603 if ((oper & Operator.RelationalMask) != 0)
3604 return CreateLiftedValueTypeResult (rc, ltype);
3606 if ((oper & Operator.BitwiseMask) != 0)
3607 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3609 // Equality operators are valid between E? and null
3612 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
3618 var lifted = new Nullable.LiftedBinaryOperator (this);
3620 lifted.Right = expr;
3621 return lifted.Resolve (rc);
3629 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr)
3631 TypeSpec underlying_type;
3632 if (expr.Type.IsNullableType) {
3633 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
3635 underlying_type = EnumSpec.GetUnderlyingType (nt);
3637 underlying_type = nt;
3638 } else if (expr.Type.IsEnum) {
3639 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
3641 underlying_type = expr.Type;
3644 switch (underlying_type.BuiltinType) {
3645 case BuiltinTypeSpec.Type.SByte:
3646 case BuiltinTypeSpec.Type.Byte:
3647 case BuiltinTypeSpec.Type.Short:
3648 case BuiltinTypeSpec.Type.UShort:
3649 underlying_type = rc.BuiltinTypes.Int;
3653 if (expr.Type.IsNullableType)
3654 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
3656 if (expr.Type == underlying_type)
3659 return EmptyCast.Create (expr, underlying_type);
3662 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3665 // U operator - (E e, E f)
3666 // E operator - (E e, U x) // Internal decomposition operator
3667 // E operator - (U x, E e) // Internal decomposition operator
3669 // E operator + (E e, U x)
3670 // E operator + (U x, E e)
3679 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3685 if (!enum_type.IsNullableType) {
3686 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
3688 if (oper == Operator.Subtraction)
3689 expr = ConvertEnumSubtractionResult (rc, expr);
3691 expr = ConvertEnumAdditionalResult (expr, enum_type);
3693 AddEnumResultCast (expr.Type);
3698 enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
3701 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
3703 if (oper == Operator.Subtraction)
3704 expr = ConvertEnumSubtractionResult (rc, expr);
3706 expr = ConvertEnumAdditionalResult (expr, enum_type);
3708 AddEnumResultCast (expr.Type);
3714 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
3716 return EmptyCast.Create (expr, enumType);
3719 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
3722 // Enumeration subtraction has different result type based on
3725 TypeSpec result_type;
3726 if (left.Type == right.Type) {
3727 var c = right as EnumConstant;
3728 if (c != null && c.IsZeroInteger) {
3730 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
3731 // E which is not what expressions E - 1 or 0 - E return
3733 result_type = left.Type;
3735 result_type = left.Type.IsNullableType ?
3736 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
3737 EnumSpec.GetUnderlyingType (left.Type);
3740 if (IsEnumOrNullableEnum (left.Type)) {
3741 result_type = left.Type;
3743 result_type = right.Type;
3746 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
3747 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
3750 return EmptyCast.Create (expr, result_type);
3753 void AddEnumResultCast (TypeSpec type)
3755 if (type.IsNullableType)
3756 type = Nullable.NullableInfo.GetUnderlyingType (type);
3759 type = EnumSpec.GetUnderlyingType (type);
3761 switch (type.BuiltinType) {
3762 case BuiltinTypeSpec.Type.SByte:
3763 enum_conversion = ConvCast.Mode.I4_I1;
3765 case BuiltinTypeSpec.Type.Byte:
3766 enum_conversion = ConvCast.Mode.I4_U1;
3768 case BuiltinTypeSpec.Type.Short:
3769 enum_conversion = ConvCast.Mode.I4_I2;
3771 case BuiltinTypeSpec.Type.UShort:
3772 enum_conversion = ConvCast.Mode.I4_U2;
3778 // Equality operators rules
3780 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
3783 type = ec.BuiltinTypes.Bool;
3784 bool no_arg_conv = false;
3786 if (!primitives_only) {
3789 // a, Both operands are reference-type values or the value null
3790 // b, One operand is a value of type T where T is a type-parameter and
3791 // the other operand is the value null. Furthermore T does not have the
3792 // value type constraint
3794 // LAMESPEC: Very confusing details in the specification, basically any
3795 // reference like type-parameter is allowed
3797 var tparam_l = l as TypeParameterSpec;
3798 var tparam_r = r as TypeParameterSpec;
3799 if (tparam_l != null) {
3800 if (right is NullLiteral) {
3801 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3804 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3808 if (!tparam_l.IsReferenceType)
3811 l = tparam_l.GetEffectiveBase ();
3812 left = new BoxedCast (left, l);
3813 } else if (left is NullLiteral && tparam_r == null) {
3814 if (TypeSpec.IsReferenceType (r))
3817 if (r.Kind == MemberKind.InternalCompilerType)
3821 if (tparam_r != null) {
3822 if (left is NullLiteral) {
3823 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3826 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3830 if (!tparam_r.IsReferenceType)
3833 r = tparam_r.GetEffectiveBase ();
3834 right = new BoxedCast (right, r);
3835 } else if (right is NullLiteral) {
3836 if (TypeSpec.IsReferenceType (l))
3839 if (l.Kind == MemberKind.InternalCompilerType)
3844 // LAMESPEC: method groups can be compared when they convert to other side delegate
3847 if (right.eclass == ExprClass.MethodGroup) {
3848 result = Convert.ImplicitConversion (ec, right, l, loc);
3854 } else if (r.IsDelegate && l != r) {
3857 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3858 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3865 no_arg_conv = l == r && !l.IsStruct;
3870 // bool operator != (string a, string b)
3871 // bool operator == (string a, string b)
3873 // bool operator != (Delegate a, Delegate b)
3874 // bool operator == (Delegate a, Delegate b)
3876 // bool operator != (bool a, bool b)
3877 // bool operator == (bool a, bool b)
3879 // LAMESPEC: Reference equality comparison can apply to value/reference types when
3880 // they implement an implicit conversion to any of types above. This does
3881 // not apply when both operands are of same reference type
3883 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3884 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
3889 // Now try lifted version of predefined operators
3891 if (no_arg_conv && !l.IsNullableType) {
3893 // Optimizes cases which won't match
3896 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
3902 // The == and != operators permit one operand to be a value of a nullable
3903 // type and the other to be the null literal, even if no predefined or user-defined
3904 // operator (in unlifted or lifted form) exists for the operation.
3906 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
3907 var lifted = new Nullable.LiftedBinaryOperator (this);
3909 lifted.Right = right;
3910 return lifted.Resolve (ec);
3915 // bool operator != (object a, object b)
3916 // bool operator == (object a, object b)
3918 // An explicit reference conversion exists from the
3919 // type of either operand to the type of the other operand.
3922 // Optimize common path
3924 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3927 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3928 !Convert.ExplicitReferenceConversionExists (r, l))
3931 // Reject allowed explicit conversions like int->object
3932 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
3935 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3936 ec.Report.Warning (253, 2, loc,
3937 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3938 l.GetSignatureForError ());
3940 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3941 ec.Report.Warning (252, 2, loc,
3942 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3943 r.GetSignatureForError ());
3949 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3952 // bool operator == (void* x, void* y);
3953 // bool operator != (void* x, void* y);
3954 // bool operator < (void* x, void* y);
3955 // bool operator > (void* x, void* y);
3956 // bool operator <= (void* x, void* y);
3957 // bool operator >= (void* x, void* y);
3959 if ((oper & Operator.ComparisonMask) != 0) {
3962 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3969 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3975 type = ec.BuiltinTypes.Bool;
3979 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
3983 // Build-in operators method overloading
3985 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
3987 PredefinedOperator best_operator = null;
3988 TypeSpec l = left.Type;
3989 TypeSpec r = right.Type;
3990 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3992 foreach (PredefinedOperator po in operators) {
3993 if ((po.OperatorsMask & oper_mask) == 0)
3996 if (primitives_only) {
3997 if (!po.IsPrimitiveApplicable (l, r))
4000 if (!po.IsApplicable (ec, left, right))
4004 if (best_operator == null) {
4006 if (primitives_only)
4012 best_operator = po.ResolveBetterOperator (ec, best_operator);
4014 if (best_operator == null) {
4015 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4016 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4023 if (best_operator == null)
4026 var expr = best_operator.ConvertResult (ec, this);
4028 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) && !best_operator.IsLifted) {
4029 expr = OptimizeAndOperation (expr);
4036 // Optimize &/&& constant expressions with 0 value
4038 Expression OptimizeAndOperation (Expression expr)
4040 Constant rc = right as Constant;
4041 Constant lc = left as Constant;
4042 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4044 // The result is a constant with side-effect
4046 Constant side_effect = rc == null ?
4047 new SideEffectConstant (lc, right, loc) :
4048 new SideEffectConstant (rc, left, loc);
4050 return ReducedExpression.Create (side_effect, expr);
4057 // Value types can be compared with the null literal because of the lifting
4058 // language rules. However the result is always true or false.
4060 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4062 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4063 type = rc.BuiltinTypes.Bool;
4067 // FIXME: Handle side effect constants
4068 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4070 if ((Oper & Operator.EqualityMask) != 0) {
4071 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4072 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4074 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4075 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4082 // Performs user-operator overloading
4084 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4086 Expression oper_expr;
4088 var op = ConvertBinaryToUserOperator (oper);
4090 if (l.IsNullableType)
4091 l = Nullable.NullableInfo.GetUnderlyingType (l);
4093 if (r.IsNullableType)
4094 r = Nullable.NullableInfo.GetUnderlyingType (r);
4096 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
4097 IList<MemberSpec> right_operators = null;
4100 right_operators = MemberCache.GetUserOperator (r, op, false);
4101 if (right_operators == null && left_operators == null)
4103 } else if (left_operators == null) {
4107 Arguments args = new Arguments (2);
4108 Argument larg = new Argument (left);
4110 Argument rarg = new Argument (right);
4114 // User-defined operator implementations always take precedence
4115 // over predefined operator implementations
4117 if (left_operators != null && right_operators != null) {
4118 left_operators = CombineUserOperators (left_operators, right_operators);
4119 } else if (right_operators != null) {
4120 left_operators = right_operators;
4123 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
4124 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
4126 var res = new OverloadResolver (left_operators, restr, loc);
4128 var oper_method = res.ResolveOperator (rc, ref args);
4129 if (oper_method == null) {
4131 // Logical && and || cannot be lifted
4133 if ((oper & Operator.LogicalMask) != 0)
4137 // Apply lifted user operators only for liftable types. Implicit conversion
4138 // to nullable types is not allowed
4140 if (!IsLiftedOperatorApplicable ())
4143 // TODO: Cache the result in module container
4144 var lifted_methods = CreateLiftedOperators (rc, left_operators);
4145 if (lifted_methods == null)
4148 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
4150 oper_method = res.ResolveOperator (rc, ref args);
4151 if (oper_method == null)
4154 MethodSpec best_original = null;
4155 foreach (MethodSpec ms in left_operators) {
4156 if (ms.MemberDefinition == oper_method.MemberDefinition) {
4162 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4164 // Expression trees use lifted notation in this case
4166 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
4167 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
4170 var ptypes = best_original.Parameters.Types;
4172 if (left.IsNull || right.IsNull) {
4174 // The lifted operator produces the value false if one or both operands are null for
4175 // relational operators.
4177 if ((oper & Operator.ComparisonMask) != 0) {
4179 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
4180 // because return type is actually bool
4182 // For some reason CSC does not report this warning for equality operators
4184 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
4187 // The lifted operator produces a null value if one or both operands are null
4189 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
4190 type = oper_method.ReturnType;
4191 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4195 type = oper_method.ReturnType;
4196 var lifted = new Nullable.LiftedBinaryOperator (this);
4197 lifted.UserOperator = best_original;
4199 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
4200 lifted.UnwrapLeft = new Nullable.Unwrap (left);
4203 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
4204 lifted.UnwrapRight = new Nullable.Unwrap (right);
4207 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
4208 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
4210 return lifted.Resolve (rc);
4213 if ((oper & Operator.LogicalMask) != 0) {
4214 // TODO: CreateExpressionTree is allocated every time
4215 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
4216 oper == Operator.LogicalAnd, loc).Resolve (rc);
4218 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
4221 this.left = larg.Expr;
4222 this.right = rarg.Expr;
4227 bool IsLiftedOperatorApplicable ()
4229 if (left.Type.IsNullableType) {
4230 if ((oper & Operator.EqualityMask) != 0)
4231 return !right.IsNull;
4236 if (right.Type.IsNullableType) {
4237 if ((oper & Operator.EqualityMask) != 0)
4238 return !left.IsNull;
4243 if (TypeSpec.IsValueType (left.Type))
4244 return right.IsNull;
4246 if (TypeSpec.IsValueType (right.Type))
4252 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
4254 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4255 if (nullable_type == null)
4259 // Lifted operators permit predefined and user-defined operators that operate
4260 // on non-nullable value types to also be used with nullable forms of those types.
4261 // Lifted operators are constructed from predefined and user-defined operators
4262 // that meet certain requirements
4264 List<MemberSpec> lifted = null;
4265 foreach (MethodSpec oper in operators) {
4267 if ((Oper & Operator.ComparisonMask) != 0) {
4269 // Result type must be of type bool for lifted comparison operators
4271 rt = oper.ReturnType;
4272 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
4275 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
4281 var ptypes = oper.Parameters.Types;
4282 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
4286 // LAMESPEC: I am not sure why but for equality operators to be lifted
4287 // both types have to match
4289 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
4293 lifted = new List<MemberSpec> ();
4296 // The lifted form is constructed by adding a single ? modifier to each operand and
4297 // result type except for comparison operators where return type is bool
4300 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
4302 var parameters = ParametersCompiled.CreateFullyResolved (
4303 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
4304 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
4306 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
4307 rt, parameters, oper.Modifiers);
4309 lifted.Add (lifted_op);
4316 // Merge two sets of user operators into one, they are mostly distinguish
4317 // except when they share base type and it contains an operator
4319 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
4321 var combined = new List<MemberSpec> (left.Count + right.Count);
4322 combined.AddRange (left);
4323 foreach (var r in right) {
4325 foreach (var l in left) {
4326 if (l.DeclaringType == r.DeclaringType) {
4339 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
4341 if (c is IntegralConstant || c is CharConstant) {
4343 c.ConvertExplicitly (true, type);
4344 } catch (OverflowException) {
4345 ec.Report.Warning (652, 2, loc,
4346 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
4347 type.GetSignatureForError ());
4353 /// EmitBranchable is called from Statement.EmitBoolExpression in the
4354 /// context of a conditional bool expression. This function will return
4355 /// false if it is was possible to use EmitBranchable, or true if it was.
4357 /// The expression's code is generated, and we will generate a branch to `target'
4358 /// if the resulting expression value is equal to isTrue
4360 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
4362 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4363 left = left.EmitToField (ec);
4365 if ((oper & Operator.LogicalMask) == 0) {
4366 right = right.EmitToField (ec);
4371 // This is more complicated than it looks, but its just to avoid
4372 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
4373 // but on top of that we want for == and != to use a special path
4374 // if we are comparing against null
4376 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
4377 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
4380 // put the constant on the rhs, for simplicity
4382 if (left is Constant) {
4383 Expression swap = right;
4389 // brtrue/brfalse works with native int only
4391 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
4392 left.EmitBranchable (ec, target, my_on_true);
4395 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
4396 // right is a boolean, and it's not 'false' => it is 'true'
4397 left.EmitBranchable (ec, target, !my_on_true);
4401 } else if (oper == Operator.LogicalAnd) {
4404 Label tests_end = ec.DefineLabel ();
4406 left.EmitBranchable (ec, tests_end, false);
4407 right.EmitBranchable (ec, target, true);
4408 ec.MarkLabel (tests_end);
4411 // This optimizes code like this
4412 // if (true && i > 4)
4414 if (!(left is Constant))
4415 left.EmitBranchable (ec, target, false);
4417 if (!(right is Constant))
4418 right.EmitBranchable (ec, target, false);
4423 } else if (oper == Operator.LogicalOr){
4425 left.EmitBranchable (ec, target, true);
4426 right.EmitBranchable (ec, target, true);
4429 Label tests_end = ec.DefineLabel ();
4430 left.EmitBranchable (ec, tests_end, true);
4431 right.EmitBranchable (ec, target, false);
4432 ec.MarkLabel (tests_end);
4437 } else if ((oper & Operator.ComparisonMask) == 0) {
4438 base.EmitBranchable (ec, target, on_true);
4445 TypeSpec t = left.Type;
4446 bool is_float = IsFloat (t);
4447 bool is_unsigned = is_float || IsUnsigned (t);
4450 case Operator.Equality:
4452 ec.Emit (OpCodes.Beq, target);
4454 ec.Emit (OpCodes.Bne_Un, target);
4457 case Operator.Inequality:
4459 ec.Emit (OpCodes.Bne_Un, target);
4461 ec.Emit (OpCodes.Beq, target);
4464 case Operator.LessThan:
4466 if (is_unsigned && !is_float)
4467 ec.Emit (OpCodes.Blt_Un, target);
4469 ec.Emit (OpCodes.Blt, target);
4472 ec.Emit (OpCodes.Bge_Un, target);
4474 ec.Emit (OpCodes.Bge, target);
4477 case Operator.GreaterThan:
4479 if (is_unsigned && !is_float)
4480 ec.Emit (OpCodes.Bgt_Un, target);
4482 ec.Emit (OpCodes.Bgt, target);
4485 ec.Emit (OpCodes.Ble_Un, target);
4487 ec.Emit (OpCodes.Ble, target);
4490 case Operator.LessThanOrEqual:
4492 if (is_unsigned && !is_float)
4493 ec.Emit (OpCodes.Ble_Un, target);
4495 ec.Emit (OpCodes.Ble, target);
4498 ec.Emit (OpCodes.Bgt_Un, target);
4500 ec.Emit (OpCodes.Bgt, target);
4504 case Operator.GreaterThanOrEqual:
4506 if (is_unsigned && !is_float)
4507 ec.Emit (OpCodes.Bge_Un, target);
4509 ec.Emit (OpCodes.Bge, target);
4512 ec.Emit (OpCodes.Blt_Un, target);
4514 ec.Emit (OpCodes.Blt, target);
4517 throw new InternalErrorException (oper.ToString ());
4521 public override void Emit (EmitContext ec)
4523 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4524 left = left.EmitToField (ec);
4526 if ((oper & Operator.LogicalMask) == 0) {
4527 right = right.EmitToField (ec);
4532 // Handle short-circuit operators differently
4535 if ((oper & Operator.LogicalMask) != 0) {
4536 Label load_result = ec.DefineLabel ();
4537 Label end = ec.DefineLabel ();
4539 bool is_or = oper == Operator.LogicalOr;
4540 left.EmitBranchable (ec, load_result, is_or);
4542 ec.Emit (OpCodes.Br_S, end);
4544 ec.MarkLabel (load_result);
4545 ec.EmitInt (is_or ? 1 : 0);
4551 // Optimize zero-based operations which cannot be optimized at expression level
4553 if (oper == Operator.Subtraction) {
4554 var lc = left as IntegralConstant;
4555 if (lc != null && lc.IsDefaultValue) {
4557 ec.Emit (OpCodes.Neg);
4562 EmitOperator (ec, left, right);
4565 public void EmitOperator (EmitContext ec, Expression left, Expression right)
4570 EmitOperatorOpcode (ec, oper, left.Type, right);
4573 // Emit result enumerable conversion this way because it's quite complicated get it
4574 // to resolved tree because expression tree cannot see it.
4576 if (enum_conversion != 0)
4577 ConvCast.Emit (ec, enum_conversion);
4580 public override void EmitSideEffect (EmitContext ec)
4582 if ((oper & Operator.LogicalMask) != 0 ||
4583 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
4584 base.EmitSideEffect (ec);
4586 left.EmitSideEffect (ec);
4587 right.EmitSideEffect (ec);
4591 public override Expression EmitToField (EmitContext ec)
4593 if ((oper & Operator.LogicalMask) == 0) {
4594 var await_expr = left as Await;
4595 if (await_expr != null && right.IsSideEffectFree) {
4596 await_expr.Statement.EmitPrologue (ec);
4597 left = await_expr.Statement.GetResultExpression (ec);
4601 await_expr = right as Await;
4602 if (await_expr != null && left.IsSideEffectFree) {
4603 await_expr.Statement.EmitPrologue (ec);
4604 right = await_expr.Statement.GetResultExpression (ec);
4609 return base.EmitToField (ec);
4612 protected override void CloneTo (CloneContext clonectx, Expression t)
4614 Binary target = (Binary) t;
4616 target.left = left.Clone (clonectx);
4617 target.right = right.Clone (clonectx);
4620 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
4622 Arguments binder_args = new Arguments (4);
4624 MemberAccess sle = new MemberAccess (new MemberAccess (
4625 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
4627 CSharpBinderFlags flags = 0;
4628 if (ec.HasSet (ResolveContext.Options.CheckedScope))
4629 flags = CSharpBinderFlags.CheckedContext;
4631 if ((oper & Operator.LogicalMask) != 0)
4632 flags |= CSharpBinderFlags.BinaryOperationLogical;
4634 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
4635 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
4636 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
4637 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
4639 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
4642 public override Expression CreateExpressionTree (ResolveContext ec)
4644 return CreateExpressionTree (ec, null);
4647 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
4650 bool lift_arg = false;
4653 case Operator.Addition:
4654 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4655 method_name = "AddChecked";
4657 method_name = "Add";
4659 case Operator.BitwiseAnd:
4660 method_name = "And";
4662 case Operator.BitwiseOr:
4665 case Operator.Division:
4666 method_name = "Divide";
4668 case Operator.Equality:
4669 method_name = "Equal";
4672 case Operator.ExclusiveOr:
4673 method_name = "ExclusiveOr";
4675 case Operator.GreaterThan:
4676 method_name = "GreaterThan";
4679 case Operator.GreaterThanOrEqual:
4680 method_name = "GreaterThanOrEqual";
4683 case Operator.Inequality:
4684 method_name = "NotEqual";
4687 case Operator.LeftShift:
4688 method_name = "LeftShift";
4690 case Operator.LessThan:
4691 method_name = "LessThan";
4694 case Operator.LessThanOrEqual:
4695 method_name = "LessThanOrEqual";
4698 case Operator.LogicalAnd:
4699 method_name = "AndAlso";
4701 case Operator.LogicalOr:
4702 method_name = "OrElse";
4704 case Operator.Modulus:
4705 method_name = "Modulo";
4707 case Operator.Multiply:
4708 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4709 method_name = "MultiplyChecked";
4711 method_name = "Multiply";
4713 case Operator.RightShift:
4714 method_name = "RightShift";
4716 case Operator.Subtraction:
4717 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4718 method_name = "SubtractChecked";
4720 method_name = "Subtract";
4724 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4727 Arguments args = new Arguments (2);
4728 args.Add (new Argument (left.CreateExpressionTree (ec)));
4729 args.Add (new Argument (right.CreateExpressionTree (ec)));
4730 if (method != null) {
4732 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4734 args.Add (new Argument (method));
4737 return CreateExpressionFactoryCall (ec, method_name, args);
4740 public override object Accept (StructuralVisitor visitor)
4742 return visitor.Visit (this);
4748 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4749 // b, c, d... may be strings or objects.
4751 public class StringConcat : Expression
4753 Arguments arguments;
4755 StringConcat (Location loc)
4758 arguments = new Arguments (2);
4761 public override bool ContainsEmitWithAwait ()
4763 return arguments.ContainsEmitWithAwait ();
4766 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4768 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4769 throw new ArgumentException ();
4771 var s = new StringConcat (loc);
4772 s.type = rc.BuiltinTypes.String;
4773 s.eclass = ExprClass.Value;
4775 s.Append (rc, left);
4776 s.Append (rc, right);
4780 public override Expression CreateExpressionTree (ResolveContext ec)
4782 Argument arg = arguments [0];
4783 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4787 // Creates nested calls tree from an array of arguments used for IL emit
4789 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4791 Arguments concat_args = new Arguments (2);
4792 Arguments add_args = new Arguments (3);
4794 concat_args.Add (left);
4795 add_args.Add (new Argument (left_etree));
4797 concat_args.Add (arguments [pos]);
4798 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4800 var methods = GetConcatMethodCandidates ();
4801 if (methods == null)
4804 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4805 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4809 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4811 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4812 if (++pos == arguments.Count)
4815 left = new Argument (new EmptyExpression (method.ReturnType));
4816 return CreateExpressionAddCall (ec, left, expr, pos);
4819 protected override Expression DoResolve (ResolveContext ec)
4824 void Append (ResolveContext rc, Expression operand)
4829 StringConstant sc = operand as StringConstant;
4831 if (arguments.Count != 0) {
4832 Argument last_argument = arguments [arguments.Count - 1];
4833 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4834 if (last_expr_constant != null) {
4835 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4841 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4843 StringConcat concat_oper = operand as StringConcat;
4844 if (concat_oper != null) {
4845 arguments.AddRange (concat_oper.arguments);
4850 arguments.Add (new Argument (operand));
4853 IList<MemberSpec> GetConcatMethodCandidates ()
4855 return MemberCache.FindMembers (type, "Concat", true);
4858 public override void Emit (EmitContext ec)
4860 // Optimize by removing any extra null arguments, they are no-op
4861 for (int i = 0; i < arguments.Count; ++i) {
4862 if (arguments[i].Expr is NullConstant)
4863 arguments.RemoveAt (i--);
4866 var members = GetConcatMethodCandidates ();
4867 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4868 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4869 if (method != null) {
4870 var call = new CallEmitter ();
4871 call.EmitPredefined (ec, method, arguments);
4875 public override SLE.Expression MakeExpression (BuilderContext ctx)
4877 if (arguments.Count != 2)
4878 throw new NotImplementedException ("arguments.Count != 2");
4880 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4881 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4886 // User-defined conditional logical operator
4888 public class ConditionalLogicalOperator : UserOperatorCall
4890 readonly bool is_and;
4891 Expression oper_expr;
4893 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4894 : base (oper, arguments, expr_tree, loc)
4896 this.is_and = is_and;
4897 eclass = ExprClass.Unresolved;
4900 protected override Expression DoResolve (ResolveContext ec)
4902 AParametersCollection pd = oper.Parameters;
4903 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4904 ec.Report.Error (217, loc,
4905 "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",
4906 oper.GetSignatureForError ());
4910 Expression left_dup = new EmptyExpression (type);
4911 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4912 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4913 if (op_true == null || op_false == null) {
4914 ec.Report.Error (218, loc,
4915 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4916 type.GetSignatureForError (), oper.GetSignatureForError ());
4920 oper_expr = is_and ? op_false : op_true;
4921 eclass = ExprClass.Value;
4925 public override void Emit (EmitContext ec)
4927 Label end_target = ec.DefineLabel ();
4930 // Emit and duplicate left argument
4932 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
4933 if (right_contains_await) {
4934 arguments[0] = arguments[0].EmitToField (ec, false);
4935 arguments[0].Expr.Emit (ec);
4937 arguments[0].Expr.Emit (ec);
4938 ec.Emit (OpCodes.Dup);
4939 arguments.RemoveAt (0);
4942 oper_expr.EmitBranchable (ec, end_target, true);
4946 if (right_contains_await) {
4948 // Special handling when right expression contains await and left argument
4949 // could not be left on stack before logical branch
4951 Label skip_left_load = ec.DefineLabel ();
4952 ec.Emit (OpCodes.Br_S, skip_left_load);
4953 ec.MarkLabel (end_target);
4954 arguments[0].Expr.Emit (ec);
4955 ec.MarkLabel (skip_left_load);
4957 ec.MarkLabel (end_target);
4962 public class PointerArithmetic : Expression {
4963 Expression left, right;
4964 readonly Binary.Operator op;
4967 // We assume that `l' is always a pointer
4969 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4978 public override bool ContainsEmitWithAwait ()
4980 throw new NotImplementedException ();
4983 public override Expression CreateExpressionTree (ResolveContext ec)
4985 Error_PointerInsideExpressionTree (ec);
4989 protected override Expression DoResolve (ResolveContext ec)
4991 eclass = ExprClass.Variable;
4993 var pc = left.Type as PointerContainer;
4994 if (pc != null && pc.Element.Kind == MemberKind.Void) {
4995 Error_VoidPointerOperation (ec);
5002 public override void Emit (EmitContext ec)
5004 TypeSpec op_type = left.Type;
5006 // It must be either array or fixed buffer
5008 if (TypeManager.HasElementType (op_type)) {
5009 element = TypeManager.GetElementType (op_type);
5011 FieldExpr fe = left as FieldExpr;
5013 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5018 int size = BuiltinTypeSpec.GetSize(element);
5019 TypeSpec rtype = right.Type;
5021 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5023 // handle (pointer - pointer)
5027 ec.Emit (OpCodes.Sub);
5031 ec.Emit (OpCodes.Sizeof, element);
5034 ec.Emit (OpCodes.Div);
5036 ec.Emit (OpCodes.Conv_I8);
5039 // handle + and - on (pointer op int)
5041 Constant left_const = left as Constant;
5042 if (left_const != null) {
5044 // Optimize ((T*)null) pointer operations
5046 if (left_const.IsDefaultValue) {
5047 left = EmptyExpression.Null;
5055 var right_const = right as Constant;
5056 if (right_const != null) {
5058 // Optimize 0-based arithmetic
5060 if (right_const.IsDefaultValue)
5064 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5066 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5068 // TODO: Should be the checks resolve context sensitive?
5069 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5070 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5076 switch (rtype.BuiltinType) {
5077 case BuiltinTypeSpec.Type.SByte:
5078 case BuiltinTypeSpec.Type.Byte:
5079 case BuiltinTypeSpec.Type.Short:
5080 case BuiltinTypeSpec.Type.UShort:
5081 ec.Emit (OpCodes.Conv_I);
5083 case BuiltinTypeSpec.Type.UInt:
5084 ec.Emit (OpCodes.Conv_U);
5088 if (right_const == null && size != 1){
5090 ec.Emit (OpCodes.Sizeof, element);
5093 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5094 ec.Emit (OpCodes.Conv_I8);
5096 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
5099 if (left_const == null) {
5100 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
5101 ec.Emit (OpCodes.Conv_I);
5102 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5103 ec.Emit (OpCodes.Conv_U);
5105 Binary.EmitOperatorOpcode (ec, op, op_type, right);
5112 // A boolean-expression is an expression that yields a result
5115 public class BooleanExpression : ShimExpression
5117 public BooleanExpression (Expression expr)
5120 this.loc = expr.Location;
5123 public override Expression CreateExpressionTree (ResolveContext ec)
5125 // TODO: We should emit IsTrue (v4) instead of direct user operator
5126 // call but that would break csc compatibility
5127 return base.CreateExpressionTree (ec);
5130 protected override Expression DoResolve (ResolveContext ec)
5132 // A boolean-expression is required to be of a type
5133 // that can be implicitly converted to bool or of
5134 // a type that implements operator true
5136 expr = expr.Resolve (ec);
5140 Assign ass = expr as Assign;
5141 if (ass != null && ass.Source is Constant) {
5142 ec.Report.Warning (665, 3, loc,
5143 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
5146 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
5149 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5150 Arguments args = new Arguments (1);
5151 args.Add (new Argument (expr));
5152 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
5155 type = ec.BuiltinTypes.Bool;
5156 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
5157 if (converted != null)
5161 // If no implicit conversion to bool exists, try using `operator true'
5163 converted = GetOperatorTrue (ec, expr, loc);
5164 if (converted == null) {
5165 expr.Error_ValueCannotBeConverted (ec, type, false);
5172 public override object Accept (StructuralVisitor visitor)
5174 return visitor.Visit (this);
5178 public class BooleanExpressionFalse : Unary
5180 public BooleanExpressionFalse (Expression expr)
5181 : base (Operator.LogicalNot, expr, expr.Location)
5185 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
5187 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
5192 /// Implements the ternary conditional operator (?:)
5194 public class Conditional : Expression {
5195 Expression expr, true_expr, false_expr;
5197 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
5200 this.true_expr = true_expr;
5201 this.false_expr = false_expr;
5207 public Expression Expr {
5213 public Expression TrueExpr {
5219 public Expression FalseExpr {
5227 public override bool ContainsEmitWithAwait ()
5229 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
5232 public override Expression CreateExpressionTree (ResolveContext ec)
5234 Arguments args = new Arguments (3);
5235 args.Add (new Argument (expr.CreateExpressionTree (ec)));
5236 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
5237 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
5238 return CreateExpressionFactoryCall (ec, "Condition", args);
5241 protected override Expression DoResolve (ResolveContext ec)
5243 expr = expr.Resolve (ec);
5246 // Unreachable code needs different resolve path. For instance for await
5247 // expression to not generate unreachable resumable statement
5249 Constant c = expr as Constant;
5250 if (c != null && ec.CurrentBranching != null) {
5251 bool unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
5253 if (c.IsDefaultValue) {
5254 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
5255 true_expr = true_expr.Resolve (ec);
5256 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
5258 false_expr = false_expr.Resolve (ec);
5260 true_expr = true_expr.Resolve (ec);
5262 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
5263 false_expr = false_expr.Resolve (ec);
5264 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
5267 true_expr = true_expr.Resolve (ec);
5268 false_expr = false_expr.Resolve (ec);
5271 if (true_expr == null || false_expr == null || expr == null)
5274 eclass = ExprClass.Value;
5275 TypeSpec true_type = true_expr.Type;
5276 TypeSpec false_type = false_expr.Type;
5280 // First, if an implicit conversion exists from true_expr
5281 // to false_expr, then the result type is of type false_expr.Type
5283 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
5284 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
5285 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5287 // Check if both can convert implicitly to each other's type
5291 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5292 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
5294 // LAMESPEC: There seems to be hardcoded promotition to int type when
5295 // both sides are numeric constants and one side is int constant and
5296 // other side is numeric constant convertible to int.
5298 // var res = condition ? (short)1 : 1;
5300 // Type of res is int even if according to the spec the conversion is
5301 // ambiguous because 1 literal can be converted to short.
5303 if (conv_false_expr != null) {
5304 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
5306 conv_false_expr = null;
5307 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
5308 conv_false_expr = null;
5312 if (conv_false_expr != null) {
5313 ec.Report.Error (172, true_expr.Location,
5314 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
5315 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5320 if (true_expr.Type != type)
5321 true_expr = EmptyCast.Create (true_expr, type);
5322 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
5325 ec.Report.Error (173, true_expr.Location,
5326 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
5327 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5333 bool is_false = c.IsDefaultValue;
5336 // Don't issue the warning for constant expressions
5338 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
5339 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location,
5340 "Unreachable expression code detected");
5343 return ReducedExpression.Create (
5344 is_false ? false_expr : true_expr, this,
5345 false_expr is Constant && true_expr is Constant).Resolve (ec);
5351 public override void Emit (EmitContext ec)
5353 Label false_target = ec.DefineLabel ();
5354 Label end_target = ec.DefineLabel ();
5356 expr.EmitBranchable (ec, false_target, false);
5357 true_expr.Emit (ec);
5360 // Verifier doesn't support interface merging. When there are two types on
5361 // the stack without common type hint and the common type is an interface.
5362 // Use temporary local to give verifier hint on what type to unify the stack
5364 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
5365 var temp = ec.GetTemporaryLocal (type);
5366 ec.Emit (OpCodes.Stloc, temp);
5367 ec.Emit (OpCodes.Ldloc, temp);
5368 ec.FreeTemporaryLocal (temp, type);
5371 ec.Emit (OpCodes.Br, end_target);
5372 ec.MarkLabel (false_target);
5373 false_expr.Emit (ec);
5374 ec.MarkLabel (end_target);
5377 protected override void CloneTo (CloneContext clonectx, Expression t)
5379 Conditional target = (Conditional) t;
5381 target.expr = expr.Clone (clonectx);
5382 target.true_expr = true_expr.Clone (clonectx);
5383 target.false_expr = false_expr.Clone (clonectx);
5387 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
5389 LocalTemporary temp;
5392 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
5393 public abstract void SetHasAddressTaken ();
5394 public abstract void VerifyAssigned (ResolveContext rc);
5396 public abstract bool IsLockedByStatement { get; set; }
5398 public abstract bool IsFixed { get; }
5399 public abstract bool IsRef { get; }
5400 public abstract string Name { get; }
5403 // Variable IL data, it has to be protected to encapsulate hoisted variables
5405 protected abstract ILocalVariable Variable { get; }
5408 // Variable flow-analysis data
5410 public abstract VariableInfo VariableInfo { get; }
5413 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5415 HoistedVariable hv = GetHoistedVariable (ec);
5417 hv.AddressOf (ec, mode);
5421 Variable.EmitAddressOf (ec);
5424 public override bool ContainsEmitWithAwait ()
5429 public override Expression CreateExpressionTree (ResolveContext ec)
5431 HoistedVariable hv = GetHoistedVariable (ec);
5433 return hv.CreateExpressionTree ();
5435 Arguments arg = new Arguments (1);
5436 arg.Add (new Argument (this));
5437 return CreateExpressionFactoryCall (ec, "Constant", arg);
5440 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
5442 if (IsLockedByStatement) {
5443 rc.Report.Warning (728, 2, loc,
5444 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
5451 public override void Emit (EmitContext ec)
5456 public override void EmitSideEffect (EmitContext ec)
5462 // This method is used by parameters that are references, that are
5463 // being passed as references: we only want to pass the pointer (that
5464 // is already stored in the parameter, not the address of the pointer,
5465 // and not the value of the variable).
5467 public void EmitLoad (EmitContext ec)
5472 public void Emit (EmitContext ec, bool leave_copy)
5474 HoistedVariable hv = GetHoistedVariable (ec);
5476 hv.Emit (ec, leave_copy);
5484 // If we are a reference, we loaded on the stack a pointer
5485 // Now lets load the real value
5487 ec.EmitLoadFromPtr (type);
5491 ec.Emit (OpCodes.Dup);
5494 temp = new LocalTemporary (Type);
5500 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
5501 bool prepare_for_load)
5503 HoistedVariable hv = GetHoistedVariable (ec);
5505 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
5509 New n_source = source as New;
5510 if (n_source != null) {
5511 if (!n_source.Emit (ec, this)) {
5515 ec.EmitLoadFromPtr (type);
5527 ec.Emit (OpCodes.Dup);
5529 temp = new LocalTemporary (Type);
5535 ec.EmitStoreFromPtr (type);
5537 Variable.EmitAssign (ec);
5545 public override Expression EmitToField (EmitContext ec)
5547 HoistedVariable hv = GetHoistedVariable (ec);
5549 return hv.EmitToField (ec);
5552 return base.EmitToField (ec);
5555 public HoistedVariable GetHoistedVariable (ResolveContext rc)
5557 return GetHoistedVariable (rc.CurrentAnonymousMethod);
5560 public HoistedVariable GetHoistedVariable (EmitContext ec)
5562 return GetHoistedVariable (ec.CurrentAnonymousMethod);
5565 public override string GetSignatureForError ()
5570 public bool IsHoisted {
5571 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
5576 // Resolved reference to a local variable
5578 public class LocalVariableReference : VariableReference
5580 public LocalVariable local_info;
5582 public LocalVariableReference (LocalVariable li, Location l)
5584 this.local_info = li;
5588 public override VariableInfo VariableInfo {
5589 get { return local_info.VariableInfo; }
5592 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5594 return local_info.HoistedVariant;
5600 // A local variable is always fixed
5602 public override bool IsFixed {
5608 public override bool IsLockedByStatement {
5610 return local_info.IsLocked;
5613 local_info.IsLocked = value;
5617 public override bool IsRef {
5618 get { return false; }
5621 public override string Name {
5622 get { return local_info.Name; }
5627 public override void VerifyAssigned (ResolveContext rc)
5629 VariableInfo variable_info = local_info.VariableInfo;
5630 if (variable_info == null)
5633 if (variable_info.IsAssigned (rc))
5636 rc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
5637 variable_info.SetAssigned (rc);
5640 public override void SetHasAddressTaken ()
5642 local_info.SetHasAddressTaken ();
5645 void DoResolveBase (ResolveContext ec)
5648 // If we are referencing a variable from the external block
5649 // flag it for capturing
5651 if (ec.MustCaptureVariable (local_info)) {
5652 if (local_info.AddressTaken) {
5653 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5654 } else if (local_info.IsFixed) {
5655 ec.Report.Error (1764, loc,
5656 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
5657 GetSignatureForError ());
5660 if (ec.IsVariableCapturingRequired) {
5661 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
5662 storey.CaptureLocalVariable (ec, local_info);
5666 eclass = ExprClass.Variable;
5667 type = local_info.Type;
5670 protected override Expression DoResolve (ResolveContext ec)
5672 local_info.SetIsUsed ();
5674 VerifyAssigned (ec);
5680 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5683 // Don't be too pedantic when variable is used as out param or for some broken code
5684 // which uses property/indexer access to run some initialization
5686 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5687 local_info.SetIsUsed ();
5689 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5692 if (rhs == EmptyExpression.OutAccess) {
5693 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5694 } else if (rhs == EmptyExpression.LValueMemberAccess) {
5695 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
5696 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5697 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5698 } else if (rhs == EmptyExpression.UnaryAddress) {
5699 code = 459; msg = "Cannot take the address of {1} `{0}'";
5701 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5703 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5704 } else if (VariableInfo != null) {
5705 VariableInfo.SetAssigned (ec);
5708 if (eclass == ExprClass.Unresolved)
5711 return base.DoResolveLValue (ec, rhs);
5714 public override int GetHashCode ()
5716 return local_info.GetHashCode ();
5719 public override bool Equals (object obj)
5721 LocalVariableReference lvr = obj as LocalVariableReference;
5725 return local_info == lvr.local_info;
5728 protected override ILocalVariable Variable {
5729 get { return local_info; }
5732 public override string ToString ()
5734 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5737 protected override void CloneTo (CloneContext clonectx, Expression t)
5744 /// This represents a reference to a parameter in the intermediate
5747 public class ParameterReference : VariableReference
5749 protected ParametersBlock.ParameterInfo pi;
5751 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5759 public override bool IsLockedByStatement {
5764 pi.IsLocked = value;
5768 public override bool IsRef {
5769 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5772 bool HasOutModifier {
5773 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5776 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5778 return pi.Parameter.HoistedVariant;
5782 // A ref or out parameter is classified as a moveable variable, even
5783 // if the argument given for the parameter is a fixed variable
5785 public override bool IsFixed {
5786 get { return !IsRef; }
5789 public override string Name {
5790 get { return Parameter.Name; }
5793 public Parameter Parameter {
5794 get { return pi.Parameter; }
5797 public override VariableInfo VariableInfo {
5798 get { return pi.VariableInfo; }
5801 protected override ILocalVariable Variable {
5802 get { return Parameter; }
5807 public override void AddressOf (EmitContext ec, AddressOp mode)
5810 // ParameterReferences might already be a reference
5817 base.AddressOf (ec, mode);
5820 public override void SetHasAddressTaken ()
5822 Parameter.HasAddressTaken = true;
5825 void SetAssigned (ResolveContext ec)
5827 if (Parameter.HoistedVariant != null)
5828 Parameter.HoistedVariant.IsAssigned = true;
5830 if (HasOutModifier && ec.DoFlowAnalysis)
5831 ec.CurrentBranching.SetAssigned (VariableInfo);
5834 bool DoResolveBase (ResolveContext ec)
5836 if (eclass != ExprClass.Unresolved)
5839 type = pi.ParameterType;
5840 eclass = ExprClass.Variable;
5843 // If we are referencing a parameter from the external block
5844 // flag it for capturing
5846 if (ec.MustCaptureVariable (pi)) {
5847 if (Parameter.HasAddressTaken)
5848 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5851 ec.Report.Error (1628, loc,
5852 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5853 Name, ec.CurrentAnonymousMethod.ContainerType);
5856 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5857 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5858 storey.CaptureParameter (ec, pi, this);
5865 public override int GetHashCode ()
5867 return Name.GetHashCode ();
5870 public override bool Equals (object obj)
5872 ParameterReference pr = obj as ParameterReference;
5876 return Name == pr.Name;
5879 protected override void CloneTo (CloneContext clonectx, Expression target)
5885 public override Expression CreateExpressionTree (ResolveContext ec)
5887 HoistedVariable hv = GetHoistedVariable (ec);
5889 return hv.CreateExpressionTree ();
5891 return Parameter.ExpressionTreeVariableReference ();
5895 // Notice that for ref/out parameters, the type exposed is not the
5896 // same type exposed externally.
5899 // externally we expose "int&"
5900 // here we expose "int".
5902 // We record this in "is_ref". This means that the type system can treat
5903 // the type as it is expected, but when we generate the code, we generate
5904 // the alternate kind of code.
5906 protected override Expression DoResolve (ResolveContext ec)
5908 if (!DoResolveBase (ec))
5911 VerifyAssigned (ec);
5915 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5917 if (!DoResolveBase (ec))
5921 return base.DoResolveLValue (ec, right_side);
5924 public override void VerifyAssigned (ResolveContext rc)
5926 // HACK: Variables are not captured in probing mode
5927 if (rc.IsInProbingMode)
5930 if (HasOutModifier && !VariableInfo.IsAssigned (rc)) {
5931 rc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
5937 /// Invocation of methods or delegates.
5939 public class Invocation : ExpressionStatement
5941 protected Arguments arguments;
5942 protected Expression expr;
5943 protected MethodGroupExpr mg;
5945 public Invocation (Expression expr, Arguments arguments)
5948 this.arguments = arguments;
5950 loc = expr.Location;
5955 public Arguments Arguments {
5961 public Expression Exp {
5967 public MethodGroupExpr MethodGroup {
5973 public override Location StartLocation {
5975 return expr.StartLocation;
5981 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
5983 if (MethodGroup == null)
5986 var candidate = MethodGroup.BestCandidate;
5987 if (candidate == null || !(candidate.IsStatic || Exp is This))
5990 var args_count = arguments == null ? 0 : arguments.Count;
5991 if (args_count != body.Parameters.Count)
5994 var lambda_parameters = body.Block.Parameters.FixedParameters;
5995 for (int i = 0; i < args_count; ++i) {
5996 var pr = arguments[i].Expr as ParameterReference;
6000 if (lambda_parameters[i] != pr.Parameter)
6003 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6007 var emg = MethodGroup as ExtensionMethodGroupExpr;
6009 return MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6015 protected override void CloneTo (CloneContext clonectx, Expression t)
6017 Invocation target = (Invocation) t;
6019 if (arguments != null)
6020 target.arguments = arguments.Clone (clonectx);
6022 target.expr = expr.Clone (clonectx);
6025 public override bool ContainsEmitWithAwait ()
6027 if (arguments != null && arguments.ContainsEmitWithAwait ())
6030 return mg.ContainsEmitWithAwait ();
6033 public override Expression CreateExpressionTree (ResolveContext ec)
6035 Expression instance = mg.IsInstance ?
6036 mg.InstanceExpression.CreateExpressionTree (ec) :
6037 new NullLiteral (loc);
6039 var args = Arguments.CreateForExpressionTree (ec, arguments,
6041 mg.CreateExpressionTree (ec));
6043 return CreateExpressionFactoryCall (ec, "Call", args);
6046 protected override Expression DoResolve (ResolveContext ec)
6048 Expression member_expr;
6049 var atn = expr as ATypeNameExpression;
6051 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
6052 if (member_expr != null)
6053 member_expr = member_expr.Resolve (ec);
6055 member_expr = expr.Resolve (ec);
6058 if (member_expr == null)
6062 // Next, evaluate all the expressions in the argument list
6064 bool dynamic_arg = false;
6065 if (arguments != null)
6066 arguments.Resolve (ec, out dynamic_arg);
6068 TypeSpec expr_type = member_expr.Type;
6069 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6070 return DoResolveDynamic (ec, member_expr);
6072 mg = member_expr as MethodGroupExpr;
6073 Expression invoke = null;
6076 if (expr_type != null && expr_type.IsDelegate) {
6077 invoke = new DelegateInvocation (member_expr, arguments, loc);
6078 invoke = invoke.Resolve (ec);
6079 if (invoke == null || !dynamic_arg)
6082 if (member_expr is RuntimeValueExpression) {
6083 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
6084 member_expr.Type.GetSignatureForError ());
6088 MemberExpr me = member_expr as MemberExpr;
6090 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
6094 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
6095 member_expr.GetSignatureForError ());
6100 if (invoke == null) {
6101 mg = DoResolveOverload (ec);
6107 return DoResolveDynamic (ec, member_expr);
6109 var method = mg.BestCandidate;
6110 type = mg.BestCandidateReturnType;
6112 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
6114 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
6116 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
6120 IsSpecialMethodInvocation (ec, method, loc);
6122 eclass = ExprClass.Value;
6126 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
6129 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
6131 args = dmb.Arguments;
6132 if (arguments != null)
6133 args.AddRange (arguments);
6134 } else if (mg == null) {
6135 if (arguments == null)
6136 args = new Arguments (1);
6140 args.Insert (0, new Argument (memberExpr));
6144 ec.Report.Error (1971, loc,
6145 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
6150 if (arguments == null)
6151 args = new Arguments (1);
6155 MemberAccess ma = expr as MemberAccess;
6157 var left_type = ma.LeftExpression as TypeExpr;
6158 if (left_type != null) {
6159 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6162 // Any value type has to be pass as by-ref to get back the same
6163 // instance on which the member was called
6165 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
6166 Argument.AType.Ref : Argument.AType.None;
6167 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
6169 } else { // is SimpleName
6171 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6173 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
6178 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
6181 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
6183 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
6186 public override string GetSignatureForError ()
6188 return mg.GetSignatureForError ();
6192 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
6193 // or the type dynamic, then the member is invocable
6195 public static bool IsMemberInvocable (MemberSpec member)
6197 switch (member.Kind) {
6198 case MemberKind.Event:
6200 case MemberKind.Field:
6201 case MemberKind.Property:
6202 var m = member as IInterfaceMemberSpec;
6203 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
6209 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
6211 if (!method.IsReservedMethod)
6214 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
6217 ec.Report.SymbolRelatedToPreviousError (method);
6218 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
6219 method.GetSignatureForError ());
6224 public override void Emit (EmitContext ec)
6226 mg.EmitCall (ec, arguments);
6229 public override void EmitStatement (EmitContext ec)
6234 // Pop the return value if there is one
6236 if (type.Kind != MemberKind.Void)
6237 ec.Emit (OpCodes.Pop);
6240 public override SLE.Expression MakeExpression (BuilderContext ctx)
6242 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
6245 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
6248 throw new NotSupportedException ();
6250 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
6251 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
6255 public override object Accept (StructuralVisitor visitor)
6257 return visitor.Visit (this);
6262 // Implements simple new expression
6264 public class New : ExpressionStatement, IMemoryLocation
6266 protected Arguments arguments;
6269 // During bootstrap, it contains the RequestedType,
6270 // but if `type' is not null, it *might* contain a NewDelegate
6271 // (because of field multi-initialization)
6273 protected Expression RequestedType;
6275 protected MethodSpec method;
6277 public New (Expression requested_type, Arguments arguments, Location l)
6279 RequestedType = requested_type;
6280 this.arguments = arguments;
6285 public Arguments Arguments {
6292 // Returns true for resolved `new S()'
6294 public bool IsDefaultStruct {
6296 return arguments == null && type.IsStruct && GetType () == typeof (New);
6300 public Expression TypeExpression {
6302 return RequestedType;
6309 /// Converts complex core type syntax like 'new int ()' to simple constant
6311 public static Constant Constantify (TypeSpec t, Location loc)
6313 switch (t.BuiltinType) {
6314 case BuiltinTypeSpec.Type.Int:
6315 return new IntConstant (t, 0, loc);
6316 case BuiltinTypeSpec.Type.UInt:
6317 return new UIntConstant (t, 0, loc);
6318 case BuiltinTypeSpec.Type.Long:
6319 return new LongConstant (t, 0, loc);
6320 case BuiltinTypeSpec.Type.ULong:
6321 return new ULongConstant (t, 0, loc);
6322 case BuiltinTypeSpec.Type.Float:
6323 return new FloatConstant (t, 0, loc);
6324 case BuiltinTypeSpec.Type.Double:
6325 return new DoubleConstant (t, 0, loc);
6326 case BuiltinTypeSpec.Type.Short:
6327 return new ShortConstant (t, 0, loc);
6328 case BuiltinTypeSpec.Type.UShort:
6329 return new UShortConstant (t, 0, loc);
6330 case BuiltinTypeSpec.Type.SByte:
6331 return new SByteConstant (t, 0, loc);
6332 case BuiltinTypeSpec.Type.Byte:
6333 return new ByteConstant (t, 0, loc);
6334 case BuiltinTypeSpec.Type.Char:
6335 return new CharConstant (t, '\0', loc);
6336 case BuiltinTypeSpec.Type.Bool:
6337 return new BoolConstant (t, false, loc);
6338 case BuiltinTypeSpec.Type.Decimal:
6339 return new DecimalConstant (t, 0, loc);
6343 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
6345 if (t.IsNullableType)
6346 return Nullable.LiftedNull.Create (t, loc);
6351 public override bool ContainsEmitWithAwait ()
6353 return arguments != null && arguments.ContainsEmitWithAwait ();
6357 // Checks whether the type is an interface that has the
6358 // [ComImport, CoClass] attributes and must be treated
6361 public Expression CheckComImport (ResolveContext ec)
6363 if (!type.IsInterface)
6367 // Turn the call into:
6368 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
6370 var real_class = type.MemberDefinition.GetAttributeCoClass ();
6371 if (real_class == null)
6374 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
6375 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
6376 return cast.Resolve (ec);
6379 public override Expression CreateExpressionTree (ResolveContext ec)
6382 if (method == null) {
6383 args = new Arguments (1);
6384 args.Add (new Argument (new TypeOf (type, loc)));
6386 args = Arguments.CreateForExpressionTree (ec,
6387 arguments, new TypeOfMethod (method, loc));
6390 return CreateExpressionFactoryCall (ec, "New", args);
6393 protected override Expression DoResolve (ResolveContext ec)
6395 type = RequestedType.ResolveAsType (ec);
6399 eclass = ExprClass.Value;
6401 if (type.IsPointer) {
6402 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
6403 type.GetSignatureForError ());
6407 if (arguments == null) {
6408 Constant c = Constantify (type, RequestedType.Location);
6410 return ReducedExpression.Create (c, this);
6413 if (type.IsDelegate) {
6414 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
6417 var tparam = type as TypeParameterSpec;
6418 if (tparam != null) {
6420 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
6421 // where type parameter constraint is inflated to struct
6423 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
6424 ec.Report.Error (304, loc,
6425 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
6426 type.GetSignatureForError ());
6429 if ((arguments != null) && (arguments.Count != 0)) {
6430 ec.Report.Error (417, loc,
6431 "`{0}': cannot provide arguments when creating an instance of a variable type",
6432 type.GetSignatureForError ());
6438 if (type.IsStatic) {
6439 ec.Report.SymbolRelatedToPreviousError (type);
6440 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
6444 if (type.IsInterface || type.IsAbstract){
6445 if (!TypeManager.IsGenericType (type)) {
6446 RequestedType = CheckComImport (ec);
6447 if (RequestedType != null)
6448 return RequestedType;
6451 ec.Report.SymbolRelatedToPreviousError (type);
6452 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
6457 // Any struct always defines parameterless constructor
6459 if (type.IsStruct && arguments == null)
6463 if (arguments != null) {
6464 arguments.Resolve (ec, out dynamic);
6469 method = ConstructorLookup (ec, type, ref arguments, loc);
6472 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6473 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
6479 bool DoEmitTypeParameter (EmitContext ec)
6481 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
6485 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
6486 var tparam = (TypeParameterSpec) type;
6488 if (tparam.IsReferenceType) {
6489 ec.Emit (OpCodes.Call, ctor_factory);
6493 // Allow DoEmit() to be called multiple times.
6494 // We need to create a new LocalTemporary each time since
6495 // you can't share LocalBuilders among ILGeneators.
6496 LocalTemporary temp = new LocalTemporary (type);
6498 Label label_activator = ec.DefineLabel ();
6499 Label label_end = ec.DefineLabel ();
6501 temp.AddressOf (ec, AddressOp.Store);
6502 ec.Emit (OpCodes.Initobj, type);
6505 ec.Emit (OpCodes.Box, type);
6506 ec.Emit (OpCodes.Brfalse, label_activator);
6508 temp.AddressOf (ec, AddressOp.Store);
6509 ec.Emit (OpCodes.Initobj, type);
6512 ec.Emit (OpCodes.Br_S, label_end);
6514 ec.MarkLabel (label_activator);
6516 ec.Emit (OpCodes.Call, ctor_factory);
6517 ec.MarkLabel (label_end);
6522 // This Emit can be invoked in two contexts:
6523 // * As a mechanism that will leave a value on the stack (new object)
6524 // * As one that wont (init struct)
6526 // If we are dealing with a ValueType, we have a few
6527 // situations to deal with:
6529 // * The target is a ValueType, and we have been provided
6530 // the instance (this is easy, we are being assigned).
6532 // * The target of New is being passed as an argument,
6533 // to a boxing operation or a function that takes a
6536 // In this case, we need to create a temporary variable
6537 // that is the argument of New.
6539 // Returns whether a value is left on the stack
6541 // *** Implementation note ***
6543 // To benefit from this optimization, each assignable expression
6544 // has to manually cast to New and call this Emit.
6546 // TODO: It's worth to implement it for arrays and fields
6548 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
6550 bool is_value_type = TypeSpec.IsValueType (type);
6551 VariableReference vr = target as VariableReference;
6553 if (target != null && is_value_type && (vr != null || method == null)) {
6554 target.AddressOf (ec, AddressOp.Store);
6555 } else if (vr != null && vr.IsRef) {
6559 if (arguments != null) {
6560 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
6561 arguments = arguments.Emit (ec, false, true);
6563 arguments.Emit (ec);
6566 if (is_value_type) {
6567 if (method == null) {
6568 ec.Emit (OpCodes.Initobj, type);
6573 ec.MarkCallEntry (loc);
6574 ec.Emit (OpCodes.Call, method);
6579 if (type is TypeParameterSpec)
6580 return DoEmitTypeParameter (ec);
6582 ec.MarkCallEntry (loc);
6583 ec.Emit (OpCodes.Newobj, method);
6587 public override void Emit (EmitContext ec)
6589 LocalTemporary v = null;
6590 if (method == null && TypeSpec.IsValueType (type)) {
6591 // TODO: Use temporary variable from pool
6592 v = new LocalTemporary (type);
6599 public override void EmitStatement (EmitContext ec)
6601 LocalTemporary v = null;
6602 if (method == null && TypeSpec.IsValueType (type)) {
6603 // TODO: Use temporary variable from pool
6604 v = new LocalTemporary (type);
6608 ec.Emit (OpCodes.Pop);
6611 public void AddressOf (EmitContext ec, AddressOp mode)
6613 EmitAddressOf (ec, mode);
6616 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
6618 LocalTemporary value_target = new LocalTemporary (type);
6620 if (type is TypeParameterSpec) {
6621 DoEmitTypeParameter (ec);
6622 value_target.Store (ec);
6623 value_target.AddressOf (ec, mode);
6624 return value_target;
6627 value_target.AddressOf (ec, AddressOp.Store);
6629 if (method == null) {
6630 ec.Emit (OpCodes.Initobj, type);
6632 if (arguments != null)
6633 arguments.Emit (ec);
6635 ec.Emit (OpCodes.Call, method);
6638 value_target.AddressOf (ec, mode);
6639 return value_target;
6642 protected override void CloneTo (CloneContext clonectx, Expression t)
6644 New target = (New) t;
6646 target.RequestedType = RequestedType.Clone (clonectx);
6647 if (arguments != null){
6648 target.arguments = arguments.Clone (clonectx);
6652 public override SLE.Expression MakeExpression (BuilderContext ctx)
6655 return base.MakeExpression (ctx);
6657 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
6661 public override object Accept (StructuralVisitor visitor)
6663 return visitor.Visit (this);
6668 // Array initializer expression, the expression is allowed in
6669 // variable or field initialization only which makes it tricky as
6670 // the type has to be infered based on the context either from field
6671 // type or variable type (think of multiple declarators)
6673 public class ArrayInitializer : Expression
6675 List<Expression> elements;
6676 BlockVariable variable;
6678 public ArrayInitializer (List<Expression> init, Location loc)
6684 public ArrayInitializer (int count, Location loc)
6685 : this (new List<Expression> (count), loc)
6689 public ArrayInitializer (Location loc)
6697 get { return elements.Count; }
6700 public List<Expression> Elements {
6706 public Expression this [int index] {
6708 return elements [index];
6712 public BlockVariable VariableDeclaration {
6723 public void Add (Expression expr)
6725 elements.Add (expr);
6728 public override bool ContainsEmitWithAwait ()
6730 throw new NotSupportedException ();
6733 public override Expression CreateExpressionTree (ResolveContext ec)
6735 throw new NotSupportedException ("ET");
6738 protected override void CloneTo (CloneContext clonectx, Expression t)
6740 var target = (ArrayInitializer) t;
6742 target.elements = new List<Expression> (elements.Count);
6743 foreach (var element in elements)
6744 target.elements.Add (element.Clone (clonectx));
6747 protected override Expression DoResolve (ResolveContext rc)
6749 var current_field = rc.CurrentMemberDefinition as FieldBase;
6750 TypeExpression type;
6751 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6752 type = new TypeExpression (current_field.MemberType, current_field.Location);
6753 } else if (variable != null) {
6754 if (variable.TypeExpression is VarExpr) {
6755 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6756 return EmptyExpression.Null;
6759 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6761 throw new NotImplementedException ("Unexpected array initializer context");
6764 return new ArrayCreation (type, this).Resolve (rc);
6767 public override void Emit (EmitContext ec)
6769 throw new InternalErrorException ("Missing Resolve call");
6772 public override object Accept (StructuralVisitor visitor)
6774 return visitor.Visit (this);
6779 /// 14.5.10.2: Represents an array creation expression.
6783 /// There are two possible scenarios here: one is an array creation
6784 /// expression that specifies the dimensions and optionally the
6785 /// initialization data and the other which does not need dimensions
6786 /// specified but where initialization data is mandatory.
6788 public class ArrayCreation : Expression
6790 FullNamedExpression requested_base_type;
6791 ArrayInitializer initializers;
6794 // The list of Argument types.
6795 // This is used to construct the `newarray' or constructor signature
6797 protected List<Expression> arguments;
6799 protected TypeSpec array_element_type;
6801 protected int dimensions;
6802 protected readonly ComposedTypeSpecifier rank;
6803 Expression first_emit;
6804 LocalTemporary first_emit_temp;
6806 protected List<Expression> array_data;
6808 Dictionary<int, int> bounds;
6811 // The number of constants in array initializers
6812 int const_initializers_count;
6813 bool only_constant_initializers;
6815 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6816 : this (requested_base_type, rank, initializers, l)
6818 arguments = new List<Expression> (exprs);
6819 num_arguments = arguments.Count;
6823 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6825 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6827 this.requested_base_type = requested_base_type;
6829 this.initializers = initializers;
6833 num_arguments = rank.Dimension;
6837 // For compiler generated single dimensional arrays only
6839 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6840 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6845 // For expressions like int[] foo = { 1, 2, 3 };
6847 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6848 : this (requested_base_type, null, initializers, initializers.Location)
6852 public ComposedTypeSpecifier Rank {
6858 public FullNamedExpression TypeExpression {
6860 return this.requested_base_type;
6864 public ArrayInitializer Initializers {
6866 return this.initializers;
6870 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6872 if (initializers != null && bounds == null) {
6874 // We use this to store all the data values in the order in which we
6875 // will need to store them in the byte blob later
6877 array_data = new List<Expression> (probe.Count);
6878 bounds = new Dictionary<int, int> ();
6881 if (specified_dims) {
6882 Expression a = arguments [idx];
6887 a = ConvertExpressionToArrayIndex (ec, a);
6893 if (initializers != null) {
6894 Constant c = a as Constant;
6895 if (c == null && a is ArrayIndexCast)
6896 c = ((ArrayIndexCast) a).Child as Constant;
6899 ec.Report.Error (150, a.Location, "A constant value is expected");
6905 value = System.Convert.ToInt32 (c.GetValue ());
6907 ec.Report.Error (150, a.Location, "A constant value is expected");
6911 // TODO: probe.Count does not fit ulong in
6912 if (value != probe.Count) {
6913 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6917 bounds[idx] = value;
6921 if (initializers == null)
6924 for (int i = 0; i < probe.Count; ++i) {
6926 if (o is ArrayInitializer) {
6927 var sub_probe = o as ArrayInitializer;
6928 if (idx + 1 >= dimensions){
6929 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6933 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
6934 if (!bounds.ContainsKey(idx + 1))
6935 bounds[idx + 1] = sub_probe.Count;
6937 if (bounds[idx + 1] != sub_probe.Count) {
6938 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
6942 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6945 } else if (child_bounds > 1) {
6946 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6948 Expression element = ResolveArrayElement (ec, o);
6949 if (element == null)
6952 // Initializers with the default values can be ignored
6953 Constant c = element as Constant;
6955 if (!c.IsDefaultInitializer (array_element_type)) {
6956 ++const_initializers_count;
6959 only_constant_initializers = false;
6962 array_data.Add (element);
6969 public override bool ContainsEmitWithAwait ()
6971 foreach (var arg in arguments) {
6972 if (arg.ContainsEmitWithAwait ())
6976 return InitializersContainAwait ();
6979 public override Expression CreateExpressionTree (ResolveContext ec)
6983 if (array_data == null) {
6984 args = new Arguments (arguments.Count + 1);
6985 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6986 foreach (Expression a in arguments)
6987 args.Add (new Argument (a.CreateExpressionTree (ec)));
6989 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6992 if (dimensions > 1) {
6993 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6997 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6998 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6999 if (array_data != null) {
7000 for (int i = 0; i < array_data.Count; ++i) {
7001 Expression e = array_data [i];
7002 args.Add (new Argument (e.CreateExpressionTree (ec)));
7006 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7009 void UpdateIndices (ResolveContext rc)
7012 for (var probe = initializers; probe != null;) {
7013 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7015 bounds[i++] = probe.Count;
7017 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7018 probe = (ArrayInitializer) probe[0];
7019 } else if (dimensions > i) {
7027 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7029 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
7032 bool InitializersContainAwait ()
7034 if (array_data == null)
7037 foreach (var expr in array_data) {
7038 if (expr.ContainsEmitWithAwait ())
7045 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
7047 element = element.Resolve (ec);
7048 if (element == null)
7051 if (element is CompoundAssign.TargetExpression) {
7052 if (first_emit != null)
7053 throw new InternalErrorException ("Can only handle one mutator at a time");
7054 first_emit = element;
7055 element = first_emit_temp = new LocalTemporary (element.Type);
7058 return Convert.ImplicitConversionRequired (
7059 ec, element, array_element_type, loc);
7062 protected bool ResolveInitializers (ResolveContext ec)
7065 only_constant_initializers = true;
7068 if (arguments != null) {
7070 for (int i = 0; i < arguments.Count; ++i) {
7071 res &= CheckIndices (ec, initializers, i, true, dimensions);
7072 if (initializers != null)
7079 arguments = new List<Expression> ();
7081 if (!CheckIndices (ec, initializers, 0, false, dimensions))
7090 // Resolved the type of the array
7092 bool ResolveArrayType (ResolveContext ec)
7097 FullNamedExpression array_type_expr;
7098 if (num_arguments > 0) {
7099 array_type_expr = new ComposedCast (requested_base_type, rank);
7101 array_type_expr = requested_base_type;
7104 type = array_type_expr.ResolveAsType (ec);
7105 if (array_type_expr == null)
7108 var ac = type as ArrayContainer;
7110 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
7114 array_element_type = ac.Element;
7115 dimensions = ac.Rank;
7120 protected override Expression DoResolve (ResolveContext ec)
7125 if (!ResolveArrayType (ec))
7129 // validate the initializers and fill in any missing bits
7131 if (!ResolveInitializers (ec))
7134 eclass = ExprClass.Value;
7138 byte [] MakeByteBlob ()
7143 int count = array_data.Count;
7145 TypeSpec element_type = array_element_type;
7146 if (element_type.IsEnum)
7147 element_type = EnumSpec.GetUnderlyingType (element_type);
7149 factor = BuiltinTypeSpec.GetSize (element_type);
7151 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
7153 data = new byte [(count * factor + 3) & ~3];
7156 for (int i = 0; i < count; ++i) {
7157 var c = array_data[i] as Constant;
7163 object v = c.GetValue ();
7165 switch (element_type.BuiltinType) {
7166 case BuiltinTypeSpec.Type.Long:
7167 long lval = (long) v;
7169 for (int j = 0; j < factor; ++j) {
7170 data[idx + j] = (byte) (lval & 0xFF);
7174 case BuiltinTypeSpec.Type.ULong:
7175 ulong ulval = (ulong) v;
7177 for (int j = 0; j < factor; ++j) {
7178 data[idx + j] = (byte) (ulval & 0xFF);
7179 ulval = (ulval >> 8);
7182 case BuiltinTypeSpec.Type.Float:
7183 var fval = SingleConverter.SingleToInt32Bits((float) v);
7185 data[idx] = (byte) (fval & 0xff);
7186 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
7187 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
7188 data[idx + 3] = (byte) (fval >> 24);
7190 case BuiltinTypeSpec.Type.Double:
7191 element = BitConverter.GetBytes ((double) v);
7193 for (int j = 0; j < factor; ++j)
7194 data[idx + j] = element[j];
7196 // FIXME: Handle the ARM float format.
7197 if (!BitConverter.IsLittleEndian)
7198 System.Array.Reverse (data, idx, 8);
7200 case BuiltinTypeSpec.Type.Char:
7201 int chval = (int) ((char) v);
7203 data[idx] = (byte) (chval & 0xff);
7204 data[idx + 1] = (byte) (chval >> 8);
7206 case BuiltinTypeSpec.Type.Short:
7207 int sval = (int) ((short) v);
7209 data[idx] = (byte) (sval & 0xff);
7210 data[idx + 1] = (byte) (sval >> 8);
7212 case BuiltinTypeSpec.Type.UShort:
7213 int usval = (int) ((ushort) v);
7215 data[idx] = (byte) (usval & 0xff);
7216 data[idx + 1] = (byte) (usval >> 8);
7218 case BuiltinTypeSpec.Type.Int:
7221 data[idx] = (byte) (val & 0xff);
7222 data[idx + 1] = (byte) ((val >> 8) & 0xff);
7223 data[idx + 2] = (byte) ((val >> 16) & 0xff);
7224 data[idx + 3] = (byte) (val >> 24);
7226 case BuiltinTypeSpec.Type.UInt:
7227 uint uval = (uint) v;
7229 data[idx] = (byte) (uval & 0xff);
7230 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
7231 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
7232 data[idx + 3] = (byte) (uval >> 24);
7234 case BuiltinTypeSpec.Type.SByte:
7235 data[idx] = (byte) (sbyte) v;
7237 case BuiltinTypeSpec.Type.Byte:
7238 data[idx] = (byte) v;
7240 case BuiltinTypeSpec.Type.Bool:
7241 data[idx] = (byte) ((bool) v ? 1 : 0);
7243 case BuiltinTypeSpec.Type.Decimal:
7244 int[] bits = Decimal.GetBits ((decimal) v);
7247 // FIXME: For some reason, this doesn't work on the MS runtime.
7248 int[] nbits = new int[4];
7254 for (int j = 0; j < 4; j++) {
7255 data[p++] = (byte) (nbits[j] & 0xff);
7256 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
7257 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
7258 data[p++] = (byte) (nbits[j] >> 24);
7262 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
7271 #if NET_4_0 || MONODROID
7272 public override SLE.Expression MakeExpression (BuilderContext ctx)
7275 return base.MakeExpression (ctx);
7277 var initializers = new SLE.Expression [array_data.Count];
7278 for (var i = 0; i < initializers.Length; i++) {
7279 if (array_data [i] == null)
7280 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
7282 initializers [i] = array_data [i].MakeExpression (ctx);
7285 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
7291 // Emits the initializers for the array
7293 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
7295 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
7300 // First, the static data
7302 byte [] data = MakeByteBlob ();
7303 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
7305 if (stackArray == null) {
7306 ec.Emit (OpCodes.Dup);
7308 stackArray.Emit (ec);
7311 ec.Emit (OpCodes.Ldtoken, fb);
7312 ec.Emit (OpCodes.Call, m);
7317 // Emits pieces of the array that can not be computed at compile
7318 // time (variables and string locations).
7320 // This always expect the top value on the stack to be the array
7322 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
7324 int dims = bounds.Count;
7325 var current_pos = new int [dims];
7327 for (int i = 0; i < array_data.Count; i++){
7329 Expression e = array_data [i];
7330 var c = e as Constant;
7332 // Constant can be initialized via StaticInitializer
7333 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
7337 if (stackArray != null) {
7338 if (e.ContainsEmitWithAwait ()) {
7339 e = e.EmitToField (ec);
7342 stackArray.Emit (ec);
7344 ec.Emit (OpCodes.Dup);
7347 for (int idx = 0; idx < dims; idx++)
7348 ec.EmitInt (current_pos [idx]);
7351 // If we are dealing with a struct, get the
7352 // address of it, so we can store it.
7354 if (dims == 1 && etype.IsStruct) {
7355 switch (etype.BuiltinType) {
7356 case BuiltinTypeSpec.Type.Byte:
7357 case BuiltinTypeSpec.Type.SByte:
7358 case BuiltinTypeSpec.Type.Bool:
7359 case BuiltinTypeSpec.Type.Short:
7360 case BuiltinTypeSpec.Type.UShort:
7361 case BuiltinTypeSpec.Type.Char:
7362 case BuiltinTypeSpec.Type.Int:
7363 case BuiltinTypeSpec.Type.UInt:
7364 case BuiltinTypeSpec.Type.Long:
7365 case BuiltinTypeSpec.Type.ULong:
7366 case BuiltinTypeSpec.Type.Float:
7367 case BuiltinTypeSpec.Type.Double:
7370 ec.Emit (OpCodes.Ldelema, etype);
7377 ec.EmitArrayStore ((ArrayContainer) type);
7383 for (int j = dims - 1; j >= 0; j--){
7385 if (current_pos [j] < bounds [j])
7387 current_pos [j] = 0;
7392 public override void Emit (EmitContext ec)
7394 EmitToFieldSource (ec);
7397 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
7399 if (first_emit != null) {
7400 first_emit.Emit (ec);
7401 first_emit_temp.Store (ec);
7404 FieldExpr await_stack_field;
7405 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
7406 await_stack_field = ec.GetTemporaryField (type);
7409 await_stack_field = null;
7412 EmitExpressionsList (ec, arguments);
7414 ec.EmitArrayNew ((ArrayContainer) type);
7416 if (initializers == null)
7417 return await_stack_field;
7419 if (await_stack_field != null)
7420 await_stack_field.EmitAssignFromStack (ec);
7424 // Emit static initializer for arrays which contain more than 2 items and
7425 // the static initializer will initialize at least 25% of array values or there
7426 // is more than 10 items to be initialized
7428 // NOTE: const_initializers_count does not contain default constant values.
7430 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
7431 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
7432 EmitStaticInitializers (ec, await_stack_field);
7434 if (!only_constant_initializers)
7435 EmitDynamicInitializers (ec, false, await_stack_field);
7439 EmitDynamicInitializers (ec, true, await_stack_field);
7442 if (first_emit_temp != null)
7443 first_emit_temp.Release (ec);
7445 return await_stack_field;
7448 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7450 // no multi dimensional or jagged arrays
7451 if (arguments.Count != 1 || array_element_type.IsArray) {
7452 base.EncodeAttributeValue (rc, enc, targetType);
7456 // No array covariance, except for array -> object
7457 if (type != targetType) {
7458 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
7459 base.EncodeAttributeValue (rc, enc, targetType);
7463 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
7464 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7469 // Single dimensional array of 0 size
7470 if (array_data == null) {
7471 IntConstant ic = arguments[0] as IntConstant;
7472 if (ic == null || !ic.IsDefaultValue) {
7473 base.EncodeAttributeValue (rc, enc, targetType);
7481 enc.Encode (array_data.Count);
7482 foreach (var element in array_data) {
7483 element.EncodeAttributeValue (rc, enc, array_element_type);
7487 protected override void CloneTo (CloneContext clonectx, Expression t)
7489 ArrayCreation target = (ArrayCreation) t;
7491 if (requested_base_type != null)
7492 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
7494 if (arguments != null){
7495 target.arguments = new List<Expression> (arguments.Count);
7496 foreach (Expression e in arguments)
7497 target.arguments.Add (e.Clone (clonectx));
7500 if (initializers != null)
7501 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
7504 public override object Accept (StructuralVisitor visitor)
7506 return visitor.Visit (this);
7511 // Represents an implicitly typed array epxression
7513 class ImplicitlyTypedArrayCreation : ArrayCreation
7515 TypeInferenceContext best_type_inference;
7517 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7518 : base (null, rank, initializers, loc)
7522 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
7523 : base (null, initializers, loc)
7527 protected override Expression DoResolve (ResolveContext ec)
7532 dimensions = rank.Dimension;
7534 best_type_inference = new TypeInferenceContext ();
7536 if (!ResolveInitializers (ec))
7539 best_type_inference.FixAllTypes (ec);
7540 array_element_type = best_type_inference.InferredTypeArguments[0];
7541 best_type_inference = null;
7543 if (array_element_type == null ||
7544 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
7545 arguments.Count != rank.Dimension) {
7546 ec.Report.Error (826, loc,
7547 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
7552 // At this point we found common base type for all initializer elements
7553 // but we have to be sure that all static initializer elements are of
7556 UnifyInitializerElement (ec);
7558 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
7559 eclass = ExprClass.Value;
7564 // Converts static initializer only
7566 void UnifyInitializerElement (ResolveContext ec)
7568 for (int i = 0; i < array_data.Count; ++i) {
7569 Expression e = array_data[i];
7571 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
7575 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
7577 element = element.Resolve (ec);
7578 if (element != null)
7579 best_type_inference.AddCommonTypeBound (element.Type);
7585 sealed class CompilerGeneratedThis : This
7587 public CompilerGeneratedThis (TypeSpec type, Location loc)
7591 eclass = ExprClass.Variable;
7594 protected override Expression DoResolve (ResolveContext ec)
7599 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7606 /// Represents the `this' construct
7609 public class This : VariableReference
7611 sealed class ThisVariable : ILocalVariable
7613 public static readonly ILocalVariable Instance = new ThisVariable ();
7615 public void Emit (EmitContext ec)
7620 public void EmitAssign (EmitContext ec)
7622 throw new InvalidOperationException ();
7625 public void EmitAddressOf (EmitContext ec)
7631 VariableInfo variable_info;
7633 public This (Location loc)
7640 public override string Name {
7641 get { return "this"; }
7644 public override bool IsLockedByStatement {
7652 public override bool IsRef {
7653 get { return type.IsStruct; }
7656 public override bool IsSideEffectFree {
7662 protected override ILocalVariable Variable {
7663 get { return ThisVariable.Instance; }
7666 public override VariableInfo VariableInfo {
7667 get { return variable_info; }
7670 public override bool IsFixed {
7671 get { return false; }
7676 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
7679 // It's null for all cases when we don't need to check `this'
7680 // definitive assignment
7682 if (variable_info == null)
7685 if (rc.OmitStructFlowAnalysis)
7688 if (!variable_info.IsAssigned (rc)) {
7689 rc.Report.Error (188, loc,
7690 "The `this' object cannot be used before all of its fields are assigned to");
7694 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7696 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7697 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7698 } else if (ec.CurrentAnonymousMethod != null) {
7699 ec.Report.Error (1673, loc,
7700 "Anonymous methods inside structs cannot access instance members of `this'. " +
7701 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7703 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7707 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7712 AnonymousMethodStorey storey = ae.Storey;
7713 return storey != null ? storey.HoistedThis : null;
7716 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7718 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7721 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7724 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7730 public virtual void ResolveBase (ResolveContext ec)
7732 eclass = ExprClass.Variable;
7733 type = ec.CurrentType;
7735 if (!IsThisAvailable (ec, false)) {
7736 Error_ThisNotAvailable (ec);
7740 var block = ec.CurrentBlock;
7741 if (block != null) {
7742 var top = block.ParametersBlock.TopBlock;
7743 if (top.ThisVariable != null)
7744 variable_info = top.ThisVariable.VariableInfo;
7746 AnonymousExpression am = ec.CurrentAnonymousMethod;
7747 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7749 // Hoisted this is almost like hoisted variable but not exactly. When
7750 // there is no variable hoisted we can simply emit an instance method
7751 // without lifting this into a storey. Unfotunatelly this complicates
7752 // things in other cases because we don't know where this will be hoisted
7753 // until top-level block is fully resolved
7755 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7756 am.SetHasThisAccess ();
7761 protected override Expression DoResolve (ResolveContext ec)
7765 CheckStructThisDefiniteAssignment (ec);
7770 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7772 if (eclass == ExprClass.Unresolved)
7775 if (variable_info != null)
7776 variable_info.SetAssigned (ec);
7779 if (right_side == EmptyExpression.UnaryAddress)
7780 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7781 else if (right_side == EmptyExpression.OutAccess)
7782 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7784 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7790 public override int GetHashCode()
7792 throw new NotImplementedException ();
7795 public override bool Equals (object obj)
7797 This t = obj as This;
7804 protected override void CloneTo (CloneContext clonectx, Expression t)
7809 public override void SetHasAddressTaken ()
7814 public override void VerifyAssigned (ResolveContext rc)
7818 public override object Accept (StructuralVisitor visitor)
7820 return visitor.Visit (this);
7825 /// Represents the `__arglist' construct
7827 public class ArglistAccess : Expression
7829 public ArglistAccess (Location loc)
7834 protected override void CloneTo (CloneContext clonectx, Expression target)
7839 public override bool ContainsEmitWithAwait ()
7844 public override Expression CreateExpressionTree (ResolveContext ec)
7846 throw new NotSupportedException ("ET");
7849 protected override Expression DoResolve (ResolveContext ec)
7851 eclass = ExprClass.Variable;
7852 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
7854 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7855 ec.Report.Error (190, loc,
7856 "The __arglist construct is valid only within a variable argument method");
7862 public override void Emit (EmitContext ec)
7864 ec.Emit (OpCodes.Arglist);
7867 public override object Accept (StructuralVisitor visitor)
7869 return visitor.Visit (this);
7874 /// Represents the `__arglist (....)' construct
7876 public class Arglist : Expression
7878 Arguments arguments;
7880 public Arglist (Location loc)
7885 public Arglist (Arguments args, Location l)
7891 public Arguments Arguments {
7897 public MetaType[] ArgumentTypes {
7899 if (arguments == null)
7900 return MetaType.EmptyTypes;
7902 var retval = new MetaType[arguments.Count];
7903 for (int i = 0; i < retval.Length; i++)
7904 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
7910 public override bool ContainsEmitWithAwait ()
7912 throw new NotImplementedException ();
7915 public override Expression CreateExpressionTree (ResolveContext ec)
7917 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7921 protected override Expression DoResolve (ResolveContext ec)
7923 eclass = ExprClass.Variable;
7924 type = InternalType.Arglist;
7925 if (arguments != null) {
7926 bool dynamic; // Can be ignored as there is always only 1 overload
7927 arguments.Resolve (ec, out dynamic);
7933 public override void Emit (EmitContext ec)
7935 if (arguments != null)
7936 arguments.Emit (ec);
7939 protected override void CloneTo (CloneContext clonectx, Expression t)
7941 Arglist target = (Arglist) t;
7943 if (arguments != null)
7944 target.arguments = arguments.Clone (clonectx);
7947 public override object Accept (StructuralVisitor visitor)
7949 return visitor.Visit (this);
7953 public class RefValueExpr : ShimExpression, IAssignMethod
7955 FullNamedExpression texpr;
7957 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7964 public FullNamedExpression TypeExpression {
7970 public override bool ContainsEmitWithAwait ()
7975 protected override Expression DoResolve (ResolveContext rc)
7977 expr = expr.Resolve (rc);
7978 type = texpr.ResolveAsType (rc);
7979 if (expr == null || type == null)
7982 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7983 eclass = ExprClass.Value;
7987 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7989 return DoResolve (rc);
7992 public override void Emit (EmitContext ec)
7995 ec.Emit (OpCodes.Refanyval, type);
7996 ec.EmitLoadFromPtr (type);
7999 public void Emit (EmitContext ec, bool leave_copy)
8001 throw new NotImplementedException ();
8004 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8007 ec.Emit (OpCodes.Refanyval, type);
8010 LocalTemporary temporary = null;
8012 ec.Emit (OpCodes.Dup);
8013 temporary = new LocalTemporary (source.Type);
8014 temporary.Store (ec);
8017 ec.EmitStoreFromPtr (type);
8019 if (temporary != null) {
8020 temporary.Emit (ec);
8021 temporary.Release (ec);
8025 public override object Accept (StructuralVisitor visitor)
8027 return visitor.Visit (this);
8031 public class RefTypeExpr : ShimExpression
8033 public RefTypeExpr (Expression expr, Location loc)
8039 protected override Expression DoResolve (ResolveContext rc)
8041 expr = expr.Resolve (rc);
8045 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8049 type = rc.BuiltinTypes.Type;
8050 eclass = ExprClass.Value;
8054 public override void Emit (EmitContext ec)
8057 ec.Emit (OpCodes.Refanytype);
8058 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8060 ec.Emit (OpCodes.Call, m);
8063 public override object Accept (StructuralVisitor visitor)
8065 return visitor.Visit (this);
8069 public class MakeRefExpr : ShimExpression
8071 public MakeRefExpr (Expression expr, Location loc)
8077 public override bool ContainsEmitWithAwait ()
8079 throw new NotImplementedException ();
8082 protected override Expression DoResolve (ResolveContext rc)
8084 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8085 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8086 eclass = ExprClass.Value;
8090 public override void Emit (EmitContext ec)
8092 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8093 ec.Emit (OpCodes.Mkrefany, expr.Type);
8096 public override object Accept (StructuralVisitor visitor)
8098 return visitor.Visit (this);
8103 /// Implements the typeof operator
8105 public class TypeOf : Expression {
8106 FullNamedExpression QueriedType;
8109 public TypeOf (FullNamedExpression queried_type, Location l)
8111 QueriedType = queried_type;
8116 // Use this constructor for any compiler generated typeof expression
8118 public TypeOf (TypeSpec type, Location loc)
8120 this.typearg = type;
8126 public override bool IsSideEffectFree {
8132 public TypeSpec TypeArgument {
8138 public FullNamedExpression TypeExpression {
8147 protected override void CloneTo (CloneContext clonectx, Expression t)
8149 TypeOf target = (TypeOf) t;
8150 if (QueriedType != null)
8151 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
8154 public override bool ContainsEmitWithAwait ()
8159 public override Expression CreateExpressionTree (ResolveContext ec)
8161 Arguments args = new Arguments (2);
8162 args.Add (new Argument (this));
8163 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8164 return CreateExpressionFactoryCall (ec, "Constant", args);
8167 protected override Expression DoResolve (ResolveContext ec)
8169 if (eclass != ExprClass.Unresolved)
8172 if (typearg == null) {
8174 // Pointer types are allowed without explicit unsafe, they are just tokens
8176 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
8177 typearg = QueriedType.ResolveAsType (ec);
8180 if (typearg == null)
8183 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8184 ec.Report.Error (1962, QueriedType.Location,
8185 "The typeof operator cannot be used on the dynamic type");
8189 type = ec.BuiltinTypes.Type;
8191 // Even though what is returned is a type object, it's treated as a value by the compiler.
8192 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
8193 eclass = ExprClass.Value;
8197 static bool ContainsDynamicType (TypeSpec type)
8199 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
8202 var element_container = type as ElementTypeSpec;
8203 if (element_container != null)
8204 return ContainsDynamicType (element_container.Element);
8206 foreach (var t in type.TypeArguments) {
8207 if (ContainsDynamicType (t)) {
8215 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
8217 // Target type is not System.Type therefore must be object
8218 // and we need to use different encoding sequence
8219 if (targetType != type)
8222 if (typearg is InflatedTypeSpec) {
8225 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
8226 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
8227 typearg.GetSignatureForError ());
8231 gt = gt.DeclaringType;
8232 } while (gt != null);
8235 if (ContainsDynamicType (typearg)) {
8236 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8240 enc.EncodeTypeName (typearg);
8243 public override void Emit (EmitContext ec)
8245 ec.Emit (OpCodes.Ldtoken, typearg);
8246 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8248 ec.Emit (OpCodes.Call, m);
8251 public override object Accept (StructuralVisitor visitor)
8253 return visitor.Visit (this);
8257 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
8259 public TypeOfMethod (MethodSpec method, Location loc)
8260 : base (method, loc)
8264 protected override Expression DoResolve (ResolveContext ec)
8266 if (member.IsConstructor) {
8267 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
8269 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
8275 return base.DoResolve (ec);
8278 public override void Emit (EmitContext ec)
8280 ec.Emit (OpCodes.Ldtoken, member);
8283 ec.Emit (OpCodes.Castclass, type);
8286 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8288 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
8291 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8293 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
8297 abstract class TypeOfMember<T> : Expression where T : MemberSpec
8299 protected readonly T member;
8301 protected TypeOfMember (T member, Location loc)
8303 this.member = member;
8307 public override bool IsSideEffectFree {
8313 public override bool ContainsEmitWithAwait ()
8318 public override Expression CreateExpressionTree (ResolveContext ec)
8320 Arguments args = new Arguments (2);
8321 args.Add (new Argument (this));
8322 args.Add (new Argument (new TypeOf (type, loc)));
8323 return CreateExpressionFactoryCall (ec, "Constant", args);
8326 protected override Expression DoResolve (ResolveContext ec)
8328 eclass = ExprClass.Value;
8332 public override void Emit (EmitContext ec)
8334 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
8335 PredefinedMember<MethodSpec> p;
8337 p = GetTypeFromHandleGeneric (ec);
8338 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
8340 p = GetTypeFromHandle (ec);
8343 var mi = p.Resolve (loc);
8345 ec.Emit (OpCodes.Call, mi);
8348 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
8349 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
8352 sealed class TypeOfField : TypeOfMember<FieldSpec>
8354 public TypeOfField (FieldSpec field, Location loc)
8359 protected override Expression DoResolve (ResolveContext ec)
8361 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
8365 return base.DoResolve (ec);
8368 public override void Emit (EmitContext ec)
8370 ec.Emit (OpCodes.Ldtoken, member);
8374 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8376 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
8379 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8381 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
8386 /// Implements the sizeof expression
8388 public class SizeOf : Expression {
8389 readonly Expression texpr;
8390 TypeSpec type_queried;
8392 public SizeOf (Expression queried_type, Location l)
8394 this.texpr = queried_type;
8398 public override bool IsSideEffectFree {
8404 public Expression TypeExpression {
8410 public override bool ContainsEmitWithAwait ()
8415 public override Expression CreateExpressionTree (ResolveContext ec)
8417 Error_PointerInsideExpressionTree (ec);
8421 protected override Expression DoResolve (ResolveContext ec)
8423 type_queried = texpr.ResolveAsType (ec);
8424 if (type_queried == null)
8427 if (type_queried.IsEnum)
8428 type_queried = EnumSpec.GetUnderlyingType (type_queried);
8430 int size_of = BuiltinTypeSpec.GetSize (type_queried);
8432 return new IntConstant (ec.BuiltinTypes, size_of, loc);
8435 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
8440 ec.Report.Error (233, loc,
8441 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
8442 type_queried.GetSignatureForError ());
8445 type = ec.BuiltinTypes.Int;
8446 eclass = ExprClass.Value;
8450 public override void Emit (EmitContext ec)
8452 ec.Emit (OpCodes.Sizeof, type_queried);
8455 protected override void CloneTo (CloneContext clonectx, Expression t)
8459 public override object Accept (StructuralVisitor visitor)
8461 return visitor.Visit (this);
8466 /// Implements the qualified-alias-member (::) expression.
8468 public class QualifiedAliasMember : MemberAccess
8470 readonly string alias;
8471 public static readonly string GlobalAlias = "global";
8473 public QualifiedAliasMember (string alias, string identifier, Location l)
8474 : base (null, identifier, l)
8479 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
8480 : base (null, identifier, targs, l)
8485 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
8486 : base (null, identifier, arity, l)
8491 public string Alias {
8497 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
8499 if (alias == GlobalAlias) {
8500 expr = ec.Module.GlobalRootNamespace;
8501 return base.ResolveAsTypeOrNamespace (ec);
8504 int errors = ec.Module.Compiler.Report.Errors;
8505 expr = ec.LookupNamespaceAlias (alias);
8507 if (errors == ec.Module.Compiler.Report.Errors)
8508 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
8512 return base.ResolveAsTypeOrNamespace (ec);
8515 protected override Expression DoResolve (ResolveContext ec)
8517 return ResolveAsTypeOrNamespace (ec);
8520 public override string GetSignatureForError ()
8523 if (targs != null) {
8524 name = Name + "<" + targs.GetSignatureForError () + ">";
8527 return alias + "::" + name;
8530 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8532 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
8533 rc.Module.Compiler.Report.Error (687, loc,
8534 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
8535 GetSignatureForError ());
8540 return DoResolve (rc);
8543 protected override void CloneTo (CloneContext clonectx, Expression t)
8548 public override object Accept (StructuralVisitor visitor)
8550 return visitor.Visit (this);
8555 /// Implements the member access expression
8557 public class MemberAccess : ATypeNameExpression
8559 protected Expression expr;
8561 public MemberAccess (Expression expr, string id)
8562 : base (id, expr.Location)
8567 public MemberAccess (Expression expr, string identifier, Location loc)
8568 : base (identifier, loc)
8573 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
8574 : base (identifier, args, loc)
8579 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
8580 : base (identifier, arity, loc)
8585 public Expression LeftExpression {
8591 public override Location StartLocation {
8593 return expr == null ? loc : expr.StartLocation;
8597 protected override Expression DoResolve (ResolveContext rc)
8599 var e = DoResolveName (rc, null);
8601 if (!rc.OmitStructFlowAnalysis) {
8602 var fe = e as FieldExpr;
8604 fe.VerifyAssignedStructField (rc, null);
8611 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
8613 var e = DoResolveName (rc, rhs);
8615 if (!rc.OmitStructFlowAnalysis) {
8616 var fe = e as FieldExpr;
8617 if (fe != null && fe.InstanceExpression is FieldExpr) {
8618 fe = (FieldExpr) fe.InstanceExpression;
8619 fe.VerifyAssignedStructField (rc, rhs);
8626 Expression DoResolveName (ResolveContext rc, Expression right_side)
8628 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
8632 if (right_side != null) {
8633 if (e is TypeExpr) {
8634 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8638 e = e.ResolveLValue (rc, right_side);
8640 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
8646 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8648 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8649 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8651 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8654 public static bool IsValidDotExpression (TypeSpec type)
8656 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8657 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8659 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8662 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8664 var sn = expr as SimpleName;
8665 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8668 // Resolve the expression with flow analysis turned off, we'll do the definite
8669 // assignment checks later. This is because we don't know yet what the expression
8670 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
8671 // definite assignment check on the actual field and not on the whole struct.
8673 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
8675 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8678 // Resolve expression which does have type set as we need expression type
8679 // with disable flow analysis as we don't know whether left side expression
8680 // is used as variable or type
8682 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8683 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
8684 expr = expr.Resolve (rc);
8686 } else if (expr is TypeParameterExpr) {
8687 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8691 expr = expr.Resolve (rc, flags);
8698 Namespace ns = expr as Namespace;
8700 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8702 if (retval == null) {
8703 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8707 if (HasTypeArguments)
8708 return new GenericTypeExpr (retval.Type, targs, loc);
8714 TypeSpec expr_type = expr.Type;
8715 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8716 me = expr as MemberExpr;
8718 me.ResolveInstanceExpression (rc, null);
8721 // Run defined assigned checks on expressions resolved with
8722 // disabled flow-analysis
8725 var vr = expr as VariableReference;
8727 vr.VerifyAssigned (rc);
8730 Arguments args = new Arguments (1);
8731 args.Add (new Argument (expr));
8732 return new DynamicMemberBinder (Name, args, loc);
8735 if (!IsValidDotExpression (expr_type)) {
8736 Error_OperatorCannotBeApplied (rc, expr_type);
8740 var lookup_arity = Arity;
8741 bool errorMode = false;
8742 Expression member_lookup;
8744 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8745 if (member_lookup == null) {
8747 // Try to look for extension method when member lookup failed
8749 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8750 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8751 if (methods != null) {
8752 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8753 if (HasTypeArguments) {
8754 if (!targs.Resolve (rc))
8757 emg.SetTypeArguments (rc, targs);
8761 // Run defined assigned checks on expressions resolved with
8762 // disabled flow-analysis
8764 if (sn != null && !errorMode) {
8765 var vr = expr as VariableReference;
8767 vr.VerifyAssigned (rc);
8770 // TODO: it should really skip the checks bellow
8771 return emg.Resolve (rc);
8777 if (member_lookup == null) {
8778 var dep = expr_type.GetMissingDependencies ();
8780 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8781 } else if (expr is TypeExpr) {
8782 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8784 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8790 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8791 // Leave it to overload resolution to report correct error
8792 } else if (!(member_lookup is TypeExpr)) {
8793 // TODO: rc.SymbolRelatedToPreviousError
8794 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8799 if (member_lookup != null)
8803 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8807 TypeExpr texpr = member_lookup as TypeExpr;
8808 if (texpr != null) {
8809 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8810 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8811 Name, texpr.GetSignatureForError ());
8814 if (!texpr.Type.IsAccessible (rc)) {
8815 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8816 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8820 if (HasTypeArguments) {
8821 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8824 return member_lookup;
8827 me = member_lookup as MemberExpr;
8829 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8833 me = me.ResolveMemberAccess (rc, expr, sn);
8836 if (!targs.Resolve (rc))
8839 me.SetTypeArguments (rc, targs);
8843 // Run defined assigned checks on expressions resolved with
8844 // disabled flow-analysis
8846 if (sn != null && !(me is FieldExpr && TypeSpec.IsValueType (expr_type))) {
8847 var vr = expr as VariableReference;
8849 vr.VerifyAssigned (rc);
8855 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8857 FullNamedExpression fexpr = expr as FullNamedExpression;
8858 if (fexpr == null) {
8859 expr.ResolveAsType (rc);
8863 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8865 if (expr_resolved == null)
8868 Namespace ns = expr_resolved as Namespace;
8870 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8872 if (retval == null) {
8873 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8874 } else if (HasTypeArguments) {
8875 retval = new GenericTypeExpr (retval.Type, targs, loc);
8876 if (retval.ResolveAsType (rc) == null)
8883 var tnew_expr = expr_resolved.ResolveAsType (rc);
8884 if (tnew_expr == null)
8887 TypeSpec expr_type = tnew_expr;
8888 if (TypeManager.IsGenericParameter (expr_type)) {
8889 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8890 tnew_expr.GetSignatureForError ());
8894 var qam = this as QualifiedAliasMember;
8896 rc.Module.Compiler.Report.Error (431, loc,
8897 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8902 TypeSpec nested = null;
8903 while (expr_type != null) {
8904 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8905 if (nested == null) {
8906 if (expr_type == tnew_expr) {
8907 Error_IdentifierNotFound (rc, expr_type, Name);
8911 expr_type = tnew_expr;
8912 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8913 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
8917 if (nested.IsAccessible (rc))
8921 // Keep looking after inaccessible candidate but only if
8922 // we are not in same context as the definition itself
8924 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
8927 expr_type = expr_type.BaseType;
8932 if (HasTypeArguments) {
8933 texpr = new GenericTypeExpr (nested, targs, loc);
8935 texpr = new GenericOpenTypeExpr (nested, loc);
8938 texpr = new TypeExpression (nested, loc);
8941 if (texpr.ResolveAsType (rc) == null)
8947 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
8949 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
8951 if (nested != null) {
8952 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
8956 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
8957 if (any_other_member != null) {
8958 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
8962 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
8963 Name, expr_type.GetSignatureForError ());
8966 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
8968 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
8971 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
8973 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8974 ec.Report.SymbolRelatedToPreviousError (type);
8976 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
8978 // a using directive or an assembly reference
8980 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
8982 missing = "an assembly reference";
8985 ec.Report.Error (1061, loc,
8986 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
8987 type.GetSignatureForError (), name, missing);
8991 base.Error_TypeDoesNotContainDefinition (ec, type, name);
8994 public override string GetSignatureForError ()
8996 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
8999 protected override void CloneTo (CloneContext clonectx, Expression t)
9001 MemberAccess target = (MemberAccess) t;
9003 target.expr = expr.Clone (clonectx);
9006 public override object Accept (StructuralVisitor visitor)
9008 return visitor.Visit (this);
9013 /// Implements checked expressions
9015 public class CheckedExpr : Expression {
9017 public Expression Expr;
9019 public CheckedExpr (Expression e, Location l)
9025 public override bool ContainsEmitWithAwait ()
9027 return Expr.ContainsEmitWithAwait ();
9030 public override Expression CreateExpressionTree (ResolveContext ec)
9032 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9033 return Expr.CreateExpressionTree (ec);
9036 protected override Expression DoResolve (ResolveContext ec)
9038 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9039 Expr = Expr.Resolve (ec);
9044 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9047 eclass = Expr.eclass;
9052 public override void Emit (EmitContext ec)
9054 using (ec.With (EmitContext.Options.CheckedScope, true))
9058 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9060 using (ec.With (EmitContext.Options.CheckedScope, true))
9061 Expr.EmitBranchable (ec, target, on_true);
9064 public override SLE.Expression MakeExpression (BuilderContext ctx)
9066 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9067 return Expr.MakeExpression (ctx);
9071 protected override void CloneTo (CloneContext clonectx, Expression t)
9073 CheckedExpr target = (CheckedExpr) t;
9075 target.Expr = Expr.Clone (clonectx);
9078 public override object Accept (StructuralVisitor visitor)
9080 return visitor.Visit (this);
9085 /// Implements the unchecked expression
9087 public class UnCheckedExpr : Expression {
9089 public Expression Expr;
9091 public UnCheckedExpr (Expression e, Location l)
9097 public override bool ContainsEmitWithAwait ()
9099 return Expr.ContainsEmitWithAwait ();
9102 public override Expression CreateExpressionTree (ResolveContext ec)
9104 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9105 return Expr.CreateExpressionTree (ec);
9108 protected override Expression DoResolve (ResolveContext ec)
9110 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9111 Expr = Expr.Resolve (ec);
9116 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9119 eclass = Expr.eclass;
9124 public override void Emit (EmitContext ec)
9126 using (ec.With (EmitContext.Options.CheckedScope, false))
9130 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9132 using (ec.With (EmitContext.Options.CheckedScope, false))
9133 Expr.EmitBranchable (ec, target, on_true);
9136 protected override void CloneTo (CloneContext clonectx, Expression t)
9138 UnCheckedExpr target = (UnCheckedExpr) t;
9140 target.Expr = Expr.Clone (clonectx);
9143 public override object Accept (StructuralVisitor visitor)
9145 return visitor.Visit (this);
9150 /// An Element Access expression.
9152 /// During semantic analysis these are transformed into
9153 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
9155 public class ElementAccess : Expression
9157 public Arguments Arguments;
9158 public Expression Expr;
9160 public ElementAccess (Expression e, Arguments args, Location loc)
9164 this.Arguments = args;
9167 public override Location StartLocation {
9169 return Expr.StartLocation;
9173 public override bool ContainsEmitWithAwait ()
9175 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
9179 // We perform some simple tests, and then to "split" the emit and store
9180 // code we create an instance of a different class, and return that.
9182 Expression CreateAccessExpression (ResolveContext ec)
9185 return (new ArrayAccess (this, loc));
9188 return MakePointerAccess (ec, type);
9190 FieldExpr fe = Expr as FieldExpr;
9192 var ff = fe.Spec as FixedFieldSpec;
9194 return MakePointerAccess (ec, ff.ElementType);
9198 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
9199 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9200 return new IndexerExpr (indexers, type, this);
9203 if (type != InternalType.ErrorType) {
9204 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
9205 type.GetSignatureForError ());
9211 public override Expression CreateExpressionTree (ResolveContext ec)
9213 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
9214 Expr.CreateExpressionTree (ec));
9216 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
9219 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
9221 if (Arguments.Count != 1){
9222 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
9226 if (Arguments [0] is NamedArgument)
9227 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
9229 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
9230 return new Indirection (p, loc);
9233 protected override Expression DoResolve (ResolveContext ec)
9235 Expr = Expr.Resolve (ec);
9241 // TODO: Create 1 result for Resolve and ResolveLValue ?
9242 var res = CreateAccessExpression (ec);
9246 return res.Resolve (ec);
9249 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
9251 Expr = Expr.Resolve (ec);
9257 var res = CreateAccessExpression (ec);
9261 return res.ResolveLValue (ec, rhs);
9264 public override void Emit (EmitContext ec)
9266 throw new Exception ("Should never be reached");
9269 public static void Error_NamedArgument (NamedArgument na, Report Report)
9271 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
9274 public override string GetSignatureForError ()
9276 return Expr.GetSignatureForError ();
9279 protected override void CloneTo (CloneContext clonectx, Expression t)
9281 ElementAccess target = (ElementAccess) t;
9283 target.Expr = Expr.Clone (clonectx);
9284 if (Arguments != null)
9285 target.Arguments = Arguments.Clone (clonectx);
9288 public override object Accept (StructuralVisitor visitor)
9290 return visitor.Visit (this);
9295 /// Implements array access
9297 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
9299 // Points to our "data" repository
9303 LocalTemporary temp;
9305 bool? has_await_args;
9307 public ArrayAccess (ElementAccess ea_data, Location l)
9313 public void AddressOf (EmitContext ec, AddressOp mode)
9315 var ac = (ArrayContainer) ea.Expr.Type;
9317 LoadInstanceAndArguments (ec, false, false);
9319 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
9320 ec.Emit (OpCodes.Readonly);
9322 ec.EmitArrayAddress (ac);
9325 public override Expression CreateExpressionTree (ResolveContext ec)
9327 return ea.CreateExpressionTree (ec);
9330 public override bool ContainsEmitWithAwait ()
9332 return ea.ContainsEmitWithAwait ();
9335 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9337 return DoResolve (ec);
9340 protected override Expression DoResolve (ResolveContext ec)
9342 // dynamic is used per argument in ConvertExpressionToArrayIndex case
9344 ea.Arguments.Resolve (ec, out dynamic);
9346 var ac = ea.Expr.Type as ArrayContainer;
9347 int rank = ea.Arguments.Count;
9348 if (ac.Rank != rank) {
9349 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
9350 rank.ToString (), ac.Rank.ToString ());
9355 if (type.IsPointer && !ec.IsUnsafe) {
9356 UnsafeError (ec, ea.Location);
9359 foreach (Argument a in ea.Arguments) {
9360 if (a is NamedArgument)
9361 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
9363 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
9366 eclass = ExprClass.Variable;
9371 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
9373 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
9377 // Load the array arguments into the stack.
9379 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
9382 ea.Expr = ea.Expr.EmitToField (ec);
9383 } else if (duplicateArguments) {
9385 ec.Emit (OpCodes.Dup);
9387 var copy = new LocalTemporary (ea.Expr.Type);
9394 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
9395 if (dup_args != null)
9396 ea.Arguments = dup_args;
9399 public void Emit (EmitContext ec, bool leave_copy)
9401 var ac = ea.Expr.Type as ArrayContainer;
9404 ec.EmitLoadFromPtr (type);
9406 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
9407 LoadInstanceAndArguments (ec, false, true);
9410 LoadInstanceAndArguments (ec, false, false);
9411 ec.EmitArrayLoad (ac);
9415 ec.Emit (OpCodes.Dup);
9416 temp = new LocalTemporary (this.type);
9421 public override void Emit (EmitContext ec)
9426 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9428 var ac = (ArrayContainer) ea.Expr.Type;
9429 TypeSpec t = source.Type;
9431 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
9434 // When we are dealing with a struct, get the address of it to avoid value copy
9435 // Same cannot be done for reference type because array covariance and the
9436 // check in ldelema requires to specify the type of array element stored at the index
9438 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
9439 LoadInstanceAndArguments (ec, false, has_await_args.Value);
9441 if (has_await_args.Value) {
9442 if (source.ContainsEmitWithAwait ()) {
9443 source = source.EmitToField (ec);
9448 LoadInstanceAndArguments (ec, isCompound, false);
9453 ec.EmitArrayAddress (ac);
9456 ec.Emit (OpCodes.Dup);
9460 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
9462 if (has_await_args.Value) {
9463 if (source.ContainsEmitWithAwait ())
9464 source = source.EmitToField (ec);
9466 LoadInstanceAndArguments (ec, false, false);
9473 var lt = ea.Expr as LocalTemporary;
9479 ec.Emit (OpCodes.Dup);
9480 temp = new LocalTemporary (this.type);
9485 ec.EmitStoreFromPtr (t);
9487 ec.EmitArrayStore (ac);
9496 public override Expression EmitToField (EmitContext ec)
9499 // Have to be specialized for arrays to get access to
9500 // underlying element. Instead of another result copy we
9501 // need direct access to element
9505 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
9507 ea.Expr = ea.Expr.EmitToField (ec);
9511 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9513 #if NET_4_0 || MONODROID
9514 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9516 throw new NotImplementedException ();
9520 public override SLE.Expression MakeExpression (BuilderContext ctx)
9522 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9525 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
9527 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9528 return Arguments.MakeExpression (ea.Arguments, ctx);
9534 // Indexer access expression
9536 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
9538 IList<MemberSpec> indexers;
9539 Arguments arguments;
9540 TypeSpec queried_type;
9542 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
9543 : base (ea.Location)
9545 this.indexers = indexers;
9546 this.queried_type = queriedType;
9547 this.InstanceExpression = ea.Expr;
9548 this.arguments = ea.Arguments;
9553 protected override Arguments Arguments {
9562 protected override TypeSpec DeclaringType {
9564 return best_candidate.DeclaringType;
9568 public override bool IsInstance {
9574 public override bool IsStatic {
9580 public override string KindName {
9581 get { return "indexer"; }
9584 public override string Name {
9592 public override bool ContainsEmitWithAwait ()
9594 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
9597 public override Expression CreateExpressionTree (ResolveContext ec)
9599 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
9600 InstanceExpression.CreateExpressionTree (ec),
9601 new TypeOfMethod (Getter, loc));
9603 return CreateExpressionFactoryCall (ec, "Call", args);
9606 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9608 LocalTemporary await_source_arg = null;
9611 emitting_compound_assignment = true;
9612 if (source is DynamicExpressionStatement) {
9617 emitting_compound_assignment = false;
9619 if (has_await_arguments) {
9620 await_source_arg = new LocalTemporary (Type);
9621 await_source_arg.Store (ec);
9623 arguments.Add (new Argument (await_source_arg));
9626 temp = await_source_arg;
9629 has_await_arguments = false;
9634 ec.Emit (OpCodes.Dup);
9635 temp = new LocalTemporary (Type);
9641 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9642 source = source.EmitToField (ec);
9644 temp = new LocalTemporary (Type);
9651 arguments.Add (new Argument (source));
9654 var call = new CallEmitter ();
9655 call.InstanceExpression = InstanceExpression;
9656 if (arguments == null)
9657 call.InstanceExpressionOnStack = true;
9659 call.Emit (ec, Setter, arguments, loc);
9664 } else if (leave_copy) {
9668 if (await_source_arg != null) {
9669 await_source_arg.Release (ec);
9673 public override string GetSignatureForError ()
9675 return best_candidate.GetSignatureForError ();
9678 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9681 throw new NotSupportedException ();
9683 var value = new[] { source.MakeExpression (ctx) };
9684 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9685 #if NET_4_0 || MONODROID
9686 return SLE.Expression.Block (
9687 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9690 return args.First ();
9695 public override SLE.Expression MakeExpression (BuilderContext ctx)
9698 return base.MakeExpression (ctx);
9700 var args = Arguments.MakeExpression (arguments, ctx);
9701 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9705 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9707 if (best_candidate != null)
9710 eclass = ExprClass.IndexerAccess;
9713 arguments.Resolve (rc, out dynamic);
9715 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9718 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9719 res.BaseMembersProvider = this;
9720 res.InstanceQualifier = this;
9722 // TODO: Do I need 2 argument sets?
9723 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9724 if (best_candidate != null)
9725 type = res.BestCandidateReturnType;
9726 else if (!res.BestCandidateIsDynamic)
9731 // It has dynamic arguments
9734 Arguments args = new Arguments (arguments.Count + 1);
9736 rc.Report.Error (1972, loc,
9737 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9739 args.Add (new Argument (InstanceExpression));
9741 args.AddRange (arguments);
9743 best_candidate = null;
9744 return new DynamicIndexBinder (args, loc);
9748 // Try to avoid resolving left expression again
9750 if (right_side != null)
9751 ResolveInstanceExpression (rc, right_side);
9756 protected override void CloneTo (CloneContext clonectx, Expression t)
9758 IndexerExpr target = (IndexerExpr) t;
9760 if (arguments != null)
9761 target.arguments = arguments.Clone (clonectx);
9764 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9766 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9769 #region IBaseMembersProvider Members
9771 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9773 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9776 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9778 if (queried_type == member.DeclaringType)
9781 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9782 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9785 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9794 // A base access expression
9796 public class BaseThis : This
9798 public BaseThis (Location loc)
9803 public BaseThis (TypeSpec type, Location loc)
9807 eclass = ExprClass.Variable;
9812 public override string Name {
9820 public override Expression CreateExpressionTree (ResolveContext ec)
9822 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9823 return base.CreateExpressionTree (ec);
9826 public override void Emit (EmitContext ec)
9830 var context_type = ec.CurrentType;
9831 if (context_type.IsStruct) {
9832 ec.Emit (OpCodes.Ldobj, context_type);
9833 ec.Emit (OpCodes.Box, context_type);
9837 protected override void Error_ThisNotAvailable (ResolveContext ec)
9840 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9842 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9846 public override void ResolveBase (ResolveContext ec)
9848 base.ResolveBase (ec);
9849 type = ec.CurrentType.BaseType;
9852 public override object Accept (StructuralVisitor visitor)
9854 return visitor.Visit (this);
9859 /// This class exists solely to pass the Type around and to be a dummy
9860 /// that can be passed to the conversion functions (this is used by
9861 /// foreach implementation to typecast the object return value from
9862 /// get_Current into the proper type. All code has been generated and
9863 /// we only care about the side effect conversions to be performed
9865 /// This is also now used as a placeholder where a no-action expression
9866 /// is needed (the `New' class).
9868 public class EmptyExpression : Expression
9870 sealed class OutAccessExpression : EmptyExpression
9872 public OutAccessExpression (TypeSpec t)
9877 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9879 rc.Report.Error (206, right_side.Location,
9880 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
9886 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
9887 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
9888 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
9889 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
9890 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
9891 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
9892 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
9893 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
9895 public EmptyExpression (TypeSpec t)
9898 eclass = ExprClass.Value;
9899 loc = Location.Null;
9902 public override bool ContainsEmitWithAwait ()
9907 public override Expression CreateExpressionTree (ResolveContext ec)
9909 throw new NotSupportedException ("ET");
9912 protected override Expression DoResolve (ResolveContext ec)
9917 public override void Emit (EmitContext ec)
9919 // nothing, as we only exist to not do anything.
9922 public override void EmitSideEffect (EmitContext ec)
9926 public override object Accept (StructuralVisitor visitor)
9928 return visitor.Visit (this);
9932 sealed class EmptyAwaitExpression : EmptyExpression
9934 public EmptyAwaitExpression (TypeSpec type)
9939 public override bool ContainsEmitWithAwait ()
9946 // Empty statement expression
9948 public sealed class EmptyExpressionStatement : ExpressionStatement
9950 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
9952 private EmptyExpressionStatement ()
9954 loc = Location.Null;
9957 public override bool ContainsEmitWithAwait ()
9962 public override Expression CreateExpressionTree (ResolveContext ec)
9967 public override void EmitStatement (EmitContext ec)
9972 protected override Expression DoResolve (ResolveContext ec)
9974 eclass = ExprClass.Value;
9975 type = ec.BuiltinTypes.Object;
9979 public override void Emit (EmitContext ec)
9984 public override object Accept (StructuralVisitor visitor)
9986 return visitor.Visit (this);
9990 public class ErrorExpression : EmptyExpression
9992 public static readonly ErrorExpression Instance = new ErrorExpression ();
9994 private ErrorExpression ()
9995 : base (InternalType.ErrorType)
9999 public override Expression CreateExpressionTree (ResolveContext ec)
10004 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10009 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
10013 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
10017 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
10021 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
10025 public override object Accept (StructuralVisitor visitor)
10027 return visitor.Visit (this);
10031 public class UserCast : Expression {
10035 public UserCast (MethodSpec method, Expression source, Location l)
10037 if (source == null)
10038 throw new ArgumentNullException ("source");
10040 this.method = method;
10041 this.source = source;
10042 type = method.ReturnType;
10046 public Expression Source {
10052 public override bool ContainsEmitWithAwait ()
10054 return source.ContainsEmitWithAwait ();
10057 public override Expression CreateExpressionTree (ResolveContext ec)
10059 Arguments args = new Arguments (3);
10060 args.Add (new Argument (source.CreateExpressionTree (ec)));
10061 args.Add (new Argument (new TypeOf (type, loc)));
10062 args.Add (new Argument (new TypeOfMethod (method, loc)));
10063 return CreateExpressionFactoryCall (ec, "Convert", args);
10066 protected override Expression DoResolve (ResolveContext ec)
10068 ObsoleteAttribute oa = method.GetAttributeObsolete ();
10070 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
10072 eclass = ExprClass.Value;
10076 public override void Emit (EmitContext ec)
10079 ec.MarkCallEntry (loc);
10080 ec.Emit (OpCodes.Call, method);
10083 public override string GetSignatureForError ()
10085 return TypeManager.CSharpSignature (method);
10088 public override SLE.Expression MakeExpression (BuilderContext ctx)
10091 return base.MakeExpression (ctx);
10093 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
10099 // Holds additional type specifiers like ?, *, []
10101 public class ComposedTypeSpecifier
10103 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
10105 public readonly int Dimension;
10106 public readonly Location Location;
10108 public ComposedTypeSpecifier (int specifier, Location loc)
10110 this.Dimension = specifier;
10111 this.Location = loc;
10115 public bool IsNullable {
10117 return Dimension == -1;
10121 public bool IsPointer {
10123 return Dimension == -2;
10127 public ComposedTypeSpecifier Next { get; set; }
10131 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
10133 return new ComposedTypeSpecifier (dimension, loc);
10136 public static ComposedTypeSpecifier CreateNullable (Location loc)
10138 return new ComposedTypeSpecifier (-1, loc);
10141 public static ComposedTypeSpecifier CreatePointer (Location loc)
10143 return new ComposedTypeSpecifier (-2, loc);
10146 public string GetSignatureForError ()
10151 ArrayContainer.GetPostfixSignature (Dimension);
10153 return Next != null ? s + Next.GetSignatureForError () : s;
10158 // This class is used to "construct" the type during a typecast
10159 // operation. Since the Type.GetType class in .NET can parse
10160 // the type specification, we just use this to construct the type
10161 // one bit at a time.
10163 public class ComposedCast : TypeExpr {
10164 FullNamedExpression left;
10165 ComposedTypeSpecifier spec;
10167 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
10170 throw new ArgumentNullException ("spec");
10174 this.loc = left.Location;
10177 public override TypeSpec ResolveAsType (IMemberContext ec)
10179 type = left.ResolveAsType (ec);
10183 eclass = ExprClass.Type;
10185 var single_spec = spec;
10187 if (single_spec.IsNullable) {
10188 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
10192 single_spec = single_spec.Next;
10193 } else if (single_spec.IsPointer) {
10194 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
10197 if (!ec.IsUnsafe) {
10198 UnsafeError (ec.Module.Compiler.Report, loc);
10202 type = PointerContainer.MakeType (ec.Module, type);
10203 single_spec = single_spec.Next;
10204 } while (single_spec != null && single_spec.IsPointer);
10207 if (single_spec != null && single_spec.Dimension > 0) {
10208 if (type.IsSpecialRuntimeType) {
10209 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
10210 } else if (type.IsStatic) {
10211 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
10212 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
10213 type.GetSignatureForError ());
10215 MakeArray (ec.Module, single_spec);
10222 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
10224 if (spec.Next != null)
10225 MakeArray (module, spec.Next);
10227 type = ArrayContainer.MakeType (module, type, spec.Dimension);
10230 public override string GetSignatureForError ()
10232 return left.GetSignatureForError () + spec.GetSignatureForError ();
10235 public override object Accept (StructuralVisitor visitor)
10237 return visitor.Visit (this);
10241 class FixedBufferPtr : Expression
10243 readonly Expression array;
10245 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
10247 this.type = array_type;
10248 this.array = array;
10252 public override bool ContainsEmitWithAwait ()
10254 throw new NotImplementedException ();
10257 public override Expression CreateExpressionTree (ResolveContext ec)
10259 Error_PointerInsideExpressionTree (ec);
10263 public override void Emit(EmitContext ec)
10268 protected override Expression DoResolve (ResolveContext ec)
10270 type = PointerContainer.MakeType (ec.Module, type);
10271 eclass = ExprClass.Value;
10278 // This class is used to represent the address of an array, used
10279 // only by the Fixed statement, this generates "&a [0]" construct
10280 // for fixed (char *pa = a)
10282 class ArrayPtr : FixedBufferPtr
10284 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
10285 base (array, array_type, l)
10289 public override void Emit (EmitContext ec)
10294 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
10299 // Encapsulates a conversion rules required for array indexes
10301 public class ArrayIndexCast : TypeCast
10303 public ArrayIndexCast (Expression expr, TypeSpec returnType)
10304 : base (expr, returnType)
10306 if (expr.Type == returnType) // int -> int
10307 throw new ArgumentException ("unnecessary array index conversion");
10310 public override Expression CreateExpressionTree (ResolveContext ec)
10312 using (ec.Set (ResolveContext.Options.CheckedScope)) {
10313 return base.CreateExpressionTree (ec);
10317 public override void Emit (EmitContext ec)
10321 switch (child.Type.BuiltinType) {
10322 case BuiltinTypeSpec.Type.UInt:
10323 ec.Emit (OpCodes.Conv_U);
10325 case BuiltinTypeSpec.Type.Long:
10326 ec.Emit (OpCodes.Conv_Ovf_I);
10328 case BuiltinTypeSpec.Type.ULong:
10329 ec.Emit (OpCodes.Conv_Ovf_I_Un);
10332 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
10338 // Implements the `stackalloc' keyword
10340 public class StackAlloc : Expression {
10345 public StackAlloc (Expression type, Expression count, Location l)
10348 this.count = count;
10352 public Expression TypeExpression {
10358 public Expression CountExpression {
10364 public override bool ContainsEmitWithAwait ()
10369 public override Expression CreateExpressionTree (ResolveContext ec)
10371 throw new NotSupportedException ("ET");
10374 protected override Expression DoResolve (ResolveContext ec)
10376 count = count.Resolve (ec);
10380 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
10381 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
10386 Constant c = count as Constant;
10387 if (c != null && c.IsNegative) {
10388 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
10391 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
10392 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
10395 otype = t.ResolveAsType (ec);
10399 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
10402 type = PointerContainer.MakeType (ec.Module, otype);
10403 eclass = ExprClass.Value;
10408 public override void Emit (EmitContext ec)
10410 int size = BuiltinTypeSpec.GetSize (otype);
10415 ec.Emit (OpCodes.Sizeof, otype);
10419 ec.Emit (OpCodes.Mul_Ovf_Un);
10420 ec.Emit (OpCodes.Localloc);
10423 protected override void CloneTo (CloneContext clonectx, Expression t)
10425 StackAlloc target = (StackAlloc) t;
10426 target.count = count.Clone (clonectx);
10427 target.t = t.Clone (clonectx);
10430 public override object Accept (StructuralVisitor visitor)
10432 return visitor.Visit (this);
10437 // An object initializer expression
10439 public class ElementInitializer : Assign
10441 public readonly string Name;
10443 public ElementInitializer (string name, Expression initializer, Location loc)
10444 : base (null, initializer, loc)
10449 protected override void CloneTo (CloneContext clonectx, Expression t)
10451 ElementInitializer target = (ElementInitializer) t;
10452 target.source = source.Clone (clonectx);
10455 public override Expression CreateExpressionTree (ResolveContext ec)
10457 Arguments args = new Arguments (2);
10458 FieldExpr fe = target as FieldExpr;
10460 args.Add (new Argument (fe.CreateTypeOfExpression ()));
10462 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
10465 Expression arg_expr;
10466 var cinit = source as CollectionOrObjectInitializers;
10467 if (cinit == null) {
10469 arg_expr = source.CreateExpressionTree (ec);
10471 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
10472 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
10475 args.Add (new Argument (arg_expr));
10476 return CreateExpressionFactoryCall (ec, mname, args);
10479 protected override Expression DoResolve (ResolveContext ec)
10481 if (source == null)
10482 return EmptyExpressionStatement.Instance;
10484 var t = ec.CurrentInitializerVariable.Type;
10485 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10486 Arguments args = new Arguments (1);
10487 args.Add (new Argument (ec.CurrentInitializerVariable));
10488 target = new DynamicMemberBinder (Name, args, loc);
10491 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10492 if (member == null) {
10493 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10495 if (member != null) {
10496 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
10497 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
10502 if (member == null) {
10503 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
10507 if (!(member is PropertyExpr || member is FieldExpr)) {
10508 ec.Report.Error (1913, loc,
10509 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
10510 member.GetSignatureForError ());
10515 var me = member as MemberExpr;
10517 ec.Report.Error (1914, loc,
10518 "Static field or property `{0}' cannot be assigned in an object initializer",
10519 me.GetSignatureForError ());
10523 me.InstanceExpression = ec.CurrentInitializerVariable;
10526 if (source is CollectionOrObjectInitializers) {
10527 Expression previous = ec.CurrentInitializerVariable;
10528 ec.CurrentInitializerVariable = target;
10529 source = source.Resolve (ec);
10530 ec.CurrentInitializerVariable = previous;
10531 if (source == null)
10534 eclass = source.eclass;
10535 type = source.Type;
10539 return base.DoResolve (ec);
10542 public override void EmitStatement (EmitContext ec)
10544 if (source is CollectionOrObjectInitializers)
10547 base.EmitStatement (ec);
10552 // A collection initializer expression
10554 class CollectionElementInitializer : Invocation
10556 public class ElementInitializerArgument : Argument
10558 public ElementInitializerArgument (Expression e)
10564 sealed class AddMemberAccess : MemberAccess
10566 public AddMemberAccess (Expression expr, Location loc)
10567 : base (expr, "Add", loc)
10571 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10573 if (TypeManager.HasElementType (type))
10576 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10580 public CollectionElementInitializer (Expression argument)
10581 : base (null, new Arguments (1))
10583 base.arguments.Add (new ElementInitializerArgument (argument));
10584 this.loc = argument.Location;
10587 public CollectionElementInitializer (List<Expression> arguments, Location loc)
10588 : base (null, new Arguments (arguments.Count))
10590 foreach (Expression e in arguments)
10591 base.arguments.Add (new ElementInitializerArgument (e));
10596 public CollectionElementInitializer (Location loc)
10597 : base (null, null)
10602 public override Expression CreateExpressionTree (ResolveContext ec)
10604 Arguments args = new Arguments (2);
10605 args.Add (new Argument (mg.CreateExpressionTree (ec)));
10607 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
10608 foreach (Argument a in arguments)
10609 expr_initializers.Add (a.CreateExpressionTree (ec));
10611 args.Add (new Argument (new ArrayCreation (
10612 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
10613 return CreateExpressionFactoryCall (ec, "ElementInit", args);
10616 protected override void CloneTo (CloneContext clonectx, Expression t)
10618 CollectionElementInitializer target = (CollectionElementInitializer) t;
10619 if (arguments != null)
10620 target.arguments = arguments.Clone (clonectx);
10623 protected override Expression DoResolve (ResolveContext ec)
10625 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
10627 return base.DoResolve (ec);
10632 // A block of object or collection initializers
10634 public class CollectionOrObjectInitializers : ExpressionStatement
10636 IList<Expression> initializers;
10637 bool is_collection_initialization;
10639 public CollectionOrObjectInitializers (Location loc)
10640 : this (new Expression[0], loc)
10644 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10646 this.initializers = initializers;
10650 public IList<Expression> Initializers {
10652 return initializers;
10656 public bool IsEmpty {
10658 return initializers.Count == 0;
10662 public bool IsCollectionInitializer {
10664 return is_collection_initialization;
10668 protected override void CloneTo (CloneContext clonectx, Expression target)
10670 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10672 t.initializers = new List<Expression> (initializers.Count);
10673 foreach (var e in initializers)
10674 t.initializers.Add (e.Clone (clonectx));
10677 public override bool ContainsEmitWithAwait ()
10679 foreach (var e in initializers) {
10680 if (e.ContainsEmitWithAwait ())
10687 public override Expression CreateExpressionTree (ResolveContext ec)
10689 return CreateExpressionTree (ec, false);
10692 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10694 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10695 foreach (Expression e in initializers) {
10696 Expression expr = e.CreateExpressionTree (ec);
10698 expr_initializers.Add (expr);
10702 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10704 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10707 protected override Expression DoResolve (ResolveContext ec)
10709 List<string> element_names = null;
10710 for (int i = 0; i < initializers.Count; ++i) {
10711 Expression initializer = initializers [i];
10712 ElementInitializer element_initializer = initializer as ElementInitializer;
10715 if (element_initializer != null) {
10716 element_names = new List<string> (initializers.Count);
10717 element_names.Add (element_initializer.Name);
10718 } else if (initializer is CompletingExpression){
10719 initializer.Resolve (ec);
10720 throw new InternalErrorException ("This line should never be reached");
10722 var t = ec.CurrentInitializerVariable.Type;
10723 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10724 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10725 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10726 "object initializer because type `{1}' does not implement `{2}' interface",
10727 ec.CurrentInitializerVariable.GetSignatureForError (),
10728 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10729 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10732 is_collection_initialization = true;
10735 if (is_collection_initialization != (element_initializer == null)) {
10736 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10737 is_collection_initialization ? "collection initializer" : "object initializer");
10741 if (!is_collection_initialization) {
10742 if (element_names.Contains (element_initializer.Name)) {
10743 ec.Report.Error (1912, element_initializer.Location,
10744 "An object initializer includes more than one member `{0}' initialization",
10745 element_initializer.Name);
10747 element_names.Add (element_initializer.Name);
10752 Expression e = initializer.Resolve (ec);
10753 if (e == EmptyExpressionStatement.Instance)
10754 initializers.RemoveAt (i--);
10756 initializers [i] = e;
10759 type = ec.CurrentInitializerVariable.Type;
10760 if (is_collection_initialization) {
10761 if (TypeManager.HasElementType (type)) {
10762 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10763 type.GetSignatureForError ());
10767 eclass = ExprClass.Variable;
10771 public override void Emit (EmitContext ec)
10773 EmitStatement (ec);
10776 public override void EmitStatement (EmitContext ec)
10778 foreach (ExpressionStatement e in initializers) {
10779 // TODO: need location region
10780 ec.Mark (e.Location);
10781 e.EmitStatement (ec);
10787 // New expression with element/object initializers
10789 public class NewInitialize : New
10792 // This class serves as a proxy for variable initializer target instances.
10793 // A real variable is assigned later when we resolve left side of an
10796 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10798 NewInitialize new_instance;
10800 public InitializerTargetExpression (NewInitialize newInstance)
10802 this.type = newInstance.type;
10803 this.loc = newInstance.loc;
10804 this.eclass = newInstance.eclass;
10805 this.new_instance = newInstance;
10808 public override bool ContainsEmitWithAwait ()
10813 public override Expression CreateExpressionTree (ResolveContext ec)
10815 // Should not be reached
10816 throw new NotSupportedException ("ET");
10819 protected override Expression DoResolve (ResolveContext ec)
10824 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10829 public override void Emit (EmitContext ec)
10831 Expression e = (Expression) new_instance.instance;
10835 public override Expression EmitToField (EmitContext ec)
10837 return (Expression) new_instance.instance;
10840 #region IMemoryLocation Members
10842 public void AddressOf (EmitContext ec, AddressOp mode)
10844 new_instance.instance.AddressOf (ec, mode);
10850 CollectionOrObjectInitializers initializers;
10851 IMemoryLocation instance;
10852 DynamicExpressionStatement dynamic;
10854 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10855 : base (requested_type, arguments, l)
10857 this.initializers = initializers;
10860 public CollectionOrObjectInitializers Initializers {
10862 return initializers;
10866 protected override void CloneTo (CloneContext clonectx, Expression t)
10868 base.CloneTo (clonectx, t);
10870 NewInitialize target = (NewInitialize) t;
10871 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
10874 public override bool ContainsEmitWithAwait ()
10876 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
10879 public override Expression CreateExpressionTree (ResolveContext ec)
10881 Arguments args = new Arguments (2);
10882 args.Add (new Argument (base.CreateExpressionTree (ec)));
10883 if (!initializers.IsEmpty)
10884 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
10886 return CreateExpressionFactoryCall (ec,
10887 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
10891 protected override Expression DoResolve (ResolveContext ec)
10893 Expression e = base.DoResolve (ec);
10897 if (type.IsDelegate) {
10898 ec.Report.Error (1958, Initializers.Location,
10899 "Object and collection initializers cannot be used to instantiate a delegate");
10902 Expression previous = ec.CurrentInitializerVariable;
10903 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
10904 initializers.Resolve (ec);
10905 ec.CurrentInitializerVariable = previous;
10907 dynamic = e as DynamicExpressionStatement;
10908 if (dynamic != null)
10914 public override bool Emit (EmitContext ec, IMemoryLocation target)
10916 bool left_on_stack;
10917 if (dynamic != null) {
10919 left_on_stack = true;
10921 left_on_stack = base.Emit (ec, target);
10924 if (initializers.IsEmpty)
10925 return left_on_stack;
10927 LocalTemporary temp = null;
10929 instance = target as LocalTemporary;
10931 if (instance == null) {
10932 if (!left_on_stack) {
10933 VariableReference vr = target as VariableReference;
10935 // FIXME: This still does not work correctly for pre-set variables
10936 if (vr != null && vr.IsRef)
10937 target.AddressOf (ec, AddressOp.Load);
10939 ((Expression) target).Emit (ec);
10940 left_on_stack = true;
10943 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
10944 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
10946 temp = new LocalTemporary (type);
10951 if (left_on_stack && temp != null)
10954 initializers.Emit (ec);
10956 if (left_on_stack) {
10957 if (temp != null) {
10961 ((Expression) instance).Emit (ec);
10965 return left_on_stack;
10968 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
10970 instance = base.EmitAddressOf (ec, Mode);
10972 if (!initializers.IsEmpty)
10973 initializers.Emit (ec);
10978 public override object Accept (StructuralVisitor visitor)
10980 return visitor.Visit (this);
10984 public class NewAnonymousType : New
10986 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
10988 List<AnonymousTypeParameter> parameters;
10989 readonly TypeContainer parent;
10990 AnonymousTypeClass anonymous_type;
10992 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
10993 : base (null, null, loc)
10995 this.parameters = parameters;
10996 this.parent = parent;
10999 public List<AnonymousTypeParameter> Parameters {
11001 return this.parameters;
11005 protected override void CloneTo (CloneContext clonectx, Expression target)
11007 if (parameters == null)
11010 NewAnonymousType t = (NewAnonymousType) target;
11011 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
11012 foreach (AnonymousTypeParameter atp in parameters)
11013 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
11016 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
11018 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
11022 type = AnonymousTypeClass.Create (parent, parameters, loc);
11026 int errors = ec.Report.Errors;
11027 type.CreateContainer ();
11028 type.DefineContainer ();
11030 if ((ec.Report.Errors - errors) == 0) {
11031 parent.Module.AddAnonymousType (type);
11037 public override Expression CreateExpressionTree (ResolveContext ec)
11039 if (parameters == null)
11040 return base.CreateExpressionTree (ec);
11042 var init = new ArrayInitializer (parameters.Count, loc);
11043 foreach (var m in anonymous_type.Members) {
11044 var p = m as Property;
11046 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
11049 var ctor_args = new ArrayInitializer (arguments.Count, loc);
11050 foreach (Argument a in arguments)
11051 ctor_args.Add (a.CreateExpressionTree (ec));
11053 Arguments args = new Arguments (3);
11054 args.Add (new Argument (new TypeOfMethod (method, loc)));
11055 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
11056 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
11058 return CreateExpressionFactoryCall (ec, "New", args);
11061 protected override Expression DoResolve (ResolveContext ec)
11063 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
11064 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
11068 if (parameters == null) {
11069 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
11070 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
11071 return base.DoResolve (ec);
11074 bool error = false;
11075 arguments = new Arguments (parameters.Count);
11076 var t_args = new TypeSpec [parameters.Count];
11077 for (int i = 0; i < parameters.Count; ++i) {
11078 Expression e = parameters [i].Resolve (ec);
11084 arguments.Add (new Argument (e));
11085 t_args [i] = e.Type;
11091 anonymous_type = CreateAnonymousType (ec, parameters);
11092 if (anonymous_type == null)
11095 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
11096 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
11097 eclass = ExprClass.Value;
11101 public override object Accept (StructuralVisitor visitor)
11103 return visitor.Visit (this);
11107 public class AnonymousTypeParameter : ShimExpression
11109 public readonly string Name;
11111 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
11112 : base (initializer)
11118 public AnonymousTypeParameter (Parameter parameter)
11119 : base (new SimpleName (parameter.Name, parameter.Location))
11121 this.Name = parameter.Name;
11122 this.loc = parameter.Location;
11125 public override bool Equals (object o)
11127 AnonymousTypeParameter other = o as AnonymousTypeParameter;
11128 return other != null && Name == other.Name;
11131 public override int GetHashCode ()
11133 return Name.GetHashCode ();
11136 protected override Expression DoResolve (ResolveContext ec)
11138 Expression e = expr.Resolve (ec);
11142 if (e.eclass == ExprClass.MethodGroup) {
11143 Error_InvalidInitializer (ec, e.ExprClassName);
11148 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
11149 Error_InvalidInitializer (ec, type.GetSignatureForError ());
11156 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
11158 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
11159 Name, initializer);