2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
19 using MetaType = IKVM.Reflection.Type;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
23 using MetaType = System.Type;
24 using System.Reflection;
25 using System.Reflection.Emit;
31 // This is an user operator expression, automatically created during
34 public class UserOperatorCall : Expression {
35 protected readonly Arguments arguments;
36 protected readonly MethodSpec oper;
37 readonly Func<ResolveContext, Expression, Expression> expr_tree;
39 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
42 this.arguments = args;
43 this.expr_tree = expr_tree;
45 type = oper.ReturnType;
46 eclass = ExprClass.Value;
50 public override bool ContainsEmitWithAwait ()
52 return arguments.ContainsEmitWithAwait ();
55 public override Expression CreateExpressionTree (ResolveContext ec)
57 if (expr_tree != null)
58 return expr_tree (ec, new TypeOfMethod (oper, loc));
60 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
61 new NullLiteral (loc),
62 new TypeOfMethod (oper, loc));
64 return CreateExpressionFactoryCall (ec, "Call", args);
67 protected override void CloneTo (CloneContext context, Expression target)
72 protected override Expression DoResolve (ResolveContext ec)
75 // We are born fully resolved
80 public override void Emit (EmitContext ec)
82 var call = new CallEmitter ();
83 call.EmitPredefined (ec, oper, arguments);
86 public override SLE.Expression MakeExpression (BuilderContext ctx)
89 return base.MakeExpression (ctx);
91 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
96 public class ParenthesizedExpression : ShimExpression
98 public ParenthesizedExpression (Expression expr)
104 protected override Expression DoResolve (ResolveContext ec)
106 return expr.Resolve (ec);
109 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
111 return expr.DoResolveLValue (ec, right_side);
116 // Unary implements unary expressions.
118 public class Unary : Expression
120 public enum Operator : byte {
121 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
125 public readonly Operator Oper;
126 public Expression Expr;
127 Expression enum_conversion;
129 public Unary (Operator op, Expression expr, Location loc)
137 // This routine will attempt to simplify the unary expression when the
138 // argument is a constant.
140 Constant TryReduceConstant (ResolveContext ec, Constant e)
142 if (e is EmptyConstantCast)
143 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
145 if (e is SideEffectConstant) {
146 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
147 return r == null ? null : new SideEffectConstant (r, e, r.Location);
150 TypeSpec expr_type = e.Type;
153 case Operator.UnaryPlus:
154 // Unary numeric promotions
155 switch (expr_type.BuiltinType) {
156 case BuiltinTypeSpec.Type.Byte:
157 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
158 case BuiltinTypeSpec.Type.SByte:
159 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
160 case BuiltinTypeSpec.Type.Short:
161 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
162 case BuiltinTypeSpec.Type.UShort:
163 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
164 case BuiltinTypeSpec.Type.Char:
165 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
167 // Predefined operators
168 case BuiltinTypeSpec.Type.Int:
169 case BuiltinTypeSpec.Type.UInt:
170 case BuiltinTypeSpec.Type.Long:
171 case BuiltinTypeSpec.Type.ULong:
172 case BuiltinTypeSpec.Type.Float:
173 case BuiltinTypeSpec.Type.Double:
174 case BuiltinTypeSpec.Type.Decimal:
180 case Operator.UnaryNegation:
181 // Unary numeric promotions
182 switch (expr_type.BuiltinType) {
183 case BuiltinTypeSpec.Type.Byte:
184 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
185 case BuiltinTypeSpec.Type.SByte:
186 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
187 case BuiltinTypeSpec.Type.Short:
188 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
189 case BuiltinTypeSpec.Type.UShort:
190 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
191 case BuiltinTypeSpec.Type.Char:
192 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
194 // Predefined operators
195 case BuiltinTypeSpec.Type.Int:
196 int ivalue = ((IntConstant) e).Value;
197 if (ivalue == int.MinValue) {
198 if (ec.ConstantCheckState) {
199 ConstantFold.Error_CompileTimeOverflow (ec, loc);
204 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
206 case BuiltinTypeSpec.Type.Long:
207 long lvalue = ((LongConstant) e).Value;
208 if (lvalue == long.MinValue) {
209 if (ec.ConstantCheckState) {
210 ConstantFold.Error_CompileTimeOverflow (ec, loc);
215 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
217 case BuiltinTypeSpec.Type.UInt:
218 UIntLiteral uil = e as UIntLiteral;
220 if (uil.Value == int.MaxValue + (uint) 1)
221 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
222 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
224 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
227 case BuiltinTypeSpec.Type.ULong:
228 ULongLiteral ull = e as ULongLiteral;
229 if (ull != null && ull.Value == 9223372036854775808)
230 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
233 case BuiltinTypeSpec.Type.Float:
234 FloatLiteral fl = e as FloatLiteral;
235 // For better error reporting
237 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
239 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
241 case BuiltinTypeSpec.Type.Double:
242 DoubleLiteral dl = e as DoubleLiteral;
243 // For better error reporting
245 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
247 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
249 case BuiltinTypeSpec.Type.Decimal:
250 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
255 case Operator.LogicalNot:
256 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
259 bool b = (bool)e.GetValue ();
260 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
262 case Operator.OnesComplement:
263 // Unary numeric promotions
264 switch (expr_type.BuiltinType) {
265 case BuiltinTypeSpec.Type.Byte:
266 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
267 case BuiltinTypeSpec.Type.SByte:
268 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
269 case BuiltinTypeSpec.Type.Short:
270 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
271 case BuiltinTypeSpec.Type.UShort:
272 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
273 case BuiltinTypeSpec.Type.Char:
274 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
276 // Predefined operators
277 case BuiltinTypeSpec.Type.Int:
278 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
279 case BuiltinTypeSpec.Type.UInt:
280 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
281 case BuiltinTypeSpec.Type.Long:
282 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
283 case BuiltinTypeSpec.Type.ULong:
284 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
286 if (e is EnumConstant) {
287 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
289 e = new EnumConstant (e, expr_type);
294 throw new Exception ("Can not constant fold: " + Oper.ToString());
297 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
299 eclass = ExprClass.Value;
301 TypeSpec expr_type = expr.Type;
302 Expression best_expr;
304 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
307 // Primitive types first
309 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
310 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
311 if (best_expr == null)
314 type = best_expr.Type;
320 // E operator ~(E x);
322 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
323 return ResolveEnumOperator (ec, expr, predefined);
325 return ResolveUserType (ec, expr, predefined);
328 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
330 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
331 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
332 if (best_expr == null)
336 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (best_expr.Type), underlying_type);
338 return EmptyCast.Create (this, type);
341 public override bool ContainsEmitWithAwait ()
343 return Expr.ContainsEmitWithAwait ();
346 public override Expression CreateExpressionTree (ResolveContext ec)
348 return CreateExpressionTree (ec, null);
351 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
355 case Operator.AddressOf:
356 Error_PointerInsideExpressionTree (ec);
358 case Operator.UnaryNegation:
359 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
360 method_name = "NegateChecked";
362 method_name = "Negate";
364 case Operator.OnesComplement:
365 case Operator.LogicalNot:
368 case Operator.UnaryPlus:
369 method_name = "UnaryPlus";
372 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
375 Arguments args = new Arguments (2);
376 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
378 args.Add (new Argument (user_op));
380 return CreateExpressionFactoryCall (ec, method_name, args);
383 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
385 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
388 // 7.6.1 Unary plus operator
390 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
391 types.Int, types.UInt,
392 types.Long, types.ULong,
393 types.Float, types.Double,
398 // 7.6.2 Unary minus operator
400 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
401 types.Int, types.Long,
402 types.Float, types.Double,
407 // 7.6.3 Logical negation operator
409 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
414 // 7.6.4 Bitwise complement operator
416 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
417 types.Int, types.UInt,
418 types.Long, types.ULong
421 return predefined_operators;
425 // Unary numeric promotions
427 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
429 TypeSpec expr_type = expr.Type;
430 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
431 switch (expr_type.BuiltinType) {
432 case BuiltinTypeSpec.Type.Byte:
433 case BuiltinTypeSpec.Type.SByte:
434 case BuiltinTypeSpec.Type.Short:
435 case BuiltinTypeSpec.Type.UShort:
436 case BuiltinTypeSpec.Type.Char:
437 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
441 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
442 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
447 protected override Expression DoResolve (ResolveContext ec)
449 if (Oper == Operator.AddressOf) {
450 return ResolveAddressOf (ec);
453 Expr = Expr.Resolve (ec);
457 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
458 Arguments args = new Arguments (1);
459 args.Add (new Argument (Expr));
460 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
463 if (Expr.Type.IsNullableType)
464 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
467 // Attempt to use a constant folding operation.
469 Constant cexpr = Expr as Constant;
471 cexpr = TryReduceConstant (ec, cexpr);
476 Expression expr = ResolveOperator (ec, Expr);
478 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
481 // Reduce unary operator on predefined types
483 if (expr == this && Oper == Operator.UnaryPlus)
489 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
494 public override void Emit (EmitContext ec)
496 EmitOperator (ec, type);
499 protected void EmitOperator (EmitContext ec, TypeSpec type)
502 case Operator.UnaryPlus:
506 case Operator.UnaryNegation:
507 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
508 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
509 Expr = Expr.EmitToField (ec);
512 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
513 ec.Emit (OpCodes.Conv_U8);
515 ec.Emit (OpCodes.Sub_Ovf);
518 ec.Emit (OpCodes.Neg);
523 case Operator.LogicalNot:
526 ec.Emit (OpCodes.Ceq);
529 case Operator.OnesComplement:
531 ec.Emit (OpCodes.Not);
534 case Operator.AddressOf:
535 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
539 throw new Exception ("This should not happen: Operator = "
544 // Same trick as in Binary expression
546 if (enum_conversion != null)
547 enum_conversion.Emit (ec);
550 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
552 if (Oper == Operator.LogicalNot)
553 Expr.EmitBranchable (ec, target, !on_true);
555 base.EmitBranchable (ec, target, on_true);
558 public override void EmitSideEffect (EmitContext ec)
560 Expr.EmitSideEffect (ec);
563 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Location loc, string oper, TypeSpec t)
565 ec.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
566 oper, TypeManager.CSharpName (t));
570 // Converts operator to System.Linq.Expressions.ExpressionType enum name
572 string GetOperatorExpressionTypeName ()
575 case Operator.OnesComplement:
576 return "OnesComplement";
577 case Operator.LogicalNot:
579 case Operator.UnaryNegation:
581 case Operator.UnaryPlus:
584 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
588 static bool IsFloat (TypeSpec t)
590 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
594 // Returns a stringified representation of the Operator
596 public static string OperName (Operator oper)
599 case Operator.UnaryPlus:
601 case Operator.UnaryNegation:
603 case Operator.LogicalNot:
605 case Operator.OnesComplement:
607 case Operator.AddressOf:
611 throw new NotImplementedException (oper.ToString ());
614 public override SLE.Expression MakeExpression (BuilderContext ctx)
616 var expr = Expr.MakeExpression (ctx);
617 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
620 case Operator.UnaryNegation:
621 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
622 case Operator.LogicalNot:
623 return SLE.Expression.Not (expr);
625 case Operator.OnesComplement:
626 return SLE.Expression.OnesComplement (expr);
629 throw new NotImplementedException (Oper.ToString ());
633 Expression ResolveAddressOf (ResolveContext ec)
636 UnsafeError (ec, loc);
638 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
639 if (Expr == null || Expr.eclass != ExprClass.Variable) {
640 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
644 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
648 IVariableReference vr = Expr as IVariableReference;
651 VariableInfo vi = vr.VariableInfo;
653 if (vi.LocalInfo != null)
654 vi.LocalInfo.SetIsUsed ();
657 // A variable is considered definitely assigned if you take its address.
662 is_fixed = vr.IsFixed;
663 vr.SetHasAddressTaken ();
666 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
669 IFixedExpression fe = Expr as IFixedExpression;
670 is_fixed = fe != null && fe.IsFixed;
673 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
674 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
677 type = PointerContainer.MakeType (ec.Module, Expr.Type);
678 eclass = ExprClass.Value;
682 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
684 expr = DoNumericPromotion (rc, Oper, expr);
685 TypeSpec expr_type = expr.Type;
686 foreach (TypeSpec t in predefined) {
694 // Perform user-operator overload resolution
696 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
698 CSharp.Operator.OpType op_type;
700 case Operator.LogicalNot:
701 op_type = CSharp.Operator.OpType.LogicalNot; break;
702 case Operator.OnesComplement:
703 op_type = CSharp.Operator.OpType.OnesComplement; break;
704 case Operator.UnaryNegation:
705 op_type = CSharp.Operator.OpType.UnaryNegation; break;
706 case Operator.UnaryPlus:
707 op_type = CSharp.Operator.OpType.UnaryPlus; break;
709 throw new InternalErrorException (Oper.ToString ());
712 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
716 Arguments args = new Arguments (1);
717 args.Add (new Argument (expr));
719 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
720 var oper = res.ResolveOperator (ec, ref args);
725 Expr = args [0].Expr;
726 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
730 // Unary user type overload resolution
732 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
734 Expression best_expr = ResolveUserOperator (ec, expr);
735 if (best_expr != null)
738 foreach (TypeSpec t in predefined) {
739 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
740 if (oper_expr == null)
743 if (oper_expr == ErrorExpression.Instance)
747 // decimal type is predefined but has user-operators
749 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
750 oper_expr = ResolveUserType (ec, oper_expr, predefined);
752 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
754 if (oper_expr == null)
757 if (best_expr == null) {
758 best_expr = oper_expr;
762 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
764 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
765 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
766 OperName (Oper), expr.Type.GetSignatureForError ());
768 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
775 best_expr = oper_expr;
778 if (best_expr == null)
782 // HACK: Decimal user-operator is included in standard operators
784 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
788 type = best_expr.Type;
792 protected override void CloneTo (CloneContext clonectx, Expression t)
794 Unary target = (Unary) t;
796 target.Expr = Expr.Clone (clonectx);
801 // Unary operators are turned into Indirection expressions
802 // after semantic analysis (this is so we can take the address
803 // of an indirection).
805 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
807 LocalTemporary temporary;
810 public Indirection (Expression expr, Location l)
816 public bool IsFixed {
820 protected override void CloneTo (CloneContext clonectx, Expression t)
822 Indirection target = (Indirection) t;
823 target.expr = expr.Clone (clonectx);
826 public override bool ContainsEmitWithAwait ()
828 throw new NotImplementedException ();
831 public override Expression CreateExpressionTree (ResolveContext ec)
833 Error_PointerInsideExpressionTree (ec);
837 public override void Emit (EmitContext ec)
842 ec.EmitLoadFromPtr (Type);
845 public void Emit (EmitContext ec, bool leave_copy)
849 ec.Emit (OpCodes.Dup);
850 temporary = new LocalTemporary (expr.Type);
851 temporary.Store (ec);
855 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
857 prepared = isCompound;
862 ec.Emit (OpCodes.Dup);
866 ec.Emit (OpCodes.Dup);
867 temporary = new LocalTemporary (source.Type);
868 temporary.Store (ec);
871 ec.EmitStoreFromPtr (type);
873 if (temporary != null) {
875 temporary.Release (ec);
879 public void AddressOf (EmitContext ec, AddressOp Mode)
884 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
886 return DoResolve (ec);
889 protected override Expression DoResolve (ResolveContext ec)
891 expr = expr.Resolve (ec);
896 UnsafeError (ec, loc);
898 var pc = expr.Type as PointerContainer;
901 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
907 if (type.Kind == MemberKind.Void) {
908 Error_VoidPointerOperation (ec);
912 eclass = ExprClass.Variable;
918 /// Unary Mutator expressions (pre and post ++ and --)
922 /// UnaryMutator implements ++ and -- expressions. It derives from
923 /// ExpressionStatement becuase the pre/post increment/decrement
924 /// operators can be used in a statement context.
926 /// FIXME: Idea, we could split this up in two classes, one simpler
927 /// for the common case, and one with the extra fields for more complex
928 /// classes (indexers require temporary access; overloaded require method)
931 public class UnaryMutator : ExpressionStatement
933 class DynamicPostMutator : Expression, IAssignMethod
938 public DynamicPostMutator (Expression expr)
941 this.type = expr.Type;
942 this.loc = expr.Location;
945 public override Expression CreateExpressionTree (ResolveContext ec)
947 throw new NotImplementedException ("ET");
950 protected override Expression DoResolve (ResolveContext rc)
952 eclass = expr.eclass;
956 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
958 expr.DoResolveLValue (ec, right_side);
959 return DoResolve (ec);
962 public override void Emit (EmitContext ec)
967 public void Emit (EmitContext ec, bool leave_copy)
969 throw new NotImplementedException ();
973 // Emits target assignment using unmodified source value
975 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
978 // Allocate temporary variable to keep original value before it's modified
980 temp = new LocalTemporary (type);
984 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
995 public enum Mode : byte {
1002 PreDecrement = IsDecrement,
1003 PostIncrement = IsPost,
1004 PostDecrement = IsPost | IsDecrement
1008 bool is_expr, recurse;
1010 protected Expression expr;
1012 // Holds the real operation
1013 Expression operation;
1015 public UnaryMutator (Mode m, Expression e, Location loc)
1022 public override bool ContainsEmitWithAwait ()
1024 return expr.ContainsEmitWithAwait ();
1027 public override Expression CreateExpressionTree (ResolveContext ec)
1029 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1032 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1035 // Predefined ++ and -- operators exist for the following types:
1036 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1038 return new TypeSpec[] {
1054 protected override Expression DoResolve (ResolveContext ec)
1056 expr = expr.Resolve (ec);
1061 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1063 // Handle postfix unary operators using local
1064 // temporary variable
1066 if ((mode & Mode.IsPost) != 0)
1067 expr = new DynamicPostMutator (expr);
1069 Arguments args = new Arguments (1);
1070 args.Add (new Argument (expr));
1071 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1074 if (expr.Type.IsNullableType)
1075 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1077 return DoResolveOperation (ec);
1080 protected Expression DoResolveOperation (ResolveContext ec)
1082 eclass = ExprClass.Value;
1085 if (expr is RuntimeValueExpression) {
1088 // Use itself at the top of the stack
1089 operation = new EmptyExpression (type);
1093 // The operand of the prefix/postfix increment decrement operators
1094 // should be an expression that is classified as a variable,
1095 // a property access or an indexer access
1097 // TODO: Move to parser, expr is ATypeNameExpression
1098 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1099 expr = expr.ResolveLValue (ec, expr);
1101 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1105 // Step 1: Try to find a user operator, it has priority over predefined ones
1107 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1108 var methods = MemberCache.GetUserOperator (type, user_op, false);
1110 if (methods != null) {
1111 Arguments args = new Arguments (1);
1112 args.Add (new Argument (expr));
1114 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1115 var method = res.ResolveOperator (ec, ref args);
1119 args[0].Expr = operation;
1120 operation = new UserOperatorCall (method, args, null, loc);
1121 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1126 // Step 2: Try predefined types
1129 Expression source = null;
1130 bool primitive_type;
1133 // Predefined without user conversion first for speed-up
1135 // Predefined ++ and -- operators exist for the following types:
1136 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1138 switch (type.BuiltinType) {
1139 case BuiltinTypeSpec.Type.Byte:
1140 case BuiltinTypeSpec.Type.SByte:
1141 case BuiltinTypeSpec.Type.Short:
1142 case BuiltinTypeSpec.Type.UShort:
1143 case BuiltinTypeSpec.Type.Int:
1144 case BuiltinTypeSpec.Type.UInt:
1145 case BuiltinTypeSpec.Type.Long:
1146 case BuiltinTypeSpec.Type.ULong:
1147 case BuiltinTypeSpec.Type.Char:
1148 case BuiltinTypeSpec.Type.Float:
1149 case BuiltinTypeSpec.Type.Double:
1150 case BuiltinTypeSpec.Type.Decimal:
1152 primitive_type = true;
1155 primitive_type = false;
1157 // ++/-- on pointer variables of all types except void*
1158 if (type.IsPointer) {
1159 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1160 Error_VoidPointerOperation (ec);
1166 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1167 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1169 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1170 if (source != null) {
1176 // ++/-- on enum types
1177 if (source == null && type.IsEnum)
1180 if (source == null) {
1181 Unary.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1188 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1189 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1190 operation = new Binary (op, source, one, loc);
1191 operation = operation.Resolve (ec);
1192 if (operation == null)
1193 throw new NotImplementedException ("should not be reached");
1195 if (operation.Type != type) {
1197 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1199 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1205 void EmitCode (EmitContext ec, bool is_expr)
1208 this.is_expr = is_expr;
1209 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1212 public override void Emit (EmitContext ec)
1215 // We use recurse to allow ourselfs to be the source
1216 // of an assignment. This little hack prevents us from
1217 // having to allocate another expression
1220 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1228 EmitCode (ec, true);
1231 protected virtual void EmitOperation (EmitContext ec)
1233 operation.Emit (ec);
1236 public override void EmitStatement (EmitContext ec)
1238 EmitCode (ec, false);
1242 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1244 string GetOperatorExpressionTypeName ()
1246 return IsDecrement ? "Decrement" : "Increment";
1250 get { return (mode & Mode.IsDecrement) != 0; }
1255 public override SLE.Expression MakeExpression (BuilderContext ctx)
1257 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1258 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1259 return SLE.Expression.Assign (target, source);
1263 protected override void CloneTo (CloneContext clonectx, Expression t)
1265 UnaryMutator target = (UnaryMutator) t;
1267 target.expr = expr.Clone (clonectx);
1272 // Base class for the `is' and `as' operators
1274 public abstract class Probe : Expression
1276 public Expression ProbeType;
1277 protected Expression expr;
1278 protected TypeSpec probe_type_expr;
1280 public Probe (Expression expr, Expression probe_type, Location l)
1282 ProbeType = probe_type;
1287 public Expression Expr {
1293 public override bool ContainsEmitWithAwait ()
1295 return expr.ContainsEmitWithAwait ();
1298 protected override Expression DoResolve (ResolveContext ec)
1300 probe_type_expr = ProbeType.ResolveAsType (ec);
1301 if (probe_type_expr == null)
1304 expr = expr.Resolve (ec);
1308 if (probe_type_expr.IsStatic) {
1309 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1313 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1314 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1319 if (expr.Type == InternalType.AnonymousMethod) {
1320 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1328 protected abstract string OperatorName { get; }
1330 protected override void CloneTo (CloneContext clonectx, Expression t)
1332 Probe target = (Probe) t;
1334 target.expr = expr.Clone (clonectx);
1335 target.ProbeType = ProbeType.Clone (clonectx);
1341 /// Implementation of the `is' operator.
1343 public class Is : Probe
1345 Nullable.Unwrap expr_unwrap;
1347 public Is (Expression expr, Expression probe_type, Location l)
1348 : base (expr, probe_type, l)
1352 public override Expression CreateExpressionTree (ResolveContext ec)
1354 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1355 expr.CreateExpressionTree (ec),
1356 new TypeOf (probe_type_expr, loc));
1358 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1361 public override void Emit (EmitContext ec)
1363 if (expr_unwrap != null) {
1364 expr_unwrap.EmitCheck (ec);
1370 // Only to make verifier happy
1371 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1372 ec.Emit (OpCodes.Box, expr.Type);
1374 ec.Emit (OpCodes.Isinst, probe_type_expr);
1376 ec.Emit (OpCodes.Cgt_Un);
1379 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1381 if (expr_unwrap != null) {
1382 expr_unwrap.EmitCheck (ec);
1385 ec.Emit (OpCodes.Isinst, probe_type_expr);
1387 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1390 Expression CreateConstantResult (ResolveContext ec, bool result)
1393 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1394 TypeManager.CSharpName (probe_type_expr));
1396 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1397 TypeManager.CSharpName (probe_type_expr));
1399 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, result, loc), this);
1402 protected override Expression DoResolve (ResolveContext ec)
1404 if (base.DoResolve (ec) == null)
1407 TypeSpec d = expr.Type;
1408 bool d_is_nullable = false;
1411 // If E is a method group or the null literal, or if the type of E is a reference
1412 // type or a nullable type and the value of E is null, the result is false
1414 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1415 return CreateConstantResult (ec, false);
1417 if (d.IsNullableType) {
1418 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1419 if (!ut.IsGenericParameter) {
1421 d_is_nullable = true;
1425 type = ec.BuiltinTypes.Bool;
1426 eclass = ExprClass.Value;
1427 TypeSpec t = probe_type_expr;
1428 bool t_is_nullable = false;
1429 if (t.IsNullableType) {
1430 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1431 if (!ut.IsGenericParameter) {
1433 t_is_nullable = true;
1440 // D and T are the same value types but D can be null
1442 if (d_is_nullable && !t_is_nullable) {
1443 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1448 // The result is true if D and T are the same value types
1450 return CreateConstantResult (ec, true);
1453 var tp = d as TypeParameterSpec;
1455 return ResolveGenericParameter (ec, t, tp);
1458 // An unboxing conversion exists
1460 if (Convert.ExplicitReferenceConversionExists (d, t))
1463 if (TypeManager.IsGenericParameter (t))
1464 return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
1466 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1467 ec.Report.Warning (1981, 3, loc,
1468 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1469 OperatorName, t.GetSignatureForError ());
1472 if (TypeManager.IsGenericParameter (d))
1473 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1475 if (TypeSpec.IsValueType (d)) {
1476 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1477 if (d_is_nullable && !t_is_nullable) {
1478 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1482 return CreateConstantResult (ec, true);
1485 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1487 // Do not optimize for imported type
1489 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None)
1493 // Turn is check into simple null check for implicitly convertible reference types
1495 return ReducedExpression.Create (
1496 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), loc).Resolve (ec),
1500 if (Convert.ExplicitReferenceConversionExists (d, t)) {
1506 return CreateConstantResult (ec, false);
1509 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1511 if (t.IsReferenceType) {
1513 return CreateConstantResult (ec, false);
1516 if (TypeManager.IsGenericParameter (expr.Type)) {
1517 if (expr.Type == d && TypeSpec.IsValueType (t))
1518 return CreateConstantResult (ec, true);
1520 expr = new BoxedCast (expr, d);
1526 protected override string OperatorName {
1527 get { return "is"; }
1532 /// Implementation of the `as' operator.
1534 public class As : Probe {
1535 Expression resolved_type;
1537 public As (Expression expr, Expression probe_type, Location l)
1538 : base (expr, probe_type, l)
1542 public override Expression CreateExpressionTree (ResolveContext ec)
1544 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1545 expr.CreateExpressionTree (ec),
1546 new TypeOf (probe_type_expr, loc));
1548 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1551 public override void Emit (EmitContext ec)
1555 ec.Emit (OpCodes.Isinst, type);
1557 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1558 ec.Emit (OpCodes.Unbox_Any, type);
1561 protected override Expression DoResolve (ResolveContext ec)
1563 if (resolved_type == null) {
1564 resolved_type = base.DoResolve (ec);
1566 if (resolved_type == null)
1570 type = probe_type_expr;
1571 eclass = ExprClass.Value;
1572 TypeSpec etype = expr.Type;
1574 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1575 if (TypeManager.IsGenericParameter (type)) {
1576 ec.Report.Error (413, loc,
1577 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1578 probe_type_expr.GetSignatureForError ());
1580 ec.Report.Error (77, loc,
1581 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1582 TypeManager.CSharpName (type));
1587 if (expr.IsNull && type.IsNullableType) {
1588 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1591 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1592 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1596 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1598 e = EmptyCast.Create (e, type);
1599 return ReducedExpression.Create (e, this).Resolve (ec);
1602 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1603 if (TypeManager.IsGenericParameter (etype))
1604 expr = new BoxedCast (expr, etype);
1609 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1610 expr = new BoxedCast (expr, etype);
1614 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1615 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1620 protected override string OperatorName {
1621 get { return "as"; }
1626 // This represents a typecast in the source language.
1628 public class Cast : ShimExpression {
1629 Expression target_type;
1631 public Cast (Expression cast_type, Expression expr, Location loc)
1634 this.target_type = cast_type;
1638 public Expression TargetType {
1639 get { return target_type; }
1642 protected override Expression DoResolve (ResolveContext ec)
1644 expr = expr.Resolve (ec);
1648 type = target_type.ResolveAsType (ec);
1652 if (type.IsStatic) {
1653 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1657 eclass = ExprClass.Value;
1659 Constant c = expr as Constant;
1661 c = c.TryReduce (ec, type, loc);
1666 if (type.IsPointer && !ec.IsUnsafe) {
1667 UnsafeError (ec, loc);
1670 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1672 return EmptyCast.Create (res, type);
1677 protected override void CloneTo (CloneContext clonectx, Expression t)
1679 Cast target = (Cast) t;
1681 target.target_type = target_type.Clone (clonectx);
1682 target.expr = expr.Clone (clonectx);
1686 public class ImplicitCast : ShimExpression
1690 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1693 this.loc = expr.Location;
1695 this.arrayAccess = arrayAccess;
1698 protected override Expression DoResolve (ResolveContext ec)
1700 expr = expr.Resolve (ec);
1705 expr = ConvertExpressionToArrayIndex (ec, expr);
1707 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1714 // C# 2.0 Default value expression
1716 public class DefaultValueExpression : Expression
1720 public DefaultValueExpression (Expression expr, Location loc)
1726 public override bool IsSideEffectFree {
1732 public override bool ContainsEmitWithAwait ()
1737 public override Expression CreateExpressionTree (ResolveContext ec)
1739 Arguments args = new Arguments (2);
1740 args.Add (new Argument (this));
1741 args.Add (new Argument (new TypeOf (type, loc)));
1742 return CreateExpressionFactoryCall (ec, "Constant", args);
1745 protected override Expression DoResolve (ResolveContext ec)
1747 type = expr.ResolveAsType (ec);
1751 if (type.IsStatic) {
1752 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1756 return new NullLiteral (Location).ConvertImplicitly (type);
1758 if (TypeSpec.IsReferenceType (type))
1759 return new NullConstant (type, loc);
1761 Constant c = New.Constantify (type, expr.Location);
1765 eclass = ExprClass.Variable;
1769 public override void Emit (EmitContext ec)
1771 LocalTemporary temp_storage = new LocalTemporary(type);
1773 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1774 ec.Emit(OpCodes.Initobj, type);
1775 temp_storage.Emit(ec);
1776 temp_storage.Release (ec);
1779 #if NET_4_0 && !STATIC
1780 public override SLE.Expression MakeExpression (BuilderContext ctx)
1782 return SLE.Expression.Default (type.GetMetaInfo ());
1786 protected override void CloneTo (CloneContext clonectx, Expression t)
1788 DefaultValueExpression target = (DefaultValueExpression) t;
1790 target.expr = expr.Clone (clonectx);
1795 /// Binary operators
1797 public class Binary : Expression, IDynamicBinder
1799 public class PredefinedOperator
1801 protected readonly TypeSpec left;
1802 protected readonly TypeSpec right;
1803 public readonly Operator OperatorsMask;
1804 public TypeSpec ReturnType;
1806 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1807 : this (ltype, rtype, op_mask, ltype)
1811 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1812 : this (type, type, op_mask, return_type)
1816 public PredefinedOperator (TypeSpec type, Operator op_mask)
1817 : this (type, type, op_mask, type)
1821 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1823 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1824 throw new InternalErrorException ("Only masked values can be used");
1828 this.OperatorsMask = op_mask;
1829 this.ReturnType = return_type;
1832 public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1834 b.type = ReturnType;
1836 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1837 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1840 // A user operators does not support multiple user conversions, but decimal type
1841 // is considered to be predefined type therefore we apply predefined operators rules
1842 // and then look for decimal user-operator implementation
1844 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal)
1845 return b.ResolveUserOperator (ec, b.left, b.right);
1847 var c = b.right as Constant;
1849 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1850 return ReducedExpression.Create (b.left, b).Resolve (ec);
1851 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
1852 return ReducedExpression.Create (b.left, b).Resolve (ec);
1856 c = b.left as Constant;
1858 if (c.IsDefaultValue && (b.oper == Operator.Addition || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1859 return ReducedExpression.Create (b.right, b).Resolve (ec);
1860 if (b.oper == Operator.Multiply && c.IsOneInteger)
1861 return ReducedExpression.Create (b.right, b).Resolve (ec);
1868 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
1871 // We are dealing with primitive types only
1873 return left == ltype && ltype == rtype;
1876 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1879 if (left == lexpr.Type && right == rexpr.Type)
1882 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1883 Convert.ImplicitConversionExists (ec, rexpr, right);
1886 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1889 if (left != null && best_operator.left != null) {
1890 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left, left);
1894 // When second argument is same as the first one, the result is same
1896 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1897 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right, right);
1900 if (result == 0 || result > 2)
1903 return result == 1 ? best_operator : this;
1907 sealed class PredefinedStringOperator : PredefinedOperator
1909 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
1910 : base (type, type, op_mask, retType)
1914 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
1915 : base (ltype, rtype, op_mask, retType)
1919 public override Expression ConvertResult (ResolveContext ec, Binary b)
1922 // Use original expression for nullable arguments
1924 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1926 b.left = unwrap.Original;
1928 unwrap = b.right as Nullable.Unwrap;
1930 b.right = unwrap.Original;
1932 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1933 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1936 // Start a new concat expression using converted expression
1938 return StringConcat.Create (ec, b.left, b.right, b.loc);
1942 sealed class PredefinedShiftOperator : PredefinedOperator
1944 public PredefinedShiftOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1945 : base (ltype, rtype, op_mask)
1949 public override Expression ConvertResult (ResolveContext ec, Binary b)
1951 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1953 Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1955 int right_mask = left.BuiltinType == BuiltinTypeSpec.Type.Int || left.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
1958 // b = b.left >> b.right & (0x1f|0x3f)
1960 b.right = new Binary (Operator.BitwiseAnd,
1961 b.right, new IntConstant (ec.BuiltinTypes, right_mask, b.right.Location), b.loc).Resolve (ec);
1964 // Expression tree representation does not use & mask
1966 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1967 b.type = ReturnType;
1970 // Optimize shift by 0
1972 var c = b.right as Constant;
1973 if (c != null && c.IsDefaultValue)
1974 return ReducedExpression.Create (b.left, b).Resolve (ec);
1980 sealed class PredefinedEqualityOperator : PredefinedOperator
1982 MethodSpec equal_method, inequal_method;
1984 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
1985 : base (arg, arg, Operator.EqualityMask, retType)
1989 public override Expression ConvertResult (ResolveContext ec, Binary b)
1991 b.type = ReturnType;
1993 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1994 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1996 Arguments args = new Arguments (2);
1997 args.Add (new Argument (b.left));
1998 args.Add (new Argument (b.right));
2001 if (b.oper == Operator.Equality) {
2002 if (equal_method == null) {
2003 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2004 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2005 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2006 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2008 throw new NotImplementedException (left.GetSignatureForError ());
2011 method = equal_method;
2013 if (inequal_method == null) {
2014 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2015 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2016 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2017 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2019 throw new NotImplementedException (left.GetSignatureForError ());
2022 method = inequal_method;
2025 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2029 class PredefinedPointerOperator : PredefinedOperator
2031 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2032 : base (ltype, rtype, op_mask)
2036 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2037 : base (ltype, rtype, op_mask, retType)
2041 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2042 : base (type, op_mask, return_type)
2046 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2049 if (!lexpr.Type.IsPointer)
2052 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2056 if (right == null) {
2057 if (!rexpr.Type.IsPointer)
2060 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2067 public override Expression ConvertResult (ResolveContext ec, Binary b)
2070 b.left = EmptyCast.Create (b.left, left);
2071 } else if (right != null) {
2072 b.right = EmptyCast.Create (b.right, right);
2075 TypeSpec r_type = ReturnType;
2076 Expression left_arg, right_arg;
2077 if (r_type == null) {
2080 right_arg = b.right;
2081 r_type = b.left.Type;
2085 r_type = b.right.Type;
2089 right_arg = b.right;
2092 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2097 public enum Operator {
2098 Multiply = 0 | ArithmeticMask,
2099 Division = 1 | ArithmeticMask,
2100 Modulus = 2 | ArithmeticMask,
2101 Addition = 3 | ArithmeticMask | AdditionMask,
2102 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2104 LeftShift = 5 | ShiftMask,
2105 RightShift = 6 | ShiftMask,
2107 LessThan = 7 | ComparisonMask | RelationalMask,
2108 GreaterThan = 8 | ComparisonMask | RelationalMask,
2109 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2110 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2111 Equality = 11 | ComparisonMask | EqualityMask,
2112 Inequality = 12 | ComparisonMask | EqualityMask,
2114 BitwiseAnd = 13 | BitwiseMask,
2115 ExclusiveOr = 14 | BitwiseMask,
2116 BitwiseOr = 15 | BitwiseMask,
2118 LogicalAnd = 16 | LogicalMask,
2119 LogicalOr = 17 | LogicalMask,
2124 ValuesOnlyMask = ArithmeticMask - 1,
2125 ArithmeticMask = 1 << 5,
2127 ComparisonMask = 1 << 7,
2128 EqualityMask = 1 << 8,
2129 BitwiseMask = 1 << 9,
2130 LogicalMask = 1 << 10,
2131 AdditionMask = 1 << 11,
2132 SubtractionMask = 1 << 12,
2133 RelationalMask = 1 << 13
2136 protected enum State
2140 LeftNullLifted = 1 << 2,
2141 RightNullLifted = 1 << 3
2144 readonly Operator oper;
2145 protected Expression left, right;
2146 protected State state;
2147 Expression enum_conversion;
2149 public Binary (Operator oper, Expression left, Expression right, bool isCompound, Location loc)
2150 : this (oper, left, right, loc)
2153 state |= State.Compound;
2156 public Binary (Operator oper, Expression left, Expression right, Location loc)
2166 public bool IsCompound {
2168 return (state & State.Compound) != 0;
2172 public Operator Oper {
2181 /// Returns a stringified representation of the Operator
2183 string OperName (Operator oper)
2187 case Operator.Multiply:
2190 case Operator.Division:
2193 case Operator.Modulus:
2196 case Operator.Addition:
2199 case Operator.Subtraction:
2202 case Operator.LeftShift:
2205 case Operator.RightShift:
2208 case Operator.LessThan:
2211 case Operator.GreaterThan:
2214 case Operator.LessThanOrEqual:
2217 case Operator.GreaterThanOrEqual:
2220 case Operator.Equality:
2223 case Operator.Inequality:
2226 case Operator.BitwiseAnd:
2229 case Operator.BitwiseOr:
2232 case Operator.ExclusiveOr:
2235 case Operator.LogicalOr:
2238 case Operator.LogicalAnd:
2242 s = oper.ToString ();
2252 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2254 new Binary (oper, left, right, loc).Error_OperatorCannotBeApplied (ec, left, right);
2257 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2259 if (left.Type == InternalType.FakeInternalType || right.Type == InternalType.FakeInternalType)
2263 l = TypeManager.CSharpName (left.Type);
2264 r = TypeManager.CSharpName (right.Type);
2266 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2270 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2272 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2276 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2278 string GetOperatorExpressionTypeName ()
2281 case Operator.Addition:
2282 return IsCompound ? "AddAssign" : "Add";
2283 case Operator.BitwiseAnd:
2284 return IsCompound ? "AndAssign" : "And";
2285 case Operator.BitwiseOr:
2286 return IsCompound ? "OrAssign" : "Or";
2287 case Operator.Division:
2288 return IsCompound ? "DivideAssign" : "Divide";
2289 case Operator.ExclusiveOr:
2290 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2291 case Operator.Equality:
2293 case Operator.GreaterThan:
2294 return "GreaterThan";
2295 case Operator.GreaterThanOrEqual:
2296 return "GreaterThanOrEqual";
2297 case Operator.Inequality:
2299 case Operator.LeftShift:
2300 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2301 case Operator.LessThan:
2303 case Operator.LessThanOrEqual:
2304 return "LessThanOrEqual";
2305 case Operator.LogicalAnd:
2307 case Operator.LogicalOr:
2309 case Operator.Modulus:
2310 return IsCompound ? "ModuloAssign" : "Modulo";
2311 case Operator.Multiply:
2312 return IsCompound ? "MultiplyAssign" : "Multiply";
2313 case Operator.RightShift:
2314 return IsCompound ? "RightShiftAssign" : "RightShift";
2315 case Operator.Subtraction:
2316 return IsCompound ? "SubtractAssign" : "Subtract";
2318 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2322 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2325 case Operator.Addition:
2326 return CSharp.Operator.OpType.Addition;
2327 case Operator.BitwiseAnd:
2328 case Operator.LogicalAnd:
2329 return CSharp.Operator.OpType.BitwiseAnd;
2330 case Operator.BitwiseOr:
2331 case Operator.LogicalOr:
2332 return CSharp.Operator.OpType.BitwiseOr;
2333 case Operator.Division:
2334 return CSharp.Operator.OpType.Division;
2335 case Operator.Equality:
2336 return CSharp.Operator.OpType.Equality;
2337 case Operator.ExclusiveOr:
2338 return CSharp.Operator.OpType.ExclusiveOr;
2339 case Operator.GreaterThan:
2340 return CSharp.Operator.OpType.GreaterThan;
2341 case Operator.GreaterThanOrEqual:
2342 return CSharp.Operator.OpType.GreaterThanOrEqual;
2343 case Operator.Inequality:
2344 return CSharp.Operator.OpType.Inequality;
2345 case Operator.LeftShift:
2346 return CSharp.Operator.OpType.LeftShift;
2347 case Operator.LessThan:
2348 return CSharp.Operator.OpType.LessThan;
2349 case Operator.LessThanOrEqual:
2350 return CSharp.Operator.OpType.LessThanOrEqual;
2351 case Operator.Modulus:
2352 return CSharp.Operator.OpType.Modulus;
2353 case Operator.Multiply:
2354 return CSharp.Operator.OpType.Multiply;
2355 case Operator.RightShift:
2356 return CSharp.Operator.OpType.RightShift;
2357 case Operator.Subtraction:
2358 return CSharp.Operator.OpType.Subtraction;
2360 throw new InternalErrorException (op.ToString ());
2364 public override bool ContainsEmitWithAwait ()
2366 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2369 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l)
2374 case Operator.Multiply:
2375 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2376 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2377 opcode = OpCodes.Mul_Ovf;
2378 else if (!IsFloat (l))
2379 opcode = OpCodes.Mul_Ovf_Un;
2381 opcode = OpCodes.Mul;
2383 opcode = OpCodes.Mul;
2387 case Operator.Division:
2389 opcode = OpCodes.Div_Un;
2391 opcode = OpCodes.Div;
2394 case Operator.Modulus:
2396 opcode = OpCodes.Rem_Un;
2398 opcode = OpCodes.Rem;
2401 case Operator.Addition:
2402 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2403 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2404 opcode = OpCodes.Add_Ovf;
2405 else if (!IsFloat (l))
2406 opcode = OpCodes.Add_Ovf_Un;
2408 opcode = OpCodes.Add;
2410 opcode = OpCodes.Add;
2413 case Operator.Subtraction:
2414 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2415 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2416 opcode = OpCodes.Sub_Ovf;
2417 else if (!IsFloat (l))
2418 opcode = OpCodes.Sub_Ovf_Un;
2420 opcode = OpCodes.Sub;
2422 opcode = OpCodes.Sub;
2425 case Operator.RightShift:
2427 opcode = OpCodes.Shr_Un;
2429 opcode = OpCodes.Shr;
2432 case Operator.LeftShift:
2433 opcode = OpCodes.Shl;
2436 case Operator.Equality:
2437 opcode = OpCodes.Ceq;
2440 case Operator.Inequality:
2441 ec.Emit (OpCodes.Ceq);
2444 opcode = OpCodes.Ceq;
2447 case Operator.LessThan:
2449 opcode = OpCodes.Clt_Un;
2451 opcode = OpCodes.Clt;
2454 case Operator.GreaterThan:
2456 opcode = OpCodes.Cgt_Un;
2458 opcode = OpCodes.Cgt;
2461 case Operator.LessThanOrEqual:
2462 if (IsUnsigned (l) || IsFloat (l))
2463 ec.Emit (OpCodes.Cgt_Un);
2465 ec.Emit (OpCodes.Cgt);
2468 opcode = OpCodes.Ceq;
2471 case Operator.GreaterThanOrEqual:
2472 if (IsUnsigned (l) || IsFloat (l))
2473 ec.Emit (OpCodes.Clt_Un);
2475 ec.Emit (OpCodes.Clt);
2479 opcode = OpCodes.Ceq;
2482 case Operator.BitwiseOr:
2483 opcode = OpCodes.Or;
2486 case Operator.BitwiseAnd:
2487 opcode = OpCodes.And;
2490 case Operator.ExclusiveOr:
2491 opcode = OpCodes.Xor;
2495 throw new InternalErrorException (oper.ToString ());
2501 static bool IsUnsigned (TypeSpec t)
2503 switch (t.BuiltinType) {
2504 case BuiltinTypeSpec.Type.Char:
2505 case BuiltinTypeSpec.Type.UInt:
2506 case BuiltinTypeSpec.Type.ULong:
2507 case BuiltinTypeSpec.Type.UShort:
2508 case BuiltinTypeSpec.Type.Byte:
2515 static bool IsFloat (TypeSpec t)
2517 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2520 Expression ResolveOperator (ResolveContext ec)
2522 TypeSpec l = left.Type;
2523 TypeSpec r = right.Type;
2525 bool primitives_only = false;
2528 // Handles predefined primitive types
2530 if (BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r)) {
2531 if ((oper & Operator.ShiftMask) == 0) {
2532 if (l.BuiltinType != BuiltinTypeSpec.Type.Bool && !DoBinaryOperatorPromotion (ec))
2535 primitives_only = true;
2539 if (l.IsPointer || r.IsPointer)
2540 return ResolveOperatorPointer (ec, l, r);
2543 bool lenum = l.IsEnum;
2544 bool renum = r.IsEnum;
2545 if (lenum || renum) {
2546 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2553 if ((oper == Operator.Addition || oper == Operator.Subtraction) && (l.IsDelegate || r.IsDelegate)) {
2555 expr = ResolveOperatorDelegate (ec, l, r);
2557 // TODO: Can this be ambiguous
2563 expr = ResolveUserOperator (ec, left, right);
2567 // Predefined reference types equality
2568 if ((oper & Operator.EqualityMask) != 0) {
2569 expr = ResolveOperatorEquality (ec, l, r);
2575 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, primitives_only, null);
2578 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2579 // if 'left' is not an enumeration constant, create one from the type of 'right'
2580 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2583 case Operator.BitwiseOr:
2584 case Operator.BitwiseAnd:
2585 case Operator.ExclusiveOr:
2586 case Operator.Equality:
2587 case Operator.Inequality:
2588 case Operator.LessThan:
2589 case Operator.LessThanOrEqual:
2590 case Operator.GreaterThan:
2591 case Operator.GreaterThanOrEqual:
2592 if (TypeManager.IsEnumType (left.Type))
2595 if (left.IsZeroInteger)
2596 return left.TryReduce (ec, right.Type, loc);
2600 case Operator.Addition:
2601 case Operator.Subtraction:
2604 case Operator.Multiply:
2605 case Operator.Division:
2606 case Operator.Modulus:
2607 case Operator.LeftShift:
2608 case Operator.RightShift:
2609 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2618 // The `|' operator used on types which were extended is dangerous
2620 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2622 OpcodeCast lcast = left as OpcodeCast;
2623 if (lcast != null) {
2624 if (IsUnsigned (lcast.UnderlyingType))
2628 OpcodeCast rcast = right as OpcodeCast;
2629 if (rcast != null) {
2630 if (IsUnsigned (rcast.UnderlyingType))
2634 if (lcast == null && rcast == null)
2637 // FIXME: consider constants
2639 ec.Report.Warning (675, 3, loc,
2640 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2641 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2644 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
2646 return new PredefinedOperator[] {
2648 // Pointer arithmetic:
2650 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2651 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2652 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2653 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2655 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
2656 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
2657 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
2658 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
2661 // T* operator + (int y, T* x);
2662 // T* operator + (uint y, T *x);
2663 // T* operator + (long y, T *x);
2664 // T* operator + (ulong y, T *x);
2666 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
2667 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
2668 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
2669 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
2672 // long operator - (T* x, T *y)
2674 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
2678 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
2680 TypeSpec bool_type = types.Bool;
2681 return new PredefinedOperator[] {
2682 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask),
2683 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
2684 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
2685 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
2686 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
2687 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
2688 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
2690 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
2691 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
2692 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
2693 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
2694 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
2695 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
2696 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
2698 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
2699 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
2700 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
2702 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
2704 new PredefinedShiftOperator (types.Int, types.Int, Operator.ShiftMask),
2705 new PredefinedShiftOperator (types.UInt, types.Int, Operator.ShiftMask),
2706 new PredefinedShiftOperator (types.Long, types.Int, Operator.ShiftMask),
2707 new PredefinedShiftOperator (types.ULong, types.Int, Operator.ShiftMask)
2711 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
2713 TypeSpec bool_type = types.Bool;
2715 return new PredefinedOperator[] {
2716 new PredefinedEqualityOperator (types.String, bool_type),
2717 new PredefinedEqualityOperator (types.Delegate, bool_type),
2718 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type)
2723 // Rules used during binary numeric promotion
2725 static bool DoNumericPromotion (ResolveContext rc, ref Expression prim_expr, ref Expression second_expr, TypeSpec type)
2729 Constant c = prim_expr as Constant;
2731 temp = c.ConvertImplicitly (type);
2738 if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
2739 switch (prim_expr.Type.BuiltinType) {
2740 case BuiltinTypeSpec.Type.Int:
2741 case BuiltinTypeSpec.Type.Short:
2742 case BuiltinTypeSpec.Type.SByte:
2743 case BuiltinTypeSpec.Type.Long:
2744 type = rc.BuiltinTypes.Long;
2746 if (type != second_expr.Type) {
2747 c = second_expr as Constant;
2749 temp = c.ConvertImplicitly (type);
2751 temp = Convert.ImplicitNumericConversion (second_expr, type);
2758 } else if (type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
2760 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2762 switch (type.BuiltinType) {
2763 case BuiltinTypeSpec.Type.Int:
2764 case BuiltinTypeSpec.Type.Long:
2765 case BuiltinTypeSpec.Type.Short:
2766 case BuiltinTypeSpec.Type.SByte:
2771 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2780 // 7.2.6.2 Binary numeric promotions
2782 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2784 TypeSpec ltype = left.Type;
2785 TypeSpec rtype = right.Type;
2788 foreach (TypeSpec t in ec.BuiltinTypes.BinaryPromotionsTypes) {
2790 return t == rtype || DoNumericPromotion (ec, ref right, ref left, t);
2793 return t == ltype || DoNumericPromotion (ec, ref left, ref right, t);
2796 TypeSpec int32 = ec.BuiltinTypes.Int;
2797 if (ltype != int32) {
2798 Constant c = left as Constant;
2800 temp = c.ConvertImplicitly (int32);
2802 temp = Convert.ImplicitNumericConversion (left, int32);
2809 if (rtype != int32) {
2810 Constant c = right as Constant;
2812 temp = c.ConvertImplicitly (int32);
2814 temp = Convert.ImplicitNumericConversion (right, int32);
2824 protected override Expression DoResolve (ResolveContext ec)
2829 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2830 left = ((ParenthesizedExpression) left).Expr;
2831 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2835 if (left.eclass == ExprClass.Type) {
2836 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2840 left = left.Resolve (ec);
2845 Constant lc = left as Constant;
2847 if (lc != null && lc.Type.BuiltinType == BuiltinTypeSpec.Type.Bool &&
2848 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2849 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2851 // FIXME: resolve right expression as unreachable
2852 // right.Resolve (ec);
2854 ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2858 right = right.Resolve (ec);
2862 eclass = ExprClass.Value;
2863 Constant rc = right as Constant;
2865 // The conversion rules are ignored in enum context but why
2866 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2867 lc = EnumLiftUp (ec, lc, rc, loc);
2869 rc = EnumLiftUp (ec, rc, lc, loc);
2872 if (rc != null && lc != null) {
2873 int prev_e = ec.Report.Errors;
2874 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
2875 if (e != null || ec.Report.Errors != prev_e)
2879 // Comparison warnings
2880 if ((oper & Operator.ComparisonMask) != 0) {
2881 if (left.Equals (right)) {
2882 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2884 CheckOutOfRangeComparison (ec, lc, right.Type);
2885 CheckOutOfRangeComparison (ec, rc, left.Type);
2888 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2890 var rt = right.Type;
2891 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
2892 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
2893 Error_OperatorCannotBeApplied (ec, left, right);
2900 // Special handling for logical boolean operators which require rhs not to be
2901 // evaluated based on lhs value
2903 if ((oper & Operator.LogicalMask) != 0) {
2904 Expression cond_left, cond_right, expr;
2906 args = new Arguments (2);
2908 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2909 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, ec.CurrentBlock, loc);
2911 var cond_args = new Arguments (1);
2912 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left).Resolve (ec)));
2915 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
2916 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
2918 left = temp.CreateReferenceExpression (ec, loc);
2919 if (oper == Operator.LogicalAnd) {
2920 expr = DynamicUnaryConversion.CreateIsFalse (ec, cond_args, loc);
2923 expr = DynamicUnaryConversion.CreateIsTrue (ec, cond_args, loc);
2927 args.Add (new Argument (left));
2928 args.Add (new Argument (right));
2929 cond_right = new DynamicExpressionStatement (this, args, loc);
2931 LocalVariable temp = LocalVariable.CreateCompilerGenerated (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
2933 args.Add (new Argument (temp.CreateReferenceExpression (ec, loc).Resolve (ec)));
2934 args.Add (new Argument (right));
2935 right = new DynamicExpressionStatement (this, args, loc);
2938 // bool && dynamic => (temp = left) ? temp && right : temp;
2939 // bool || dynamic => (temp = left) ? temp : temp || right;
2941 if (oper == Operator.LogicalAnd) {
2943 cond_right = temp.CreateReferenceExpression (ec, loc);
2945 cond_left = temp.CreateReferenceExpression (ec, loc);
2949 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left));
2952 return new Conditional (expr, cond_left, cond_right, loc).Resolve (ec);
2955 args = new Arguments (2);
2956 args.Add (new Argument (left));
2957 args.Add (new Argument (right));
2958 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
2961 if (ec.Module.Compiler.Settings.Version >= LanguageVersion.ISO_2 &&
2962 ((left.Type.IsNullableType && (right is NullLiteral || right.Type.IsNullableType || TypeSpec.IsValueType (right.Type))) ||
2963 (TypeSpec.IsValueType (left.Type) && right is NullLiteral) ||
2964 (right.Type.IsNullableType && (left is NullLiteral || left.Type.IsNullableType || TypeSpec.IsValueType (left.Type))) ||
2965 (TypeSpec.IsValueType (right.Type) && left is NullLiteral))) {
2966 var lifted = new Nullable.LiftedBinaryOperator (oper, left, right, loc);
2967 lifted.state = state;
2968 return lifted.Resolve (ec);
2971 return DoResolveCore (ec, left, right);
2974 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
2976 Expression expr = ResolveOperator (ec);
2978 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
2980 if (left == null || right == null)
2981 throw new InternalErrorException ("Invalid conversion");
2983 if (oper == Operator.BitwiseOr)
2984 CheckBitwiseOrOnSignExtended (ec);
2989 public override SLE.Expression MakeExpression (BuilderContext ctx)
2991 var le = left.MakeExpression (ctx);
2992 var re = right.MakeExpression (ctx);
2993 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
2996 case Operator.Addition:
2997 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
2998 case Operator.BitwiseAnd:
2999 return SLE.Expression.And (le, re);
3000 case Operator.BitwiseOr:
3001 return SLE.Expression.Or (le, re);
3002 case Operator.Division:
3003 return SLE.Expression.Divide (le, re);
3004 case Operator.Equality:
3005 return SLE.Expression.Equal (le, re);
3006 case Operator.ExclusiveOr:
3007 return SLE.Expression.ExclusiveOr (le, re);
3008 case Operator.GreaterThan:
3009 return SLE.Expression.GreaterThan (le, re);
3010 case Operator.GreaterThanOrEqual:
3011 return SLE.Expression.GreaterThanOrEqual (le, re);
3012 case Operator.Inequality:
3013 return SLE.Expression.NotEqual (le, re);
3014 case Operator.LeftShift:
3015 return SLE.Expression.LeftShift (le, re);
3016 case Operator.LessThan:
3017 return SLE.Expression.LessThan (le, re);
3018 case Operator.LessThanOrEqual:
3019 return SLE.Expression.LessThanOrEqual (le, re);
3020 case Operator.LogicalAnd:
3021 return SLE.Expression.AndAlso (le, re);
3022 case Operator.LogicalOr:
3023 return SLE.Expression.OrElse (le, re);
3024 case Operator.Modulus:
3025 return SLE.Expression.Modulo (le, re);
3026 case Operator.Multiply:
3027 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3028 case Operator.RightShift:
3029 return SLE.Expression.RightShift (le, re);
3030 case Operator.Subtraction:
3031 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3033 throw new NotImplementedException (oper.ToString ());
3038 // D operator + (D x, D y)
3039 // D operator - (D x, D y)
3041 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3043 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3045 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3046 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3051 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3052 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3062 MethodSpec method = null;
3063 Arguments args = new Arguments (2);
3064 args.Add (new Argument (left));
3065 args.Add (new Argument (right));
3067 if (oper == Operator.Addition) {
3068 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3069 } else if (oper == Operator.Subtraction) {
3070 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3074 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3076 MethodGroupExpr mg = MethodGroupExpr.CreatePredefined (method, ec.BuiltinTypes.Delegate, loc);
3077 Expression expr = new UserOperatorCall (mg.BestCandidate, args, CreateExpressionTree, loc);
3078 return new ClassCast (expr, l);
3082 // Enumeration operators
3084 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3087 // bool operator == (E x, E y);
3088 // bool operator != (E x, E y);
3089 // bool operator < (E x, E y);
3090 // bool operator > (E x, E y);
3091 // bool operator <= (E x, E y);
3092 // bool operator >= (E x, E y);
3094 // E operator & (E x, E y);
3095 // E operator | (E x, E y);
3096 // E operator ^ (E x, E y);
3098 // U operator - (E e, E f)
3099 // E operator - (E e, U x)
3100 // E operator - (U x, E e) // LAMESPEC: Not covered by the specification
3102 // E operator + (E e, U x)
3103 // E operator + (U x, E e)
3105 Expression ltemp = left;
3106 Expression rtemp = right;
3107 TypeSpec underlying_type;
3108 TypeSpec underlying_type_result;
3113 // LAMESPEC: There is never ambiguous conversion between enum operators
3114 // the one which contains more enum parameters always wins even if there
3115 // is an implicit conversion involved
3117 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3119 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3120 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
3127 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3128 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
3138 if ((oper & Operator.BitwiseMask) != 0) {
3140 underlying_type_result = underlying_type;
3143 underlying_type_result = null;
3145 } else if (oper == Operator.Subtraction) {
3147 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3148 if (ltype != rtype) {
3149 expr = Convert.ImplicitConversion (ec, left, rtype, left.Location);
3151 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3157 res_type = underlying_type;
3162 res_type = underlying_type;
3165 underlying_type_result = underlying_type;
3167 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3168 expr = Convert.ImplicitConversion (ec, right, ltype, right.Location);
3169 if (expr == null || expr is EnumConstant) {
3170 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3176 res_type = underlying_type;
3180 underlying_type_result = underlying_type;
3184 } else if (oper == Operator.Addition) {
3186 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3189 if (rtype != underlying_type && (state & (State.RightNullLifted | State.LeftNullLifted)) == 0) {
3190 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3197 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3199 if (ltype != underlying_type) {
3200 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3208 underlying_type_result = underlying_type;
3213 // Unwrap the constant correctly, so DoBinaryOperatorPromotion can do the magic
3214 // with constants and expressions
3215 if (left.Type != underlying_type) {
3216 if (left is Constant)
3217 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
3219 left = EmptyCast.Create (left, underlying_type);
3222 if (right.Type != underlying_type) {
3223 if (right is Constant)
3224 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
3226 right = EmptyCast.Create (right, underlying_type);
3230 // C# specification uses explicit cast syntax which means binary promotion
3231 // should happen, however it seems that csc does not do that
3233 if (!DoBinaryOperatorPromotion (ec)) {
3239 if (underlying_type_result != null && left.Type != underlying_type_result) {
3240 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (left.Type), underlying_type_result);
3243 expr = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, true, res_type);
3255 // If the return type of the selected operator is implicitly convertible to the type of x
3257 if (Convert.ImplicitConversionExists (ec, expr, ltype))
3261 // Otherwise, if the selected operator is a predefined operator, if the return type of the
3262 // selected operator is explicitly convertible to the type of x, and if y is implicitly
3263 // convertible to the type of x or the operator is a shift operator, then the operation
3264 // is evaluated as x = (T)(x op y), where T is the type of x
3266 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
3270 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
3277 // 7.9.6 Reference type equality operators
3279 Expression ResolveOperatorEquality (ResolveContext ec, TypeSpec l, TypeSpec r)
3282 type = ec.BuiltinTypes.Bool;
3285 // a, Both operands are reference-type values or the value null
3286 // b, One operand is a value of type T where T is a type-parameter and
3287 // the other operand is the value null. Furthermore T does not have the
3288 // value type constraint
3290 // LAMESPEC: Very confusing details in the specification, basically any
3291 // reference like type-parameter is allowed
3293 var tparam_l = l as TypeParameterSpec;
3294 var tparam_r = r as TypeParameterSpec;
3295 if (tparam_l != null) {
3296 if (right is NullLiteral && !tparam_l.HasSpecialStruct) {
3297 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3301 if (!tparam_l.IsReferenceType)
3304 l = tparam_l.GetEffectiveBase ();
3305 left = new BoxedCast (left, l);
3306 } else if (left is NullLiteral && tparam_r == null) {
3307 if (!TypeSpec.IsReferenceType (r) || r.Kind == MemberKind.InternalCompilerType)
3313 if (tparam_r != null) {
3314 if (left is NullLiteral && !tparam_r.HasSpecialStruct) {
3315 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3319 if (!tparam_r.IsReferenceType)
3322 r = tparam_r.GetEffectiveBase ();
3323 right = new BoxedCast (right, r);
3324 } else if (right is NullLiteral) {
3325 if (!TypeSpec.IsReferenceType (l) || l.Kind == MemberKind.InternalCompilerType)
3332 // LAMESPEC: method groups can be compared when they convert to other side delegate
3335 if (right.eclass == ExprClass.MethodGroup) {
3336 result = Convert.ImplicitConversion (ec, right, l, loc);
3342 } else if (r.IsDelegate && l != r) {
3345 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3346 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3355 // bool operator != (string a, string b)
3356 // bool operator == (string a, string b)
3358 // bool operator != (Delegate a, Delegate b)
3359 // bool operator == (Delegate a, Delegate b)
3361 // bool operator != (bool a, bool b)
3362 // bool operator == (bool a, bool b)
3364 // LAMESPEC: Reference equality comparison can apply to value types when
3365 // they implement an implicit conversion to any of types above.
3367 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3368 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, false, null);
3374 // bool operator != (object a, object b)
3375 // bool operator == (object a, object b)
3377 // An explicit reference conversion exists from the
3378 // type of either operand to the type of the other operand.
3381 // Optimize common path
3383 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3386 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3387 !Convert.ExplicitReferenceConversionExists (r, l))
3390 // Reject allowed explicit conversions like int->object
3391 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
3394 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3395 ec.Report.Warning (253, 2, loc,
3396 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3397 l.GetSignatureForError ());
3399 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3400 ec.Report.Warning (252, 2, loc,
3401 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3402 r.GetSignatureForError ());
3408 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3411 // bool operator == (void* x, void* y);
3412 // bool operator != (void* x, void* y);
3413 // bool operator < (void* x, void* y);
3414 // bool operator > (void* x, void* y);
3415 // bool operator <= (void* x, void* y);
3416 // bool operator >= (void* x, void* y);
3418 if ((oper & Operator.ComparisonMask) != 0) {
3421 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3428 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3434 type = ec.BuiltinTypes.Bool;
3438 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false, null);
3442 // Build-in operators method overloading
3444 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, TypeSpec enum_type)
3446 PredefinedOperator best_operator = null;
3447 TypeSpec l = left.Type;
3448 TypeSpec r = right.Type;
3449 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3451 foreach (PredefinedOperator po in operators) {
3452 if ((po.OperatorsMask & oper_mask) == 0)
3455 if (primitives_only) {
3456 if (!po.IsPrimitiveApplicable (l, r))
3459 if (!po.IsApplicable (ec, left, right))
3463 if (best_operator == null) {
3465 if (primitives_only)
3471 best_operator = po.ResolveBetterOperator (ec, best_operator);
3473 if (best_operator == null) {
3474 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3475 OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
3482 if (best_operator == null)
3485 Expression expr = best_operator.ConvertResult (ec, this);
3488 // Optimize &/&& constant expressions with 0 value
3490 if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
3491 Constant rc = right as Constant;
3492 Constant lc = left as Constant;
3493 if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
3495 // The result is a constant with side-effect
3497 Constant side_effect = rc == null ?
3498 new SideEffectConstant (lc, right, loc) :
3499 new SideEffectConstant (rc, left, loc);
3501 return ReducedExpression.Create (side_effect, expr);
3505 if (enum_type == null)
3509 // HACK: required by enum_conversion
3511 expr.Type = enum_type;
3512 return EmptyCast.Create (expr, enum_type);
3516 // Performs user-operator overloading
3518 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression left, Expression right)
3520 var op = ConvertBinaryToUserOperator (oper);
3522 if (l.IsNullableType)
3523 l = Nullable.NullableInfo.GetUnderlyingType (l);
3525 if (r.IsNullableType)
3526 r = Nullable.NullableInfo.GetUnderlyingType (r);
3528 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
3529 IList<MemberSpec> right_operators = null;
3532 right_operators = MemberCache.GetUserOperator (r, op, false);
3533 if (right_operators == null && left_operators == null)
3535 } else if (left_operators == null) {
3539 Arguments args = new Arguments (2);
3540 Argument larg = new Argument (left);
3542 Argument rarg = new Argument (right);
3546 // User-defined operator implementations always take precedence
3547 // over predefined operator implementations
3549 if (left_operators != null && right_operators != null) {
3550 left_operators = CombineUserOperators (left_operators, right_operators);
3551 } else if (right_operators != null) {
3552 left_operators = right_operators;
3555 var res = new OverloadResolver (left_operators, OverloadResolver.Restrictions.ProbingOnly |
3556 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded, loc);
3558 var oper_method = res.ResolveOperator (ec, ref args);
3559 if (oper_method == null)
3562 var llifted = (state & State.LeftNullLifted) != 0;
3563 var rlifted = (state & State.RightNullLifted) != 0;
3564 if ((Oper & Operator.EqualityMask) != 0) {
3565 var parameters = oper_method.Parameters;
3566 // LAMESPEC: No idea why this is not allowed
3567 if ((left is Nullable.Unwrap || right is Nullable.Unwrap) && parameters.Types [0] != parameters.Types [1])
3570 // Binary operation was lifted but we have found a user operator
3571 // which requires value-type argument, we downgrade ourself back to
3573 // LAMESPEC: The user operator is not called (it cannot be we are passing null to struct)
3574 // but compilation succeeds
3575 if ((llifted && !parameters.Types[0].IsStruct) || (rlifted && !parameters.Types[1].IsStruct)) {
3576 state &= ~(State.LeftNullLifted | State.RightNullLifted);
3580 Expression oper_expr;
3582 // TODO: CreateExpressionTree is allocated every time
3583 if ((oper & Operator.LogicalMask) != 0) {
3584 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
3585 oper == Operator.LogicalAnd, loc).Resolve (ec);
3587 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
3591 this.left = larg.Expr;
3594 this.right = rarg.Expr;
3600 // Merge two sets of user operators into one, they are mostly distinguish
3601 // expect when they share base type and it contains an operator
3603 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
3605 var combined = new List<MemberSpec> (left.Count + right.Count);
3606 combined.AddRange (left);
3607 foreach (var r in right) {
3609 foreach (var l in left) {
3610 if (l.DeclaringType == r.DeclaringType) {
3623 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
3625 if (c is IntegralConstant || c is CharConstant) {
3627 c.ConvertExplicitly (true, type);
3628 } catch (OverflowException) {
3629 ec.Report.Warning (652, 2, loc,
3630 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
3631 TypeManager.CSharpName (type));
3637 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3638 /// context of a conditional bool expression. This function will return
3639 /// false if it is was possible to use EmitBranchable, or true if it was.
3641 /// The expression's code is generated, and we will generate a branch to `target'
3642 /// if the resulting expression value is equal to isTrue
3644 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3647 // This is more complicated than it looks, but its just to avoid
3648 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3649 // but on top of that we want for == and != to use a special path
3650 // if we are comparing against null
3652 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
3653 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3656 // put the constant on the rhs, for simplicity
3658 if (left is Constant) {
3659 Expression swap = right;
3665 // brtrue/brfalse works with native int only
3667 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
3668 left.EmitBranchable (ec, target, my_on_true);
3671 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
3672 // right is a boolean, and it's not 'false' => it is 'true'
3673 left.EmitBranchable (ec, target, !my_on_true);
3677 } else if (oper == Operator.LogicalAnd) {
3680 Label tests_end = ec.DefineLabel ();
3682 left.EmitBranchable (ec, tests_end, false);
3683 right.EmitBranchable (ec, target, true);
3684 ec.MarkLabel (tests_end);
3687 // This optimizes code like this
3688 // if (true && i > 4)
3690 if (!(left is Constant))
3691 left.EmitBranchable (ec, target, false);
3693 if (!(right is Constant))
3694 right.EmitBranchable (ec, target, false);
3699 } else if (oper == Operator.LogicalOr){
3701 left.EmitBranchable (ec, target, true);
3702 right.EmitBranchable (ec, target, true);
3705 Label tests_end = ec.DefineLabel ();
3706 left.EmitBranchable (ec, tests_end, true);
3707 right.EmitBranchable (ec, target, false);
3708 ec.MarkLabel (tests_end);
3713 } else if ((oper & Operator.ComparisonMask) == 0) {
3714 base.EmitBranchable (ec, target, on_true);
3721 TypeSpec t = left.Type;
3722 bool is_float = IsFloat (t);
3723 bool is_unsigned = is_float || IsUnsigned (t);
3726 case Operator.Equality:
3728 ec.Emit (OpCodes.Beq, target);
3730 ec.Emit (OpCodes.Bne_Un, target);
3733 case Operator.Inequality:
3735 ec.Emit (OpCodes.Bne_Un, target);
3737 ec.Emit (OpCodes.Beq, target);
3740 case Operator.LessThan:
3742 if (is_unsigned && !is_float)
3743 ec.Emit (OpCodes.Blt_Un, target);
3745 ec.Emit (OpCodes.Blt, target);
3748 ec.Emit (OpCodes.Bge_Un, target);
3750 ec.Emit (OpCodes.Bge, target);
3753 case Operator.GreaterThan:
3755 if (is_unsigned && !is_float)
3756 ec.Emit (OpCodes.Bgt_Un, target);
3758 ec.Emit (OpCodes.Bgt, target);
3761 ec.Emit (OpCodes.Ble_Un, target);
3763 ec.Emit (OpCodes.Ble, target);
3766 case Operator.LessThanOrEqual:
3768 if (is_unsigned && !is_float)
3769 ec.Emit (OpCodes.Ble_Un, target);
3771 ec.Emit (OpCodes.Ble, target);
3774 ec.Emit (OpCodes.Bgt_Un, target);
3776 ec.Emit (OpCodes.Bgt, target);
3780 case Operator.GreaterThanOrEqual:
3782 if (is_unsigned && !is_float)
3783 ec.Emit (OpCodes.Bge_Un, target);
3785 ec.Emit (OpCodes.Bge, target);
3788 ec.Emit (OpCodes.Blt_Un, target);
3790 ec.Emit (OpCodes.Blt, target);
3793 throw new InternalErrorException (oper.ToString ());
3797 public override void Emit (EmitContext ec)
3799 EmitOperator (ec, left.Type);
3802 protected virtual void EmitOperator (EmitContext ec, TypeSpec l)
3804 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
3805 left = left.EmitToField (ec);
3807 if ((oper & Operator.LogicalMask) == 0) {
3808 right = right.EmitToField (ec);
3813 // Handle short-circuit operators differently
3816 if ((oper & Operator.LogicalMask) != 0) {
3817 Label load_result = ec.DefineLabel ();
3818 Label end = ec.DefineLabel ();
3820 bool is_or = oper == Operator.LogicalOr;
3821 left.EmitBranchable (ec, load_result, is_or);
3823 ec.Emit (OpCodes.Br_S, end);
3825 ec.MarkLabel (load_result);
3826 ec.EmitInt (is_or ? 1 : 0);
3832 // Optimize zero-based operations which cannot be optimized at expression level
3834 if (oper == Operator.Subtraction) {
3835 var lc = left as IntegralConstant;
3836 if (lc != null && lc.IsDefaultValue) {
3838 ec.Emit (OpCodes.Neg);
3845 EmitOperatorOpcode (ec, oper, l);
3848 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3849 // expression because that would wrap lifted binary operation
3851 if (enum_conversion != null)
3852 enum_conversion.Emit (ec);
3855 public override void EmitSideEffect (EmitContext ec)
3857 if ((oper & Operator.LogicalMask) != 0 ||
3858 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3859 base.EmitSideEffect (ec);
3861 left.EmitSideEffect (ec);
3862 right.EmitSideEffect (ec);
3866 protected override void CloneTo (CloneContext clonectx, Expression t)
3868 Binary target = (Binary) t;
3870 target.left = left.Clone (clonectx);
3871 target.right = right.Clone (clonectx);
3874 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3876 Arguments binder_args = new Arguments (4);
3878 MemberAccess sle = new MemberAccess (new MemberAccess (
3879 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3881 CSharpBinderFlags flags = 0;
3882 if (ec.HasSet (ResolveContext.Options.CheckedScope))
3883 flags = CSharpBinderFlags.CheckedContext;
3885 if ((oper & Operator.LogicalMask) != 0)
3886 flags |= CSharpBinderFlags.BinaryOperationLogical;
3888 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
3889 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3890 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
3891 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
3893 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
3896 public override Expression CreateExpressionTree (ResolveContext ec)
3898 return CreateExpressionTree (ec, null);
3901 Expression CreateExpressionTree (ResolveContext ec, Expression method)
3904 bool lift_arg = false;
3907 case Operator.Addition:
3908 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3909 method_name = "AddChecked";
3911 method_name = "Add";
3913 case Operator.BitwiseAnd:
3914 method_name = "And";
3916 case Operator.BitwiseOr:
3919 case Operator.Division:
3920 method_name = "Divide";
3922 case Operator.Equality:
3923 method_name = "Equal";
3926 case Operator.ExclusiveOr:
3927 method_name = "ExclusiveOr";
3929 case Operator.GreaterThan:
3930 method_name = "GreaterThan";
3933 case Operator.GreaterThanOrEqual:
3934 method_name = "GreaterThanOrEqual";
3937 case Operator.Inequality:
3938 method_name = "NotEqual";
3941 case Operator.LeftShift:
3942 method_name = "LeftShift";
3944 case Operator.LessThan:
3945 method_name = "LessThan";
3948 case Operator.LessThanOrEqual:
3949 method_name = "LessThanOrEqual";
3952 case Operator.LogicalAnd:
3953 method_name = "AndAlso";
3955 case Operator.LogicalOr:
3956 method_name = "OrElse";
3958 case Operator.Modulus:
3959 method_name = "Modulo";
3961 case Operator.Multiply:
3962 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3963 method_name = "MultiplyChecked";
3965 method_name = "Multiply";
3967 case Operator.RightShift:
3968 method_name = "RightShift";
3970 case Operator.Subtraction:
3971 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3972 method_name = "SubtractChecked";
3974 method_name = "Subtract";
3978 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3981 Arguments args = new Arguments (2);
3982 args.Add (new Argument (left.CreateExpressionTree (ec)));
3983 args.Add (new Argument (right.CreateExpressionTree (ec)));
3984 if (method != null) {
3986 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
3988 args.Add (new Argument (method));
3991 return CreateExpressionFactoryCall (ec, method_name, args);
3996 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3997 // b, c, d... may be strings or objects.
3999 public class StringConcat : Expression
4001 Arguments arguments;
4003 StringConcat (Location loc)
4006 arguments = new Arguments (2);
4009 public override bool ContainsEmitWithAwait ()
4011 return arguments.ContainsEmitWithAwait ();
4014 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4016 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4017 throw new ArgumentException ();
4019 var s = new StringConcat (loc);
4020 s.type = rc.BuiltinTypes.String;
4021 s.eclass = ExprClass.Value;
4023 s.Append (rc, left);
4024 s.Append (rc, right);
4028 public override Expression CreateExpressionTree (ResolveContext ec)
4030 Argument arg = arguments [0];
4031 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4035 // Creates nested calls tree from an array of arguments used for IL emit
4037 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4039 Arguments concat_args = new Arguments (2);
4040 Arguments add_args = new Arguments (3);
4042 concat_args.Add (left);
4043 add_args.Add (new Argument (left_etree));
4045 concat_args.Add (arguments [pos]);
4046 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4048 var methods = GetConcatMethodCandidates ();
4049 if (methods == null)
4052 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4053 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4057 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4059 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4060 if (++pos == arguments.Count)
4063 left = new Argument (new EmptyExpression (method.ReturnType));
4064 return CreateExpressionAddCall (ec, left, expr, pos);
4067 protected override Expression DoResolve (ResolveContext ec)
4072 void Append (ResolveContext rc, Expression operand)
4077 StringConstant sc = operand as StringConstant;
4079 if (arguments.Count != 0) {
4080 Argument last_argument = arguments [arguments.Count - 1];
4081 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4082 if (last_expr_constant != null) {
4083 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4089 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4091 StringConcat concat_oper = operand as StringConcat;
4092 if (concat_oper != null) {
4093 arguments.AddRange (concat_oper.arguments);
4098 arguments.Add (new Argument (operand));
4101 IList<MemberSpec> GetConcatMethodCandidates ()
4103 return MemberCache.FindMembers (type, "Concat", true);
4106 public override void Emit (EmitContext ec)
4108 var members = GetConcatMethodCandidates ();
4109 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4110 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4111 if (method != null) {
4112 var call = new CallEmitter ();
4113 call.EmitPredefined (ec, method, arguments);
4117 public override SLE.Expression MakeExpression (BuilderContext ctx)
4119 if (arguments.Count != 2)
4120 throw new NotImplementedException ("arguments.Count != 2");
4122 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4123 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4128 // User-defined conditional logical operator
4130 public class ConditionalLogicalOperator : UserOperatorCall
4132 readonly bool is_and;
4133 Expression oper_expr;
4135 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4136 : base (oper, arguments, expr_tree, loc)
4138 this.is_and = is_and;
4139 eclass = ExprClass.Unresolved;
4142 protected override Expression DoResolve (ResolveContext ec)
4144 AParametersCollection pd = oper.Parameters;
4145 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4146 ec.Report.Error (217, loc,
4147 "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",
4148 oper.GetSignatureForError ());
4152 Expression left_dup = new EmptyExpression (type);
4153 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4154 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4155 if (op_true == null || op_false == null) {
4156 ec.Report.Error (218, loc,
4157 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4158 TypeManager.CSharpName (type), oper.GetSignatureForError ());
4162 oper_expr = is_and ? op_false : op_true;
4163 eclass = ExprClass.Value;
4167 public override void Emit (EmitContext ec)
4169 Label end_target = ec.DefineLabel ();
4172 // Emit and duplicate left argument
4174 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
4175 if (right_contains_await) {
4176 arguments[0] = arguments[0].EmitToField (ec);
4177 arguments[0].Expr.Emit (ec);
4179 arguments[0].Expr.Emit (ec);
4180 ec.Emit (OpCodes.Dup);
4181 arguments.RemoveAt (0);
4184 oper_expr.EmitBranchable (ec, end_target, true);
4188 if (right_contains_await) {
4190 // Special handling when right expression contains await and left argument
4191 // could not be left on stack before logical branch
4193 Label skip_left_load = ec.DefineLabel ();
4194 ec.Emit (OpCodes.Br_S, skip_left_load);
4195 ec.MarkLabel (end_target);
4196 arguments[0].Expr.Emit (ec);
4197 ec.MarkLabel (skip_left_load);
4199 ec.MarkLabel (end_target);
4204 public class PointerArithmetic : Expression {
4205 Expression left, right;
4209 // We assume that `l' is always a pointer
4211 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4220 public override bool ContainsEmitWithAwait ()
4222 throw new NotImplementedException ();
4225 public override Expression CreateExpressionTree (ResolveContext ec)
4227 Error_PointerInsideExpressionTree (ec);
4231 protected override Expression DoResolve (ResolveContext ec)
4233 eclass = ExprClass.Variable;
4235 var pc = left.Type as PointerContainer;
4236 if (pc != null && pc.Element.Kind == MemberKind.Void) {
4237 Error_VoidPointerOperation (ec);
4244 public override void Emit (EmitContext ec)
4246 TypeSpec op_type = left.Type;
4248 // It must be either array or fixed buffer
4250 if (TypeManager.HasElementType (op_type)) {
4251 element = TypeManager.GetElementType (op_type);
4253 FieldExpr fe = left as FieldExpr;
4255 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
4260 int size = BuiltinTypeSpec.GetSize(element);
4261 TypeSpec rtype = right.Type;
4263 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4265 // handle (pointer - pointer)
4269 ec.Emit (OpCodes.Sub);
4273 ec.Emit (OpCodes.Sizeof, element);
4276 ec.Emit (OpCodes.Div);
4278 ec.Emit (OpCodes.Conv_I8);
4281 // handle + and - on (pointer op int)
4283 Constant left_const = left as Constant;
4284 if (left_const != null) {
4286 // Optimize ((T*)null) pointer operations
4288 if (left_const.IsDefaultValue) {
4289 left = EmptyExpression.Null;
4297 var right_const = right as Constant;
4298 if (right_const != null) {
4300 // Optimize 0-based arithmetic
4302 if (right_const.IsDefaultValue)
4306 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
4308 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
4310 // TODO: Should be the checks resolve context sensitive?
4311 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
4312 right = new Binary (Binary.Operator.Multiply, right, right_const, loc).Resolve (rc);
4318 switch (rtype.BuiltinType) {
4319 case BuiltinTypeSpec.Type.SByte:
4320 case BuiltinTypeSpec.Type.Byte:
4321 case BuiltinTypeSpec.Type.Short:
4322 case BuiltinTypeSpec.Type.UShort:
4323 ec.Emit (OpCodes.Conv_I);
4325 case BuiltinTypeSpec.Type.UInt:
4326 ec.Emit (OpCodes.Conv_U);
4330 if (right_const == null && size != 1){
4332 ec.Emit (OpCodes.Sizeof, element);
4335 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4336 ec.Emit (OpCodes.Conv_I8);
4338 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4341 if (left_const == null) {
4342 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
4343 ec.Emit (OpCodes.Conv_I);
4344 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4345 ec.Emit (OpCodes.Conv_U);
4347 Binary.EmitOperatorOpcode (ec, op, op_type);
4354 // A boolean-expression is an expression that yields a result
4357 public class BooleanExpression : ShimExpression
4359 public BooleanExpression (Expression expr)
4362 this.loc = expr.Location;
4365 public override Expression CreateExpressionTree (ResolveContext ec)
4367 // TODO: We should emit IsTrue (v4) instead of direct user operator
4368 // call but that would break csc compatibility
4369 return base.CreateExpressionTree (ec);
4372 protected override Expression DoResolve (ResolveContext ec)
4374 // A boolean-expression is required to be of a type
4375 // that can be implicitly converted to bool or of
4376 // a type that implements operator true
4378 expr = expr.Resolve (ec);
4382 Assign ass = expr as Assign;
4383 if (ass != null && ass.Source is Constant) {
4384 ec.Report.Warning (665, 3, loc,
4385 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4388 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
4391 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4392 Arguments args = new Arguments (1);
4393 args.Add (new Argument (expr));
4394 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
4397 type = ec.BuiltinTypes.Bool;
4398 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4399 if (converted != null)
4403 // If no implicit conversion to bool exists, try using `operator true'
4405 converted = GetOperatorTrue (ec, expr, loc);
4406 if (converted == null) {
4407 expr.Error_ValueCannotBeConverted (ec, loc, type, false);
4415 public class BooleanExpressionFalse : Unary
4417 public BooleanExpressionFalse (Expression expr)
4418 : base (Operator.LogicalNot, expr, expr.Location)
4422 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
4424 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
4429 /// Implements the ternary conditional operator (?:)
4431 public class Conditional : Expression {
4432 Expression expr, true_expr, false_expr;
4434 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
4437 this.true_expr = true_expr;
4438 this.false_expr = false_expr;
4444 public Expression Expr {
4450 public Expression TrueExpr {
4456 public Expression FalseExpr {
4464 public override bool ContainsEmitWithAwait ()
4466 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
4469 public override Expression CreateExpressionTree (ResolveContext ec)
4471 Arguments args = new Arguments (3);
4472 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4473 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4474 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4475 return CreateExpressionFactoryCall (ec, "Condition", args);
4478 protected override Expression DoResolve (ResolveContext ec)
4480 expr = expr.Resolve (ec);
4481 true_expr = true_expr.Resolve (ec);
4482 false_expr = false_expr.Resolve (ec);
4484 if (true_expr == null || false_expr == null || expr == null)
4487 eclass = ExprClass.Value;
4488 TypeSpec true_type = true_expr.Type;
4489 TypeSpec false_type = false_expr.Type;
4493 // First, if an implicit conversion exists from true_expr
4494 // to false_expr, then the result type is of type false_expr.Type
4496 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
4497 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4498 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
4500 // Check if both can convert implicitly to each other's type
4504 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic && Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
4505 ec.Report.Error (172, true_expr.Location,
4506 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
4507 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
4512 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4515 ec.Report.Error (173, true_expr.Location,
4516 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4517 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4522 // Dead code optimalization
4523 Constant c = expr as Constant;
4525 bool is_false = c.IsDefaultValue;
4526 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
4527 return ReducedExpression.Create (
4528 is_false ? false_expr : true_expr, this,
4529 false_expr is Constant && true_expr is Constant).Resolve (ec);
4535 public override void Emit (EmitContext ec)
4537 Label false_target = ec.DefineLabel ();
4538 Label end_target = ec.DefineLabel ();
4540 expr.EmitBranchable (ec, false_target, false);
4541 true_expr.Emit (ec);
4543 ec.Emit (OpCodes.Br, end_target);
4544 ec.MarkLabel (false_target);
4545 false_expr.Emit (ec);
4546 ec.MarkLabel (end_target);
4549 protected override void CloneTo (CloneContext clonectx, Expression t)
4551 Conditional target = (Conditional) t;
4553 target.expr = expr.Clone (clonectx);
4554 target.true_expr = true_expr.Clone (clonectx);
4555 target.false_expr = false_expr.Clone (clonectx);
4559 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
4561 LocalTemporary temp;
4564 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4566 public abstract bool IsLockedByStatement { get; set; }
4568 public abstract bool IsFixed { get; }
4569 public abstract bool IsRef { get; }
4570 public abstract string Name { get; }
4571 public abstract void SetHasAddressTaken ();
4574 // Variable IL data, it has to be protected to encapsulate hoisted variables
4576 protected abstract ILocalVariable Variable { get; }
4579 // Variable flow-analysis data
4581 public abstract VariableInfo VariableInfo { get; }
4584 public virtual void AddressOf (EmitContext ec, AddressOp mode)
4586 HoistedVariable hv = GetHoistedVariable (ec);
4588 hv.AddressOf (ec, mode);
4592 Variable.EmitAddressOf (ec);
4595 public override bool ContainsEmitWithAwait ()
4600 public override Expression CreateExpressionTree (ResolveContext ec)
4602 HoistedVariable hv = GetHoistedVariable (ec);
4604 return hv.CreateExpressionTree ();
4606 Arguments arg = new Arguments (1);
4607 arg.Add (new Argument (this));
4608 return CreateExpressionFactoryCall (ec, "Constant", arg);
4611 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
4613 if (IsLockedByStatement) {
4614 rc.Report.Warning (728, 2, loc,
4615 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
4622 public override void Emit (EmitContext ec)
4627 public override void EmitSideEffect (EmitContext ec)
4633 // This method is used by parameters that are references, that are
4634 // being passed as references: we only want to pass the pointer (that
4635 // is already stored in the parameter, not the address of the pointer,
4636 // and not the value of the variable).
4638 public void EmitLoad (EmitContext ec)
4643 public void Emit (EmitContext ec, bool leave_copy)
4645 HoistedVariable hv = GetHoistedVariable (ec);
4647 hv.Emit (ec, leave_copy);
4655 // If we are a reference, we loaded on the stack a pointer
4656 // Now lets load the real value
4658 ec.EmitLoadFromPtr (type);
4662 ec.Emit (OpCodes.Dup);
4665 temp = new LocalTemporary (Type);
4671 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4672 bool prepare_for_load)
4674 HoistedVariable hv = GetHoistedVariable (ec);
4676 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4680 New n_source = source as New;
4681 if (n_source != null) {
4682 if (!n_source.Emit (ec, this)) {
4686 ec.EmitLoadFromPtr (type);
4698 ec.Emit (OpCodes.Dup);
4700 temp = new LocalTemporary (Type);
4706 ec.EmitStoreFromPtr (type);
4708 Variable.EmitAssign (ec);
4716 public override Expression EmitToField (EmitContext ec)
4718 HoistedVariable hv = GetHoistedVariable (ec);
4720 return hv.EmitToField (ec);
4723 return base.EmitToField (ec);
4726 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4728 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4731 public HoistedVariable GetHoistedVariable (EmitContext ec)
4733 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4736 public override string GetSignatureForError ()
4741 public bool IsHoisted {
4742 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4747 // Resolved reference to a local variable
4749 public class LocalVariableReference : VariableReference
4751 public LocalVariable local_info;
4753 public LocalVariableReference (LocalVariable li, Location l)
4755 this.local_info = li;
4759 public override VariableInfo VariableInfo {
4760 get { return local_info.VariableInfo; }
4763 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4765 return local_info.HoistedVariant;
4771 // A local variable is always fixed
4773 public override bool IsFixed {
4779 public override bool IsLockedByStatement {
4781 return local_info.IsLocked;
4784 local_info.IsLocked = value;
4788 public override bool IsRef {
4789 get { return false; }
4792 public override string Name {
4793 get { return local_info.Name; }
4798 public bool VerifyAssigned (ResolveContext ec)
4800 VariableInfo variable_info = local_info.VariableInfo;
4801 return variable_info == null || variable_info.IsAssigned (ec, loc);
4804 public override void SetHasAddressTaken ()
4806 local_info.AddressTaken = true;
4809 void DoResolveBase (ResolveContext ec)
4811 VerifyAssigned (ec);
4814 // If we are referencing a variable from the external block
4815 // flag it for capturing
4817 if (ec.MustCaptureVariable (local_info)) {
4818 if (local_info.AddressTaken) {
4819 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4820 } else if (local_info.IsFixed) {
4821 ec.Report.Error (1764, loc,
4822 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
4823 GetSignatureForError ());
4826 if (ec.IsVariableCapturingRequired) {
4827 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4828 storey.CaptureLocalVariable (ec, local_info);
4832 eclass = ExprClass.Variable;
4833 type = local_info.Type;
4836 protected override Expression DoResolve (ResolveContext ec)
4838 local_info.SetIsUsed ();
4844 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4847 if (right_side == EmptyExpression.OutAccess)
4848 local_info.SetIsUsed ();
4850 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
4853 if (right_side == EmptyExpression.OutAccess) {
4854 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4855 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4856 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4857 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4858 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4859 } else if (right_side == EmptyExpression.UnaryAddress) {
4860 code = 459; msg = "Cannot take the address of {1} `{0}'";
4862 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4864 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4865 } else if (VariableInfo != null) {
4866 VariableInfo.SetAssigned (ec);
4871 return base.DoResolveLValue (ec, right_side);
4874 public override int GetHashCode ()
4876 return local_info.GetHashCode ();
4879 public override bool Equals (object obj)
4881 LocalVariableReference lvr = obj as LocalVariableReference;
4885 return local_info == lvr.local_info;
4888 protected override ILocalVariable Variable {
4889 get { return local_info; }
4892 public override string ToString ()
4894 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4897 protected override void CloneTo (CloneContext clonectx, Expression t)
4904 /// This represents a reference to a parameter in the intermediate
4907 public class ParameterReference : VariableReference
4909 protected ParametersBlock.ParameterInfo pi;
4911 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
4919 public override bool IsLockedByStatement {
4924 pi.IsLocked = value;
4928 public override bool IsRef {
4929 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4932 bool HasOutModifier {
4933 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4936 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4938 return pi.Parameter.HoistedVariant;
4942 // A ref or out parameter is classified as a moveable variable, even
4943 // if the argument given for the parameter is a fixed variable
4945 public override bool IsFixed {
4946 get { return !IsRef; }
4949 public override string Name {
4950 get { return Parameter.Name; }
4953 public Parameter Parameter {
4954 get { return pi.Parameter; }
4957 public override VariableInfo VariableInfo {
4958 get { return pi.VariableInfo; }
4961 protected override ILocalVariable Variable {
4962 get { return Parameter; }
4967 public bool IsAssigned (ResolveContext ec, Location loc)
4969 // HACK: Variables are not captured in probing mode
4970 if (ec.IsInProbingMode)
4973 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4976 ec.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4980 public override void SetHasAddressTaken ()
4982 Parameter.HasAddressTaken = true;
4985 void SetAssigned (ResolveContext ec)
4987 if (HasOutModifier && ec.DoFlowAnalysis)
4988 ec.CurrentBranching.SetAssigned (VariableInfo);
4991 bool DoResolveBase (ResolveContext ec)
4993 if (eclass != ExprClass.Unresolved)
4996 type = pi.ParameterType;
4997 eclass = ExprClass.Variable;
5000 // If we are referencing a parameter from the external block
5001 // flag it for capturing
5003 if (ec.MustCaptureVariable (pi)) {
5004 if (Parameter.HasAddressTaken)
5005 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5008 ec.Report.Error (1628, loc,
5009 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5010 Name, ec.CurrentAnonymousMethod.ContainerType);
5013 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5014 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5015 storey.CaptureParameter (ec, this);
5022 public override int GetHashCode ()
5024 return Name.GetHashCode ();
5027 public override bool Equals (object obj)
5029 ParameterReference pr = obj as ParameterReference;
5033 return Name == pr.Name;
5036 public override void AddressOf (EmitContext ec, AddressOp mode)
5039 // ParameterReferences might already be a reference
5046 base.AddressOf (ec, mode);
5049 protected override void CloneTo (CloneContext clonectx, Expression target)
5055 public override Expression CreateExpressionTree (ResolveContext ec)
5057 HoistedVariable hv = GetHoistedVariable (ec);
5059 return hv.CreateExpressionTree ();
5061 return Parameter.ExpressionTreeVariableReference ();
5065 // Notice that for ref/out parameters, the type exposed is not the
5066 // same type exposed externally.
5069 // externally we expose "int&"
5070 // here we expose "int".
5072 // We record this in "is_ref". This means that the type system can treat
5073 // the type as it is expected, but when we generate the code, we generate
5074 // the alternate kind of code.
5076 protected override Expression DoResolve (ResolveContext ec)
5078 if (!DoResolveBase (ec))
5081 // HACK: Variables are not captured in probing mode
5082 if (ec.IsInProbingMode)
5085 if (HasOutModifier && ec.DoFlowAnalysis &&
5086 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
5092 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5094 if (!DoResolveBase (ec))
5098 return base.DoResolveLValue (ec, right_side);
5103 /// Invocation of methods or delegates.
5105 public class Invocation : ExpressionStatement
5107 protected Arguments arguments;
5108 protected Expression expr;
5109 protected MethodGroupExpr mg;
5111 public Invocation (Expression expr, Arguments arguments)
5114 this.arguments = arguments;
5116 loc = expr.Location;
5120 public Arguments Arguments {
5126 public Expression Expression {
5133 protected override void CloneTo (CloneContext clonectx, Expression t)
5135 Invocation target = (Invocation) t;
5137 if (arguments != null)
5138 target.arguments = arguments.Clone (clonectx);
5140 target.expr = expr.Clone (clonectx);
5143 public override bool ContainsEmitWithAwait ()
5145 if (arguments != null && arguments.ContainsEmitWithAwait ())
5148 return mg.ContainsEmitWithAwait ();
5151 public override Expression CreateExpressionTree (ResolveContext ec)
5153 Expression instance = mg.IsInstance ?
5154 mg.InstanceExpression.CreateExpressionTree (ec) :
5155 new NullLiteral (loc);
5157 var args = Arguments.CreateForExpressionTree (ec, arguments,
5159 mg.CreateExpressionTree (ec));
5161 return CreateExpressionFactoryCall (ec, "Call", args);
5164 protected override Expression DoResolve (ResolveContext ec)
5166 Expression member_expr;
5167 var atn = expr as ATypeNameExpression;
5169 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
5170 if (member_expr != null)
5171 member_expr = member_expr.Resolve (ec);
5173 member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5176 if (member_expr == null)
5180 // Next, evaluate all the expressions in the argument list
5182 bool dynamic_arg = false;
5183 if (arguments != null)
5184 arguments.Resolve (ec, out dynamic_arg);
5186 TypeSpec expr_type = member_expr.Type;
5187 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5188 return DoResolveDynamic (ec, member_expr);
5190 mg = member_expr as MethodGroupExpr;
5191 Expression invoke = null;
5194 if (expr_type != null && TypeManager.IsDelegateType (expr_type)) {
5195 invoke = new DelegateInvocation (member_expr, arguments, loc);
5196 invoke = invoke.Resolve (ec);
5197 if (invoke == null || !dynamic_arg)
5200 if (member_expr is RuntimeValueExpression) {
5201 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
5202 member_expr.Type.GetSignatureForError ()); ;
5206 MemberExpr me = member_expr as MemberExpr;
5208 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5212 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
5213 member_expr.GetSignatureForError ());
5218 if (invoke == null) {
5219 mg = DoResolveOverload (ec);
5225 return DoResolveDynamic (ec, member_expr);
5227 var method = mg.BestCandidate;
5228 type = mg.BestCandidateReturnType;
5230 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
5232 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5234 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5238 IsSpecialMethodInvocation (ec, method, loc);
5240 eclass = ExprClass.Value;
5244 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
5247 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
5249 args = dmb.Arguments;
5250 if (arguments != null)
5251 args.AddRange (arguments);
5252 } else if (mg == null) {
5253 if (arguments == null)
5254 args = new Arguments (1);
5258 args.Insert (0, new Argument (memberExpr));
5262 ec.Report.Error (1971, loc,
5263 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
5268 if (arguments == null)
5269 args = new Arguments (1);
5273 MemberAccess ma = expr as MemberAccess;
5275 var left_type = ma.LeftExpression as TypeExpr;
5276 if (left_type != null) {
5277 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5280 // Any value type has to be pass as by-ref to get back the same
5281 // instance on which the member was called
5283 var mod = TypeSpec.IsValueType (ma.LeftExpression.Type) ? Argument.AType.Ref : Argument.AType.None;
5284 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
5286 } else { // is SimpleName
5288 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5290 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5295 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5298 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5300 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
5303 static MetaType[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
5305 AParametersCollection pd = mb.Parameters;
5307 Argument a = arguments[pd.Count - 1];
5308 Arglist list = (Arglist) a.Expr;
5310 return list.ArgumentTypes;
5314 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
5315 // or the type dynamic, then the member is invocable
5317 public static bool IsMemberInvocable (MemberSpec member)
5319 switch (member.Kind) {
5320 case MemberKind.Event:
5322 case MemberKind.Field:
5323 case MemberKind.Property:
5324 var m = member as IInterfaceMemberSpec;
5325 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
5331 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
5333 if (!method.IsReservedMethod)
5336 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
5339 ec.Report.SymbolRelatedToPreviousError (method);
5340 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5341 method.GetSignatureForError ());
5346 public override void Emit (EmitContext ec)
5348 mg.EmitCall (ec, arguments);
5351 public override void EmitStatement (EmitContext ec)
5356 // Pop the return value if there is one
5358 if (type.Kind != MemberKind.Void)
5359 ec.Emit (OpCodes.Pop);
5362 public override SLE.Expression MakeExpression (BuilderContext ctx)
5364 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
5367 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
5370 throw new NotSupportedException ();
5372 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5373 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
5379 // Implements simple new expression
5381 public class New : ExpressionStatement, IMemoryLocation
5383 protected Arguments arguments;
5386 // During bootstrap, it contains the RequestedType,
5387 // but if `type' is not null, it *might* contain a NewDelegate
5388 // (because of field multi-initialization)
5390 protected Expression RequestedType;
5392 protected MethodSpec method;
5394 public New (Expression requested_type, Arguments arguments, Location l)
5396 RequestedType = requested_type;
5397 this.arguments = arguments;
5402 public Arguments Arguments {
5409 // Returns true for resolved `new S()'
5411 public bool IsDefaultStruct {
5413 return arguments == null && type.IsStruct && GetType () == typeof (New);
5420 /// Converts complex core type syntax like 'new int ()' to simple constant
5422 public static Constant Constantify (TypeSpec t, Location loc)
5424 switch (t.BuiltinType) {
5425 case BuiltinTypeSpec.Type.Int:
5426 return new IntConstant (t, 0, loc);
5427 case BuiltinTypeSpec.Type.UInt:
5428 return new UIntConstant (t, 0, loc);
5429 case BuiltinTypeSpec.Type.Long:
5430 return new LongConstant (t, 0, loc);
5431 case BuiltinTypeSpec.Type.ULong:
5432 return new ULongConstant (t, 0, loc);
5433 case BuiltinTypeSpec.Type.Float:
5434 return new FloatConstant (t, 0, loc);
5435 case BuiltinTypeSpec.Type.Double:
5436 return new DoubleConstant (t, 0, loc);
5437 case BuiltinTypeSpec.Type.Short:
5438 return new ShortConstant (t, 0, loc);
5439 case BuiltinTypeSpec.Type.UShort:
5440 return new UShortConstant (t, 0, loc);
5441 case BuiltinTypeSpec.Type.SByte:
5442 return new SByteConstant (t, 0, loc);
5443 case BuiltinTypeSpec.Type.Byte:
5444 return new ByteConstant (t, 0, loc);
5445 case BuiltinTypeSpec.Type.Char:
5446 return new CharConstant (t, '\0', loc);
5447 case BuiltinTypeSpec.Type.Bool:
5448 return new BoolConstant (t, false, loc);
5449 case BuiltinTypeSpec.Type.Decimal:
5450 return new DecimalConstant (t, 0, loc);
5454 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
5456 if (t.IsNullableType)
5457 return Nullable.LiftedNull.Create (t, loc);
5462 public override bool ContainsEmitWithAwait ()
5464 return arguments != null && arguments.ContainsEmitWithAwait ();
5468 // Checks whether the type is an interface that has the
5469 // [ComImport, CoClass] attributes and must be treated
5472 public Expression CheckComImport (ResolveContext ec)
5474 if (!type.IsInterface)
5478 // Turn the call into:
5479 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5481 var real_class = type.MemberDefinition.GetAttributeCoClass ();
5482 if (real_class == null)
5485 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
5486 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5487 return cast.Resolve (ec);
5490 public override Expression CreateExpressionTree (ResolveContext ec)
5493 if (method == null) {
5494 args = new Arguments (1);
5495 args.Add (new Argument (new TypeOf (type, loc)));
5497 args = Arguments.CreateForExpressionTree (ec,
5498 arguments, new TypeOfMethod (method, loc));
5501 return CreateExpressionFactoryCall (ec, "New", args);
5504 protected override Expression DoResolve (ResolveContext ec)
5506 type = RequestedType.ResolveAsType (ec);
5510 eclass = ExprClass.Value;
5512 if (type.IsPointer) {
5513 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5514 TypeManager.CSharpName (type));
5518 if (arguments == null) {
5519 Constant c = Constantify (type, RequestedType.Location);
5521 return ReducedExpression.Create (c, this);
5524 if (TypeManager.IsDelegateType (type)) {
5525 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
5528 var tparam = type as TypeParameterSpec;
5529 if (tparam != null) {
5531 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
5532 // where type parameter constraint is inflated to struct
5534 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !tparam.BaseType.IsStruct) {
5535 ec.Report.Error (304, loc,
5536 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
5537 TypeManager.CSharpName (type));
5540 if ((arguments != null) && (arguments.Count != 0)) {
5541 ec.Report.Error (417, loc,
5542 "`{0}': cannot provide arguments when creating an instance of a variable type",
5543 TypeManager.CSharpName (type));
5549 if (type.IsStatic) {
5550 ec.Report.SymbolRelatedToPreviousError (type);
5551 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5555 if (type.IsInterface || type.IsAbstract){
5556 if (!TypeManager.IsGenericType (type)) {
5557 RequestedType = CheckComImport (ec);
5558 if (RequestedType != null)
5559 return RequestedType;
5562 ec.Report.SymbolRelatedToPreviousError (type);
5563 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5568 // Any struct always defines parameterless constructor
5570 if (type.IsStruct && arguments == null)
5574 if (arguments != null) {
5575 arguments.Resolve (ec, out dynamic);
5580 method = ConstructorLookup (ec, type, ref arguments, loc);
5583 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5584 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
5590 bool DoEmitTypeParameter (EmitContext ec)
5592 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
5596 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
5597 var tparam = (TypeParameterSpec) type;
5599 if (tparam.IsReferenceType) {
5600 ec.Emit (OpCodes.Call, ctor_factory);
5604 // Allow DoEmit() to be called multiple times.
5605 // We need to create a new LocalTemporary each time since
5606 // you can't share LocalBuilders among ILGeneators.
5607 LocalTemporary temp = new LocalTemporary (type);
5609 Label label_activator = ec.DefineLabel ();
5610 Label label_end = ec.DefineLabel ();
5612 temp.AddressOf (ec, AddressOp.Store);
5613 ec.Emit (OpCodes.Initobj, type);
5616 ec.Emit (OpCodes.Box, type);
5617 ec.Emit (OpCodes.Brfalse, label_activator);
5619 temp.AddressOf (ec, AddressOp.Store);
5620 ec.Emit (OpCodes.Initobj, type);
5623 ec.Emit (OpCodes.Br_S, label_end);
5625 ec.MarkLabel (label_activator);
5627 ec.Emit (OpCodes.Call, ctor_factory);
5628 ec.MarkLabel (label_end);
5633 // This Emit can be invoked in two contexts:
5634 // * As a mechanism that will leave a value on the stack (new object)
5635 // * As one that wont (init struct)
5637 // If we are dealing with a ValueType, we have a few
5638 // situations to deal with:
5640 // * The target is a ValueType, and we have been provided
5641 // the instance (this is easy, we are being assigned).
5643 // * The target of New is being passed as an argument,
5644 // to a boxing operation or a function that takes a
5647 // In this case, we need to create a temporary variable
5648 // that is the argument of New.
5650 // Returns whether a value is left on the stack
5652 // *** Implementation note ***
5654 // To benefit from this optimization, each assignable expression
5655 // has to manually cast to New and call this Emit.
5657 // TODO: It's worth to implement it for arrays and fields
5659 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5661 bool is_value_type = TypeSpec.IsValueType (type);
5662 VariableReference vr = target as VariableReference;
5664 if (target != null && is_value_type && (vr != null || method == null)) {
5665 target.AddressOf (ec, AddressOp.Store);
5666 } else if (vr != null && vr.IsRef) {
5670 if (arguments != null) {
5671 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
5672 arguments = arguments.Emit (ec, false, true);
5674 arguments.Emit (ec);
5677 if (is_value_type) {
5678 if (method == null) {
5679 ec.Emit (OpCodes.Initobj, type);
5684 ec.Emit (OpCodes.Call, method);
5689 if (type is TypeParameterSpec)
5690 return DoEmitTypeParameter (ec);
5692 ec.Emit (OpCodes.Newobj, method);
5696 public override void Emit (EmitContext ec)
5698 LocalTemporary v = null;
5699 if (method == null && TypeSpec.IsValueType (type)) {
5700 // TODO: Use temporary variable from pool
5701 v = new LocalTemporary (type);
5708 public override void EmitStatement (EmitContext ec)
5710 LocalTemporary v = null;
5711 if (method == null && TypeSpec.IsValueType (type)) {
5712 // TODO: Use temporary variable from pool
5713 v = new LocalTemporary (type);
5717 ec.Emit (OpCodes.Pop);
5720 public void AddressOf (EmitContext ec, AddressOp mode)
5722 EmitAddressOf (ec, mode);
5725 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5727 LocalTemporary value_target = new LocalTemporary (type);
5729 if (type is TypeParameterSpec) {
5730 DoEmitTypeParameter (ec);
5731 value_target.Store (ec);
5732 value_target.AddressOf (ec, mode);
5733 return value_target;
5736 value_target.AddressOf (ec, AddressOp.Store);
5738 if (method == null) {
5739 ec.Emit (OpCodes.Initobj, type);
5741 if (arguments != null)
5742 arguments.Emit (ec);
5744 ec.Emit (OpCodes.Call, method);
5747 value_target.AddressOf (ec, mode);
5748 return value_target;
5751 protected override void CloneTo (CloneContext clonectx, Expression t)
5753 New target = (New) t;
5755 target.RequestedType = RequestedType.Clone (clonectx);
5756 if (arguments != null){
5757 target.arguments = arguments.Clone (clonectx);
5761 public override SLE.Expression MakeExpression (BuilderContext ctx)
5764 return base.MakeExpression (ctx);
5766 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
5772 // Array initializer expression, the expression is allowed in
5773 // variable or field initialization only which makes it tricky as
5774 // the type has to be infered based on the context either from field
5775 // type or variable type (think of multiple declarators)
5777 public class ArrayInitializer : Expression
5779 List<Expression> elements;
5780 BlockVariableDeclaration variable;
5782 public ArrayInitializer (List<Expression> init, Location loc)
5788 public ArrayInitializer (int count, Location loc)
5789 : this (new List<Expression> (count), loc)
5793 public ArrayInitializer (Location loc)
5801 get { return elements.Count; }
5804 public Expression this [int index] {
5806 return elements [index];
5810 public BlockVariableDeclaration VariableDeclaration {
5821 public void Add (Expression expr)
5823 elements.Add (expr);
5826 public override bool ContainsEmitWithAwait ()
5828 throw new NotSupportedException ();
5831 public override Expression CreateExpressionTree (ResolveContext ec)
5833 throw new NotSupportedException ("ET");
5836 protected override void CloneTo (CloneContext clonectx, Expression t)
5838 var target = (ArrayInitializer) t;
5840 target.elements = new List<Expression> (elements.Count);
5841 foreach (var element in elements)
5842 target.elements.Add (element.Clone (clonectx));
5845 protected override Expression DoResolve (ResolveContext rc)
5847 var current_field = rc.CurrentMemberDefinition as FieldBase;
5848 TypeExpression type;
5849 if (current_field != null && rc.CurrentAnonymousMethod == null) {
5850 type = new TypeExpression (current_field.MemberType, current_field.Location);
5851 } else if (variable != null) {
5852 if (variable.TypeExpression is VarExpr) {
5853 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5854 return EmptyExpression.Null;
5857 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
5859 throw new NotImplementedException ("Unexpected array initializer context");
5862 return new ArrayCreation (type, this).Resolve (rc);
5865 public override void Emit (EmitContext ec)
5867 throw new InternalErrorException ("Missing Resolve call");
5872 /// 14.5.10.2: Represents an array creation expression.
5876 /// There are two possible scenarios here: one is an array creation
5877 /// expression that specifies the dimensions and optionally the
5878 /// initialization data and the other which does not need dimensions
5879 /// specified but where initialization data is mandatory.
5881 public class ArrayCreation : Expression
5883 FullNamedExpression requested_base_type;
5884 ArrayInitializer initializers;
5887 // The list of Argument types.
5888 // This is used to construct the `newarray' or constructor signature
5890 protected List<Expression> arguments;
5892 protected TypeSpec array_element_type;
5893 int num_arguments = 0;
5894 protected int dimensions;
5895 protected readonly ComposedTypeSpecifier rank;
5896 Expression first_emit;
5897 LocalTemporary first_emit_temp;
5899 protected List<Expression> array_data;
5901 Dictionary<int, int> bounds;
5903 // The number of constants in array initializers
5904 int const_initializers_count;
5905 bool only_constant_initializers;
5907 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
5908 : this (requested_base_type, rank, initializers, l)
5910 arguments = new List<Expression> (exprs);
5911 num_arguments = arguments.Count;
5915 // For expressions like int[] foo = new int[] { 1, 2, 3 };
5917 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
5919 this.requested_base_type = requested_base_type;
5921 this.initializers = initializers;
5925 num_arguments = rank.Dimension;
5929 // For compiler generated single dimensional arrays only
5931 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
5932 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
5937 // For expressions like int[] foo = { 1, 2, 3 };
5939 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
5940 : this (requested_base_type, null, initializers, initializers.Location)
5944 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
5946 if (initializers != null && bounds == null) {
5948 // We use this to store all the date values in the order in which we
5949 // will need to store them in the byte blob later
5951 array_data = new List<Expression> ();
5952 bounds = new Dictionary<int, int> ();
5955 if (specified_dims) {
5956 Expression a = arguments [idx];
5961 a = ConvertExpressionToArrayIndex (ec, a);
5967 if (initializers != null) {
5968 Constant c = a as Constant;
5969 if (c == null && a is ArrayIndexCast)
5970 c = ((ArrayIndexCast) a).Child as Constant;
5973 ec.Report.Error (150, a.Location, "A constant value is expected");
5979 value = System.Convert.ToInt32 (c.GetValue ());
5981 ec.Report.Error (150, a.Location, "A constant value is expected");
5985 // TODO: probe.Count does not fit ulong in
5986 if (value != probe.Count) {
5987 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
5991 bounds[idx] = value;
5995 if (initializers == null)
5998 for (int i = 0; i < probe.Count; ++i) {
6000 if (o is ArrayInitializer) {
6001 var sub_probe = o as ArrayInitializer;
6002 if (idx + 1 >= dimensions){
6003 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6007 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6010 } else if (child_bounds > 1) {
6011 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6013 Expression element = ResolveArrayElement (ec, o);
6014 if (element == null)
6017 // Initializers with the default values can be ignored
6018 Constant c = element as Constant;
6020 if (!c.IsDefaultInitializer (array_element_type)) {
6021 ++const_initializers_count;
6024 only_constant_initializers = false;
6027 array_data.Add (element);
6034 public override bool ContainsEmitWithAwait ()
6036 foreach (var arg in arguments) {
6037 if (arg.ContainsEmitWithAwait ())
6041 return InitializersContainAwait ();
6044 public override Expression CreateExpressionTree (ResolveContext ec)
6048 if (array_data == null) {
6049 args = new Arguments (arguments.Count + 1);
6050 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6051 foreach (Expression a in arguments)
6052 args.Add (new Argument (a.CreateExpressionTree (ec)));
6054 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6057 if (dimensions > 1) {
6058 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6062 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6063 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6064 if (array_data != null) {
6065 for (int i = 0; i < array_data.Count; ++i) {
6066 Expression e = array_data [i];
6067 args.Add (new Argument (e.CreateExpressionTree (ec)));
6071 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6074 void UpdateIndices (ResolveContext rc)
6077 for (var probe = initializers; probe != null;) {
6078 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
6080 bounds[i++] = probe.Count;
6082 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
6083 probe = (ArrayInitializer) probe[0];
6084 } else if (dimensions > i) {
6092 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
6094 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
6097 bool InitializersContainAwait ()
6099 if (array_data == null)
6102 foreach (var expr in array_data) {
6103 if (expr.ContainsEmitWithAwait ())
6110 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
6112 element = element.Resolve (ec);
6113 if (element == null)
6116 if (element is CompoundAssign.TargetExpression) {
6117 if (first_emit != null)
6118 throw new InternalErrorException ("Can only handle one mutator at a time");
6119 first_emit = element;
6120 element = first_emit_temp = new LocalTemporary (element.Type);
6123 return Convert.ImplicitConversionRequired (
6124 ec, element, array_element_type, loc);
6127 protected bool ResolveInitializers (ResolveContext ec)
6129 only_constant_initializers = true;
6131 if (arguments != null) {
6133 for (int i = 0; i < arguments.Count; ++i) {
6134 res &= CheckIndices (ec, initializers, i, true, dimensions);
6135 if (initializers != null)
6142 arguments = new List<Expression> ();
6144 if (!CheckIndices (ec, initializers, 0, false, dimensions))
6153 // Resolved the type of the array
6155 bool ResolveArrayType (ResolveContext ec)
6160 FullNamedExpression array_type_expr;
6161 if (num_arguments > 0) {
6162 array_type_expr = new ComposedCast (requested_base_type, rank);
6164 array_type_expr = requested_base_type;
6167 type = array_type_expr.ResolveAsType (ec);
6168 if (array_type_expr == null)
6171 var ac = type as ArrayContainer;
6173 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6177 array_element_type = ac.Element;
6178 dimensions = ac.Rank;
6183 protected override Expression DoResolve (ResolveContext ec)
6188 if (!ResolveArrayType (ec))
6192 // validate the initializers and fill in any missing bits
6194 if (!ResolveInitializers (ec))
6197 eclass = ExprClass.Value;
6201 byte [] MakeByteBlob ()
6206 int count = array_data.Count;
6208 TypeSpec element_type = array_element_type;
6209 if (TypeManager.IsEnumType (element_type))
6210 element_type = EnumSpec.GetUnderlyingType (element_type);
6212 factor = BuiltinTypeSpec.GetSize (element_type);
6214 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6216 data = new byte [(count * factor + 3) & ~3];
6219 for (int i = 0; i < count; ++i) {
6220 var c = array_data[i] as Constant;
6226 object v = c.GetValue ();
6228 switch (element_type.BuiltinType) {
6229 case BuiltinTypeSpec.Type.Long:
6230 long lval = (long) v;
6232 for (int j = 0; j < factor; ++j) {
6233 data[idx + j] = (byte) (lval & 0xFF);
6237 case BuiltinTypeSpec.Type.ULong:
6238 ulong ulval = (ulong) v;
6240 for (int j = 0; j < factor; ++j) {
6241 data[idx + j] = (byte) (ulval & 0xFF);
6242 ulval = (ulval >> 8);
6245 case BuiltinTypeSpec.Type.Float:
6246 element = BitConverter.GetBytes ((float) v);
6248 for (int j = 0; j < factor; ++j)
6249 data[idx + j] = element[j];
6250 if (!BitConverter.IsLittleEndian)
6251 System.Array.Reverse (data, idx, 4);
6253 case BuiltinTypeSpec.Type.Double:
6254 element = BitConverter.GetBytes ((double) v);
6256 for (int j = 0; j < factor; ++j)
6257 data[idx + j] = element[j];
6259 // FIXME: Handle the ARM float format.
6260 if (!BitConverter.IsLittleEndian)
6261 System.Array.Reverse (data, idx, 8);
6263 case BuiltinTypeSpec.Type.Char:
6264 int chval = (int) ((char) v);
6266 data[idx] = (byte) (chval & 0xff);
6267 data[idx + 1] = (byte) (chval >> 8);
6269 case BuiltinTypeSpec.Type.Short:
6270 int sval = (int) ((short) v);
6272 data[idx] = (byte) (sval & 0xff);
6273 data[idx + 1] = (byte) (sval >> 8);
6275 case BuiltinTypeSpec.Type.UShort:
6276 int usval = (int) ((ushort) v);
6278 data[idx] = (byte) (usval & 0xff);
6279 data[idx + 1] = (byte) (usval >> 8);
6281 case BuiltinTypeSpec.Type.Int:
6284 data[idx] = (byte) (val & 0xff);
6285 data[idx + 1] = (byte) ((val >> 8) & 0xff);
6286 data[idx + 2] = (byte) ((val >> 16) & 0xff);
6287 data[idx + 3] = (byte) (val >> 24);
6289 case BuiltinTypeSpec.Type.UInt:
6290 uint uval = (uint) v;
6292 data[idx] = (byte) (uval & 0xff);
6293 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
6294 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
6295 data[idx + 3] = (byte) (uval >> 24);
6297 case BuiltinTypeSpec.Type.SByte:
6298 data[idx] = (byte) (sbyte) v;
6300 case BuiltinTypeSpec.Type.Byte:
6301 data[idx] = (byte) v;
6303 case BuiltinTypeSpec.Type.Bool:
6304 data[idx] = (byte) ((bool) v ? 1 : 0);
6306 case BuiltinTypeSpec.Type.Decimal:
6307 int[] bits = Decimal.GetBits ((decimal) v);
6310 // FIXME: For some reason, this doesn't work on the MS runtime.
6311 int[] nbits = new int[4];
6317 for (int j = 0; j < 4; j++) {
6318 data[p++] = (byte) (nbits[j] & 0xff);
6319 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
6320 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
6321 data[p++] = (byte) (nbits[j] >> 24);
6325 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6335 public override SLE.Expression MakeExpression (BuilderContext ctx)
6338 return base.MakeExpression (ctx);
6340 var initializers = new SLE.Expression [array_data.Count];
6341 for (var i = 0; i < initializers.Length; i++) {
6342 if (array_data [i] == null)
6343 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
6345 initializers [i] = array_data [i].MakeExpression (ctx);
6348 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
6354 // Emits the initializers for the array
6356 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
6358 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
6363 // First, the static data
6365 byte [] data = MakeByteBlob ();
6366 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
6368 if (stackArray == null) {
6369 ec.Emit (OpCodes.Dup);
6371 stackArray.Emit (ec);
6374 ec.Emit (OpCodes.Ldtoken, fb);
6375 ec.Emit (OpCodes.Call, m);
6380 // Emits pieces of the array that can not be computed at compile
6381 // time (variables and string locations).
6383 // This always expect the top value on the stack to be the array
6385 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
6387 int dims = bounds.Count;
6388 var current_pos = new int [dims];
6390 for (int i = 0; i < array_data.Count; i++){
6392 Expression e = array_data [i];
6393 var c = e as Constant;
6395 // Constant can be initialized via StaticInitializer
6396 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
6400 if (stackArray != null) {
6401 if (e.ContainsEmitWithAwait ()) {
6402 e = e.EmitToField (ec);
6405 stackArray.Emit (ec);
6407 ec.Emit (OpCodes.Dup);
6410 for (int idx = 0; idx < dims; idx++)
6411 ec.EmitInt (current_pos [idx]);
6414 // If we are dealing with a struct, get the
6415 // address of it, so we can store it.
6417 if (dims == 1 && etype.IsStruct) {
6418 switch (etype.BuiltinType) {
6419 case BuiltinTypeSpec.Type.Byte:
6420 case BuiltinTypeSpec.Type.SByte:
6421 case BuiltinTypeSpec.Type.Bool:
6422 case BuiltinTypeSpec.Type.Short:
6423 case BuiltinTypeSpec.Type.UShort:
6424 case BuiltinTypeSpec.Type.Char:
6425 case BuiltinTypeSpec.Type.Int:
6426 case BuiltinTypeSpec.Type.UInt:
6427 case BuiltinTypeSpec.Type.Long:
6428 case BuiltinTypeSpec.Type.ULong:
6429 case BuiltinTypeSpec.Type.Float:
6430 case BuiltinTypeSpec.Type.Double:
6433 ec.Emit (OpCodes.Ldelema, etype);
6440 ec.EmitArrayStore ((ArrayContainer) type);
6446 for (int j = dims - 1; j >= 0; j--){
6448 if (current_pos [j] < bounds [j])
6450 current_pos [j] = 0;
6455 public override void Emit (EmitContext ec)
6457 if (first_emit != null) {
6458 first_emit.Emit (ec);
6459 first_emit_temp.Store (ec);
6462 FieldExpr await_stack_field;
6463 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
6464 await_stack_field = ec.GetTemporaryField (type);
6467 await_stack_field = null;
6470 EmitExpressionsList (ec, arguments);
6472 ec.EmitArrayNew ((ArrayContainer) type);
6474 if (initializers == null)
6477 if (await_stack_field != null)
6478 await_stack_field.EmitAssignFromStack (ec);
6482 // Emit static initializer for arrays which contain more than 2 items and
6483 // the static initializer will initialize at least 25% of array values or there
6484 // is more than 10 items to be initialized
6486 // NOTE: const_initializers_count does not contain default constant values.
6488 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
6489 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
6490 EmitStaticInitializers (ec, await_stack_field);
6492 if (!only_constant_initializers)
6493 EmitDynamicInitializers (ec, false, await_stack_field);
6497 EmitDynamicInitializers (ec, true, await_stack_field);
6500 if (await_stack_field != null)
6501 await_stack_field.Emit (ec);
6503 if (first_emit_temp != null)
6504 first_emit_temp.Release (ec);
6507 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
6509 // no multi dimensional or jagged arrays
6510 if (arguments.Count != 1 || array_element_type.IsArray) {
6511 base.EncodeAttributeValue (rc, enc, targetType);
6515 // No array covariance, except for array -> object
6516 if (type != targetType) {
6517 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
6518 base.EncodeAttributeValue (rc, enc, targetType);
6522 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
6523 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
6528 // Single dimensional array of 0 size
6529 if (array_data == null) {
6530 IntConstant ic = arguments[0] as IntConstant;
6531 if (ic == null || !ic.IsDefaultValue) {
6532 base.EncodeAttributeValue (rc, enc, targetType);
6540 enc.Encode (array_data.Count);
6541 foreach (var element in array_data) {
6542 element.EncodeAttributeValue (rc, enc, array_element_type);
6546 protected override void CloneTo (CloneContext clonectx, Expression t)
6548 ArrayCreation target = (ArrayCreation) t;
6550 if (requested_base_type != null)
6551 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6553 if (arguments != null){
6554 target.arguments = new List<Expression> (arguments.Count);
6555 foreach (Expression e in arguments)
6556 target.arguments.Add (e.Clone (clonectx));
6559 if (initializers != null)
6560 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
6565 // Represents an implicitly typed array epxression
6567 class ImplicitlyTypedArrayCreation : ArrayCreation
6569 sealed class InferenceContext : TypeInferenceContext
6571 class ExpressionBoundInfo : BoundInfo
6573 readonly Expression expr;
6575 public ExpressionBoundInfo (Expression expr)
6576 : base (expr.Type, BoundKind.Lower)
6581 public override bool Equals (BoundInfo other)
6583 // We are using expression not type for conversion check
6584 // no optimization based on types is possible
6588 public override Expression GetTypeExpression ()
6594 public void AddExpression (Expression expr)
6596 AddToBounds (new ExpressionBoundInfo (expr), 0);
6600 InferenceContext best_type_inference;
6602 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6603 : base (null, rank, initializers, loc)
6607 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
6608 : base (null, initializers, loc)
6612 protected override Expression DoResolve (ResolveContext ec)
6617 dimensions = rank.Dimension;
6619 best_type_inference = new InferenceContext ();
6621 if (!ResolveInitializers (ec))
6624 best_type_inference.FixAllTypes (ec);
6625 array_element_type = best_type_inference.InferredTypeArguments[0];
6626 best_type_inference = null;
6628 if (array_element_type == null || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
6629 arguments.Count != rank.Dimension) {
6630 ec.Report.Error (826, loc,
6631 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6636 // At this point we found common base type for all initializer elements
6637 // but we have to be sure that all static initializer elements are of
6640 UnifyInitializerElement (ec);
6642 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
6643 eclass = ExprClass.Value;
6648 // Converts static initializer only
6650 void UnifyInitializerElement (ResolveContext ec)
6652 for (int i = 0; i < array_data.Count; ++i) {
6653 Expression e = array_data[i];
6655 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6659 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6661 element = element.Resolve (ec);
6662 if (element != null)
6663 best_type_inference.AddExpression (element);
6669 sealed class CompilerGeneratedThis : This
6671 public CompilerGeneratedThis (TypeSpec type, Location loc)
6675 eclass = ExprClass.Variable;
6678 protected override Expression DoResolve (ResolveContext ec)
6683 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6690 /// Represents the `this' construct
6693 public class This : VariableReference
6695 sealed class ThisVariable : ILocalVariable
6697 public static readonly ILocalVariable Instance = new ThisVariable ();
6699 public void Emit (EmitContext ec)
6704 public void EmitAssign (EmitContext ec)
6706 throw new InvalidOperationException ();
6709 public void EmitAddressOf (EmitContext ec)
6715 VariableInfo variable_info;
6717 public This (Location loc)
6724 public override string Name {
6725 get { return "this"; }
6728 public override bool IsLockedByStatement {
6736 public override bool IsRef {
6737 get { return type.IsStruct; }
6740 public override bool IsSideEffectFree {
6746 protected override ILocalVariable Variable {
6747 get { return ThisVariable.Instance; }
6750 public override VariableInfo VariableInfo {
6751 get { return variable_info; }
6754 public override bool IsFixed {
6755 get { return false; }
6760 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
6762 if (variable_info != null && !variable_info.IsAssigned (rc)) {
6763 rc.Report.Error (188, loc,
6764 "The `this' object cannot be used before all of its fields are assigned to");
6768 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
6770 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6771 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6772 } else if (ec.CurrentAnonymousMethod != null) {
6773 ec.Report.Error (1673, loc,
6774 "Anonymous methods inside structs cannot access instance members of `this'. " +
6775 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6777 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6781 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6786 AnonymousMethodStorey storey = ae.Storey;
6787 while (storey != null) {
6788 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6790 return storey.HoistedThis;
6798 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
6800 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
6803 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
6806 if (ec.CurrentType.IsStruct && ec.CurrentIterator == null)
6812 public virtual void ResolveBase (ResolveContext ec)
6814 eclass = ExprClass.Variable;
6815 type = ec.CurrentType;
6817 if (!IsThisAvailable (ec, false)) {
6818 Error_ThisNotAvailable (ec);
6822 var block = ec.CurrentBlock;
6823 if (block != null) {
6824 if (block.ParametersBlock.TopBlock.ThisVariable != null)
6825 variable_info = block.ParametersBlock.TopBlock.ThisVariable.VariableInfo;
6827 AnonymousExpression am = ec.CurrentAnonymousMethod;
6828 if (am != null && ec.IsVariableCapturingRequired) {
6829 am.SetHasThisAccess ();
6834 protected override Expression DoResolve (ResolveContext ec)
6838 if (variable_info != null && type.IsStruct) {
6839 CheckStructThisDefiniteAssignment (ec);
6845 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6849 if (variable_info != null)
6850 variable_info.SetAssigned (ec);
6853 if (right_side == EmptyExpression.UnaryAddress)
6854 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6855 else if (right_side == EmptyExpression.OutAccess)
6856 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6858 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6864 public override int GetHashCode()
6866 throw new NotImplementedException ();
6869 public override bool Equals (object obj)
6871 This t = obj as This;
6878 protected override void CloneTo (CloneContext clonectx, Expression t)
6883 public override void SetHasAddressTaken ()
6890 /// Represents the `__arglist' construct
6892 public class ArglistAccess : Expression
6894 public ArglistAccess (Location loc)
6899 protected override void CloneTo (CloneContext clonectx, Expression target)
6904 public override bool ContainsEmitWithAwait ()
6909 public override Expression CreateExpressionTree (ResolveContext ec)
6911 throw new NotSupportedException ("ET");
6914 protected override Expression DoResolve (ResolveContext ec)
6916 eclass = ExprClass.Variable;
6917 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
6919 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
6920 ec.Report.Error (190, loc,
6921 "The __arglist construct is valid only within a variable argument method");
6927 public override void Emit (EmitContext ec)
6929 ec.Emit (OpCodes.Arglist);
6934 /// Represents the `__arglist (....)' construct
6936 public class Arglist : Expression
6938 Arguments Arguments;
6940 public Arglist (Location loc)
6945 public Arglist (Arguments args, Location l)
6951 public MetaType[] ArgumentTypes {
6953 if (Arguments == null)
6954 return MetaType.EmptyTypes;
6956 var retval = new MetaType[Arguments.Count];
6957 for (int i = 0; i < retval.Length; i++)
6958 retval[i] = Arguments[i].Expr.Type.GetMetaInfo ();
6964 public override bool ContainsEmitWithAwait ()
6966 throw new NotImplementedException ();
6969 public override Expression CreateExpressionTree (ResolveContext ec)
6971 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6975 protected override Expression DoResolve (ResolveContext ec)
6977 eclass = ExprClass.Variable;
6978 type = InternalType.Arglist;
6979 if (Arguments != null) {
6980 bool dynamic; // Can be ignored as there is always only 1 overload
6981 Arguments.Resolve (ec, out dynamic);
6987 public override void Emit (EmitContext ec)
6989 if (Arguments != null)
6990 Arguments.Emit (ec);
6993 protected override void CloneTo (CloneContext clonectx, Expression t)
6995 Arglist target = (Arglist) t;
6997 if (Arguments != null)
6998 target.Arguments = Arguments.Clone (clonectx);
7002 class RefValueExpr : ShimExpression
7004 FullNamedExpression texpr;
7006 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7013 public override bool ContainsEmitWithAwait ()
7018 protected override Expression DoResolve (ResolveContext rc)
7020 expr = expr.Resolve (rc);
7021 type = texpr.ResolveAsType (rc);
7022 if (expr == null || type == null)
7025 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7026 eclass = ExprClass.Value;
7030 public override void Emit (EmitContext ec)
7033 ec.Emit (OpCodes.Refanyval, type);
7034 ec.EmitLoadFromPtr (type);
7038 class RefTypeExpr : ShimExpression
7040 public RefTypeExpr (Expression expr, Location loc)
7046 protected override Expression DoResolve (ResolveContext rc)
7048 expr = expr.Resolve (rc);
7052 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7056 type = rc.BuiltinTypes.Type;
7057 eclass = ExprClass.Value;
7061 public override void Emit (EmitContext ec)
7064 ec.Emit (OpCodes.Refanytype);
7065 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7067 ec.Emit (OpCodes.Call, m);
7071 class MakeRefExpr : ShimExpression
7073 public MakeRefExpr (Expression expr, Location loc)
7079 public override bool ContainsEmitWithAwait ()
7081 throw new NotImplementedException ();
7084 protected override Expression DoResolve (ResolveContext rc)
7086 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
7087 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
7088 eclass = ExprClass.Value;
7092 public override void Emit (EmitContext ec)
7094 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
7095 ec.Emit (OpCodes.Mkrefany, expr.Type);
7100 /// Implements the typeof operator
7102 public class TypeOf : Expression {
7103 FullNamedExpression QueriedType;
7106 public TypeOf (FullNamedExpression queried_type, Location l)
7108 QueriedType = queried_type;
7113 // Use this constructor for any compiler generated typeof expression
7115 public TypeOf (TypeSpec type, Location loc)
7117 this.typearg = type;
7123 public override bool IsSideEffectFree {
7129 public TypeSpec TypeArgument {
7135 public FullNamedExpression TypeExpression {
7144 protected override void CloneTo (CloneContext clonectx, Expression t)
7146 TypeOf target = (TypeOf) t;
7147 if (QueriedType != null)
7148 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
7151 public override bool ContainsEmitWithAwait ()
7156 public override Expression CreateExpressionTree (ResolveContext ec)
7158 Arguments args = new Arguments (2);
7159 args.Add (new Argument (this));
7160 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7161 return CreateExpressionFactoryCall (ec, "Constant", args);
7164 protected override Expression DoResolve (ResolveContext ec)
7166 if (eclass != ExprClass.Unresolved)
7169 if (typearg == null) {
7171 // Pointer types are allowed without explicit unsafe, they are just tokens
7173 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
7174 typearg = QueriedType.ResolveAsType (ec);
7177 if (typearg == null)
7180 if (typearg.Kind == MemberKind.Void && !(QueriedType is TypeExpression)) {
7181 ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
7182 } else if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7183 ec.Report.Error (1962, QueriedType.Location,
7184 "The typeof operator cannot be used on the dynamic type");
7188 type = ec.BuiltinTypes.Type;
7190 // Even though what is returned is a type object, it's treated as a value by the compiler.
7191 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7192 eclass = ExprClass.Value;
7196 static bool ContainsDynamicType (TypeSpec type)
7198 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7201 var element_container = type as ElementTypeSpec;
7202 if (element_container != null)
7203 return ContainsDynamicType (element_container.Element);
7205 foreach (var t in type.TypeArguments) {
7206 if (ContainsDynamicType (t)) {
7214 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7216 // Target type is not System.Type therefore must be object
7217 // and we need to use different encoding sequence
7218 if (targetType != type)
7221 if (typearg is InflatedTypeSpec) {
7224 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
7225 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7226 typearg.GetSignatureForError ());
7230 gt = gt.DeclaringType;
7231 } while (gt != null);
7234 if (ContainsDynamicType (typearg)) {
7235 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7239 enc.EncodeTypeName (typearg);
7242 public override void Emit (EmitContext ec)
7244 ec.Emit (OpCodes.Ldtoken, typearg);
7245 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7247 ec.Emit (OpCodes.Call, m);
7251 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
7253 public TypeOfMethod (MethodSpec method, Location loc)
7254 : base (method, loc)
7258 protected override Expression DoResolve (ResolveContext ec)
7260 if (member.IsConstructor) {
7261 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
7263 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
7269 return base.DoResolve (ec);
7272 public override void Emit (EmitContext ec)
7274 ec.Emit (OpCodes.Ldtoken, member);
7277 ec.Emit (OpCodes.Castclass, type);
7280 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7282 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
7285 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7287 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
7291 abstract class TypeOfMember<T> : Expression where T : MemberSpec
7293 protected readonly T member;
7295 protected TypeOfMember (T member, Location loc)
7297 this.member = member;
7301 public override bool IsSideEffectFree {
7307 public override bool ContainsEmitWithAwait ()
7312 public override Expression CreateExpressionTree (ResolveContext ec)
7314 Arguments args = new Arguments (2);
7315 args.Add (new Argument (this));
7316 args.Add (new Argument (new TypeOf (type, loc)));
7317 return CreateExpressionFactoryCall (ec, "Constant", args);
7320 protected override Expression DoResolve (ResolveContext ec)
7322 eclass = ExprClass.Value;
7326 public override void Emit (EmitContext ec)
7328 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
7329 PredefinedMember<MethodSpec> p;
7331 p = GetTypeFromHandleGeneric (ec);
7332 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
7334 p = GetTypeFromHandle (ec);
7337 var mi = p.Resolve (loc);
7339 ec.Emit (OpCodes.Call, mi);
7342 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
7343 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
7346 sealed class TypeOfField : TypeOfMember<FieldSpec>
7348 public TypeOfField (FieldSpec field, Location loc)
7353 protected override Expression DoResolve (ResolveContext ec)
7355 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
7359 return base.DoResolve (ec);
7362 public override void Emit (EmitContext ec)
7364 ec.Emit (OpCodes.Ldtoken, member);
7368 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7370 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
7373 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7375 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
7380 /// Implements the sizeof expression
7382 public class SizeOf : Expression {
7383 readonly Expression QueriedType;
7384 TypeSpec type_queried;
7386 public SizeOf (Expression queried_type, Location l)
7388 this.QueriedType = queried_type;
7392 public override bool IsSideEffectFree {
7398 public override bool ContainsEmitWithAwait ()
7403 public override Expression CreateExpressionTree (ResolveContext ec)
7405 Error_PointerInsideExpressionTree (ec);
7409 protected override Expression DoResolve (ResolveContext ec)
7411 type_queried = QueriedType.ResolveAsType (ec);
7412 if (type_queried == null)
7415 if (TypeManager.IsEnumType (type_queried))
7416 type_queried = EnumSpec.GetUnderlyingType (type_queried);
7418 int size_of = BuiltinTypeSpec.GetSize (type_queried);
7420 return new IntConstant (ec.BuiltinTypes, size_of, loc);
7423 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
7428 ec.Report.Error (233, loc,
7429 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7430 TypeManager.CSharpName (type_queried));
7433 type = ec.BuiltinTypes.Int;
7434 eclass = ExprClass.Value;
7438 public override void Emit (EmitContext ec)
7440 ec.Emit (OpCodes.Sizeof, type_queried);
7443 protected override void CloneTo (CloneContext clonectx, Expression t)
7449 /// Implements the qualified-alias-member (::) expression.
7451 public class QualifiedAliasMember : MemberAccess
7453 readonly string alias;
7454 public static readonly string GlobalAlias = "global";
7456 public QualifiedAliasMember (string alias, string identifier, Location l)
7457 : base (null, identifier, l)
7462 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7463 : base (null, identifier, targs, l)
7468 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
7469 : base (null, identifier, arity, l)
7474 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
7476 if (alias == GlobalAlias) {
7477 expr = ec.Module.GlobalRootNamespace;
7478 return base.ResolveAsTypeOrNamespace (ec);
7481 int errors = ec.Module.Compiler.Report.Errors;
7482 expr = ec.LookupNamespaceAlias (alias);
7484 if (errors == ec.Module.Compiler.Report.Errors)
7485 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7489 FullNamedExpression fne = base.ResolveAsTypeOrNamespace (ec);
7493 if (expr.eclass == ExprClass.Type) {
7494 ec.Module.Compiler.Report.Error (431, loc,
7495 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7503 protected override Expression DoResolve (ResolveContext ec)
7505 return ResolveAsTypeOrNamespace (ec);
7508 protected override void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7510 rc.Module.Compiler.Report.Error (687, loc,
7511 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7512 GetSignatureForError ());
7515 public override string GetSignatureForError ()
7518 if (targs != null) {
7519 name = Name + "<" + targs.GetSignatureForError () + ">";
7522 return alias + "::" + name;
7525 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7527 return DoResolve (rc);
7530 protected override void CloneTo (CloneContext clonectx, Expression t)
7537 /// Implements the member access expression
7539 public class MemberAccess : ATypeNameExpression
7541 protected Expression expr;
7543 public MemberAccess (Expression expr, string id)
7544 : base (id, expr.Location)
7549 public MemberAccess (Expression expr, string identifier, Location loc)
7550 : base (identifier, loc)
7555 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7556 : base (identifier, args, loc)
7561 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
7562 : base (identifier, arity, loc)
7567 public Expression LeftExpression {
7573 protected override Expression DoResolve (ResolveContext ec)
7575 return DoResolveName (ec, null);
7578 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7580 return DoResolveName (ec, right_side);
7583 Expression DoResolveName (ResolveContext rc, Expression right_side)
7585 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
7589 if (right_side != null) {
7590 if (e is TypeExpr) {
7591 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
7595 e = e.ResolveLValue (rc, right_side);
7597 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
7603 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
7605 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
7606 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
7608 Unary.Error_OperatorCannotBeApplied (rc, loc, ".", type);
7611 public static bool IsValidDotExpression (TypeSpec type)
7613 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
7614 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
7616 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7619 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7621 var sn = expr as SimpleName;
7622 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
7625 // Resolve the expression with flow analysis turned off, we'll do the definite
7626 // assignment checks later. This is because we don't know yet what the expression
7627 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7628 // definite assignment check on the actual field and not on the whole struct.
7630 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
7632 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
7634 // Call resolve on expression which does have type set as we need expression type
7635 // TODO: I should probably ensure that the type is always set and leave resolve for the final
7636 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
7637 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
7638 expr = expr.Resolve (rc);
7640 } else if (expr is TypeParameterExpr) {
7641 expr.Error_UnexpectedKind (rc, flags, sn.Location);
7645 expr = expr.Resolve (rc, flags);
7652 Namespace ns = expr as Namespace;
7654 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
7656 if (retval == null) {
7657 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
7661 if (HasTypeArguments)
7662 return new GenericTypeExpr (retval.Type, targs, loc);
7668 TypeSpec expr_type = expr.Type;
7669 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7670 me = expr as MemberExpr;
7672 me.ResolveInstanceExpression (rc, null);
7674 Arguments args = new Arguments (1);
7675 args.Add (new Argument (expr));
7676 return new DynamicMemberBinder (Name, args, loc);
7679 if (!IsValidDotExpression (expr_type)) {
7680 Error_OperatorCannotBeApplied (rc, expr_type);
7684 var lookup_arity = Arity;
7685 bool errorMode = false;
7686 Expression member_lookup;
7688 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
7689 if (member_lookup == null) {
7691 // Try to look for extension method when member lookup failed
7693 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
7694 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
7695 if (methods != null) {
7696 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
7697 if (HasTypeArguments) {
7698 if (!targs.Resolve (rc))
7701 emg.SetTypeArguments (rc, targs);
7704 // TODO: it should really skip the checks bellow
7705 return emg.Resolve (rc);
7711 if (member_lookup == null) {
7712 var dep = expr_type.GetMissingDependencies ();
7714 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
7715 } else if (expr is TypeExpr) {
7716 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
7718 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
7724 if (member_lookup is MethodGroupExpr) {
7725 // Leave it to overload resolution to report correct error
7726 } else if (!(member_lookup is TypeExpr)) {
7727 // TODO: rc.SymbolRelatedToPreviousError
7728 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
7733 if (member_lookup != null)
7737 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
7741 TypeExpr texpr = member_lookup as TypeExpr;
7742 if (texpr != null) {
7743 if (!(expr is TypeExpr)) {
7744 me = expr as MemberExpr;
7745 if (me == null || me.ProbeIdenticalTypeName (rc, expr, sn) == expr) {
7746 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7747 Name, member_lookup.GetSignatureForError ());
7752 if (!texpr.Type.IsAccessible (rc)) {
7753 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
7754 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
7758 if (HasTypeArguments) {
7759 return new GenericTypeExpr (member_lookup.Type, targs, loc);
7762 return member_lookup;
7765 me = member_lookup as MemberExpr;
7767 if (sn != null && me.IsStatic)
7768 expr = me.ProbeIdenticalTypeName (rc, expr, sn);
7770 me = me.ResolveMemberAccess (rc, expr, sn);
7773 if (!targs.Resolve (rc))
7776 me.SetTypeArguments (rc, targs);
7779 if (sn != null && (!TypeSpec.IsValueType (expr_type) || me is PropertyExpr)) {
7780 if (me.IsInstance) {
7781 LocalVariableReference var = expr as LocalVariableReference;
7782 if (var != null && !var.VerifyAssigned (rc))
7790 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
7792 FullNamedExpression fexpr = expr as FullNamedExpression;
7793 if (fexpr == null) {
7794 expr.ResolveAsType (rc);
7798 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
7800 if (expr_resolved == null)
7803 Namespace ns = expr_resolved as Namespace;
7805 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
7807 if (retval == null) {
7808 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
7809 } else if (HasTypeArguments) {
7810 retval = new GenericTypeExpr (retval.Type, targs, loc);
7811 if (retval.ResolveAsType (rc) == null)
7818 var tnew_expr = expr_resolved.ResolveAsType (rc);
7819 if (tnew_expr == null)
7822 TypeSpec expr_type = tnew_expr;
7823 if (TypeManager.IsGenericParameter (expr_type)) {
7824 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7825 tnew_expr.GetSignatureForError ());
7829 TypeSpec nested = null;
7830 while (expr_type != null) {
7831 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7832 if (nested == null) {
7833 if (expr_type == tnew_expr) {
7834 Error_IdentifierNotFound (rc, expr_type, Name);
7838 expr_type = tnew_expr;
7839 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7840 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
7844 if (nested.IsAccessible (rc))
7848 // Keep looking after inaccessible candidate but only if
7849 // we are not in same context as the definition itself
7851 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
7854 expr_type = expr_type.BaseType;
7859 if (HasTypeArguments) {
7860 texpr = new GenericTypeExpr (nested, targs, loc);
7862 texpr = new GenericOpenTypeExpr (nested, loc);
7865 texpr = new TypeExpression (nested, loc);
7868 if (texpr.ResolveAsType (rc) == null)
7874 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7876 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
7878 if (nested != null) {
7879 Error_TypeArgumentsCannotBeUsed (rc, nested, Arity, expr.Location);
7883 var any_other_member = MemberLookup (rc, true, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
7884 if (any_other_member != null) {
7885 any_other_member.Error_UnexpectedKind (rc.Module.Compiler.Report, null, "type", loc);
7889 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7890 Name, expr_type.GetSignatureForError ());
7893 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
7895 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
7896 ec.Report.SymbolRelatedToPreviousError (type);
7897 ec.Report.Error (1061, loc,
7898 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found (are you missing a using directive or an assembly reference?)",
7899 type.GetSignatureForError (), name);
7903 base.Error_TypeDoesNotContainDefinition (ec, type, name);
7906 public override string GetSignatureForError ()
7908 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7911 protected override void CloneTo (CloneContext clonectx, Expression t)
7913 MemberAccess target = (MemberAccess) t;
7915 target.expr = expr.Clone (clonectx);
7920 /// Implements checked expressions
7922 public class CheckedExpr : Expression {
7924 public Expression Expr;
7926 public CheckedExpr (Expression e, Location l)
7932 public override bool ContainsEmitWithAwait ()
7934 return Expr.ContainsEmitWithAwait ();
7937 public override Expression CreateExpressionTree (ResolveContext ec)
7939 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7940 return Expr.CreateExpressionTree (ec);
7943 protected override Expression DoResolve (ResolveContext ec)
7945 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7946 Expr = Expr.Resolve (ec);
7951 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7954 eclass = Expr.eclass;
7959 public override void Emit (EmitContext ec)
7961 using (ec.With (EmitContext.Options.CheckedScope, true))
7965 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7967 using (ec.With (EmitContext.Options.CheckedScope, true))
7968 Expr.EmitBranchable (ec, target, on_true);
7971 public override SLE.Expression MakeExpression (BuilderContext ctx)
7973 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
7974 return Expr.MakeExpression (ctx);
7978 protected override void CloneTo (CloneContext clonectx, Expression t)
7980 CheckedExpr target = (CheckedExpr) t;
7982 target.Expr = Expr.Clone (clonectx);
7987 /// Implements the unchecked expression
7989 public class UnCheckedExpr : Expression {
7991 public Expression Expr;
7993 public UnCheckedExpr (Expression e, Location l)
7999 public override bool ContainsEmitWithAwait ()
8001 return Expr.ContainsEmitWithAwait ();
8004 public override Expression CreateExpressionTree (ResolveContext ec)
8006 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8007 return Expr.CreateExpressionTree (ec);
8010 protected override Expression DoResolve (ResolveContext ec)
8012 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8013 Expr = Expr.Resolve (ec);
8018 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8021 eclass = Expr.eclass;
8026 public override void Emit (EmitContext ec)
8028 using (ec.With (EmitContext.Options.CheckedScope, false))
8032 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8034 using (ec.With (EmitContext.Options.CheckedScope, false))
8035 Expr.EmitBranchable (ec, target, on_true);
8038 protected override void CloneTo (CloneContext clonectx, Expression t)
8040 UnCheckedExpr target = (UnCheckedExpr) t;
8042 target.Expr = Expr.Clone (clonectx);
8047 /// An Element Access expression.
8049 /// During semantic analysis these are transformed into
8050 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
8052 public class ElementAccess : Expression
8054 public Arguments Arguments;
8055 public Expression Expr;
8057 public ElementAccess (Expression e, Arguments args, Location loc)
8061 this.Arguments = args;
8064 public override bool ContainsEmitWithAwait ()
8066 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
8070 // We perform some simple tests, and then to "split" the emit and store
8071 // code we create an instance of a different class, and return that.
8073 Expression CreateAccessExpression (ResolveContext ec)
8076 return (new ArrayAccess (this, loc));
8079 return MakePointerAccess (ec, type);
8081 FieldExpr fe = Expr as FieldExpr;
8083 var ff = fe.Spec as FixedFieldSpec;
8085 return MakePointerAccess (ec, ff.ElementType);
8089 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
8090 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8091 return new IndexerExpr (indexers, type, this);
8094 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8095 type.GetSignatureForError ());
8099 public override Expression CreateExpressionTree (ResolveContext ec)
8101 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
8102 Expr.CreateExpressionTree (ec));
8104 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
8107 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
8109 if (Arguments.Count != 1){
8110 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
8114 if (Arguments [0] is NamedArgument)
8115 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
8117 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
8118 return new Indirection (p, loc);
8121 protected override Expression DoResolve (ResolveContext ec)
8123 Expr = Expr.Resolve (ec);
8129 // TODO: Create 1 result for Resolve and ResolveLValue ?
8130 var res = CreateAccessExpression (ec);
8134 return res.Resolve (ec);
8137 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8139 Expr = Expr.Resolve (ec);
8145 var res = CreateAccessExpression (ec);
8149 return res.ResolveLValue (ec, right_side);
8152 public override void Emit (EmitContext ec)
8154 throw new Exception ("Should never be reached");
8157 public static void Error_NamedArgument (NamedArgument na, Report Report)
8159 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
8162 public override string GetSignatureForError ()
8164 return Expr.GetSignatureForError ();
8167 protected override void CloneTo (CloneContext clonectx, Expression t)
8169 ElementAccess target = (ElementAccess) t;
8171 target.Expr = Expr.Clone (clonectx);
8172 if (Arguments != null)
8173 target.Arguments = Arguments.Clone (clonectx);
8178 /// Implements array access
8180 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
8182 // Points to our "data" repository
8186 LocalTemporary temp;
8188 bool? has_await_args;
8190 public ArrayAccess (ElementAccess ea_data, Location l)
8196 public void AddressOf (EmitContext ec, AddressOp mode)
8198 var ac = (ArrayContainer) ea.Expr.Type;
8200 LoadInstanceAndArguments (ec, false, false);
8202 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
8203 ec.Emit (OpCodes.Readonly);
8205 ec.EmitArrayAddress (ac);
8208 public override Expression CreateExpressionTree (ResolveContext ec)
8210 return ea.CreateExpressionTree (ec);
8213 public override bool ContainsEmitWithAwait ()
8215 return ea.ContainsEmitWithAwait ();
8218 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8220 return DoResolve (ec);
8223 protected override Expression DoResolve (ResolveContext ec)
8225 // dynamic is used per argument in ConvertExpressionToArrayIndex case
8227 ea.Arguments.Resolve (ec, out dynamic);
8229 var ac = ea.Expr.Type as ArrayContainer;
8230 int rank = ea.Arguments.Count;
8231 if (ac.Rank != rank) {
8232 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8233 rank.ToString (), ac.Rank.ToString ());
8238 if (type.IsPointer && !ec.IsUnsafe) {
8239 UnsafeError (ec, ea.Location);
8242 foreach (Argument a in ea.Arguments) {
8243 if (a is NamedArgument)
8244 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
8246 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
8249 eclass = ExprClass.Variable;
8254 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8256 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8260 // Load the array arguments into the stack.
8262 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
8265 ea.Expr = ea.Expr.EmitToField (ec);
8266 } else if (duplicateArguments) {
8268 ec.Emit (OpCodes.Dup);
8270 var copy = new LocalTemporary (ea.Expr.Type);
8277 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
8278 if (dup_args != null)
8279 ea.Arguments = dup_args;
8282 public void Emit (EmitContext ec, bool leave_copy)
8284 var ac = ea.Expr.Type as ArrayContainer;
8287 ec.EmitLoadFromPtr (type);
8289 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
8290 LoadInstanceAndArguments (ec, false, true);
8293 LoadInstanceAndArguments (ec, false, false);
8294 ec.EmitArrayLoad (ac);
8298 ec.Emit (OpCodes.Dup);
8299 temp = new LocalTemporary (this.type);
8304 public override void Emit (EmitContext ec)
8309 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8311 var ac = (ArrayContainer) ea.Expr.Type;
8312 TypeSpec t = source.Type;
8314 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
8317 // When we are dealing with a struct, get the address of it to avoid value copy
8318 // Same cannot be done for reference type because array covariance and the
8319 // check in ldelema requires to specify the type of array element stored at the index
8321 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
8322 LoadInstanceAndArguments (ec, false, has_await_args.Value);
8324 if (has_await_args.Value) {
8325 if (source.ContainsEmitWithAwait ()) {
8326 source = source.EmitToField (ec);
8331 LoadInstanceAndArguments (ec, isCompound, false);
8336 ec.EmitArrayAddress (ac);
8339 ec.Emit (OpCodes.Dup);
8343 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
8345 if (has_await_args.Value) {
8346 if (source.ContainsEmitWithAwait ())
8347 source = source.EmitToField (ec);
8349 LoadInstanceAndArguments (ec, false, false);
8356 var lt = ea.Expr as LocalTemporary;
8362 ec.Emit (OpCodes.Dup);
8363 temp = new LocalTemporary (this.type);
8368 ec.EmitStoreFromPtr (t);
8370 ec.EmitArrayStore (ac);
8379 public override Expression EmitToField (EmitContext ec)
8382 // Have to be specialized for arrays to get access to
8383 // underlying element. Instead of another result copy we
8384 // need direct access to element
8388 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
8390 ea.Expr = ea.Expr.EmitToField (ec);
8394 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8397 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8399 throw new NotImplementedException ();
8403 public override SLE.Expression MakeExpression (BuilderContext ctx)
8405 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8408 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
8410 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
8411 return Arguments.MakeExpression (ea.Arguments, ctx);
8417 // Indexer access expression
8419 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
8421 IList<MemberSpec> indexers;
8422 Arguments arguments;
8423 TypeSpec queried_type;
8425 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
8426 : base (ea.Location)
8428 this.indexers = indexers;
8429 this.queried_type = queriedType;
8430 this.InstanceExpression = ea.Expr;
8431 this.arguments = ea.Arguments;
8436 protected override Arguments Arguments {
8445 protected override TypeSpec DeclaringType {
8447 return best_candidate.DeclaringType;
8451 public override bool IsInstance {
8457 public override bool IsStatic {
8463 public override string Name {
8471 public override bool ContainsEmitWithAwait ()
8473 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
8476 public override Expression CreateExpressionTree (ResolveContext ec)
8478 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8479 InstanceExpression.CreateExpressionTree (ec),
8480 new TypeOfMethod (Getter, loc));
8482 return CreateExpressionFactoryCall (ec, "Call", args);
8485 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8487 LocalTemporary await_source_arg = null;
8490 emitting_compound_assignment = true;
8491 if (source is DynamicExpressionStatement) {
8496 emitting_compound_assignment = false;
8498 if (has_await_arguments) {
8499 await_source_arg = new LocalTemporary (Type);
8500 await_source_arg.Store (ec);
8502 arguments.Add (new Argument (await_source_arg));
8505 temp = await_source_arg;
8508 has_await_arguments = false;
8513 ec.Emit (OpCodes.Dup);
8514 temp = new LocalTemporary (Type);
8520 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
8521 source = source.EmitToField (ec);
8523 temp = new LocalTemporary (Type);
8530 arguments.Add (new Argument (source));
8533 var call = new CallEmitter ();
8534 call.InstanceExpression = InstanceExpression;
8535 if (arguments == null)
8536 call.InstanceExpressionOnStack = true;
8538 call.Emit (ec, Setter, arguments, loc);
8543 } else if (leave_copy) {
8547 if (await_source_arg != null) {
8548 await_source_arg.Release (ec);
8552 public override string GetSignatureForError ()
8554 return best_candidate.GetSignatureForError ();
8557 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8560 throw new NotSupportedException ();
8562 var value = new[] { source.MakeExpression (ctx) };
8563 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
8565 return SLE.Expression.Block (
8566 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
8569 return args.First ();
8574 public override SLE.Expression MakeExpression (BuilderContext ctx)
8577 return base.MakeExpression (ctx);
8579 var args = Arguments.MakeExpression (arguments, ctx);
8580 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
8584 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
8586 if (best_candidate != null)
8589 eclass = ExprClass.IndexerAccess;
8592 arguments.Resolve (rc, out dynamic);
8594 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8597 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
8598 res.BaseMembersProvider = this;
8600 // TODO: Do I need 2 argument sets?
8601 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
8602 if (best_candidate != null)
8603 type = res.BestCandidateReturnType;
8604 else if (!res.BestCandidateIsDynamic)
8609 // It has dynamic arguments
8612 Arguments args = new Arguments (arguments.Count + 1);
8614 rc.Report.Error (1972, loc,
8615 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8617 args.Add (new Argument (InstanceExpression));
8619 args.AddRange (arguments);
8621 best_candidate = null;
8622 return new DynamicIndexBinder (args, loc);
8625 ResolveInstanceExpression (rc, right_side);
8626 CheckProtectedMemberAccess (rc, best_candidate);
8630 protected override void CloneTo (CloneContext clonectx, Expression t)
8632 IndexerExpr target = (IndexerExpr) t;
8634 if (arguments != null)
8635 target.arguments = arguments.Clone (clonectx);
8638 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
8640 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
8643 #region IBaseMembersProvider Members
8645 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
8647 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
8650 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
8652 if (queried_type == member.DeclaringType)
8655 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
8656 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
8659 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
8668 // A base access expression
8670 public class BaseThis : This
8672 public BaseThis (Location loc)
8677 public BaseThis (TypeSpec type, Location loc)
8681 eclass = ExprClass.Variable;
8686 public override string Name {
8694 public override Expression CreateExpressionTree (ResolveContext ec)
8696 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
8697 return base.CreateExpressionTree (ec);
8700 public override void Emit (EmitContext ec)
8704 var context_type = ec.CurrentType;
8705 if (context_type.IsStruct) {
8706 ec.Emit (OpCodes.Ldobj, context_type);
8707 ec.Emit (OpCodes.Box, context_type);
8711 protected override void Error_ThisNotAvailable (ResolveContext ec)
8714 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
8716 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
8720 public override void ResolveBase (ResolveContext ec)
8722 base.ResolveBase (ec);
8723 type = ec.CurrentType.BaseType;
8728 /// This class exists solely to pass the Type around and to be a dummy
8729 /// that can be passed to the conversion functions (this is used by
8730 /// foreach implementation to typecast the object return value from
8731 /// get_Current into the proper type. All code has been generated and
8732 /// we only care about the side effect conversions to be performed
8734 /// This is also now used as a placeholder where a no-action expression
8735 /// is needed (the `New' class).
8737 class EmptyExpression : Expression
8739 sealed class OutAccessExpression : EmptyExpression
8741 public OutAccessExpression (TypeSpec t)
8746 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8748 rc.Report.Error (206, right_side.Location,
8749 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
8755 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
8756 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
8757 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
8758 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
8759 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
8760 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
8761 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
8762 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
8764 public EmptyExpression (TypeSpec t)
8767 eclass = ExprClass.Value;
8768 loc = Location.Null;
8771 public override bool ContainsEmitWithAwait ()
8776 public override Expression CreateExpressionTree (ResolveContext ec)
8778 throw new NotSupportedException ("ET");
8781 protected override Expression DoResolve (ResolveContext ec)
8786 public override void Emit (EmitContext ec)
8788 // nothing, as we only exist to not do anything.
8791 public override void EmitSideEffect (EmitContext ec)
8796 sealed class EmptyAwaitExpression : EmptyExpression
8798 public EmptyAwaitExpression (TypeSpec type)
8803 public override bool ContainsEmitWithAwait ()
8810 // Empty statement expression
8812 public sealed class EmptyExpressionStatement : ExpressionStatement
8814 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8816 private EmptyExpressionStatement ()
8818 loc = Location.Null;
8821 public override bool ContainsEmitWithAwait ()
8826 public override Expression CreateExpressionTree (ResolveContext ec)
8831 public override void EmitStatement (EmitContext ec)
8836 protected override Expression DoResolve (ResolveContext ec)
8838 eclass = ExprClass.Value;
8839 type = ec.BuiltinTypes.Object;
8843 public override void Emit (EmitContext ec)
8849 class ErrorExpression : EmptyExpression
8851 public static readonly ErrorExpression Instance = new ErrorExpression ();
8853 private ErrorExpression ()
8854 : base (InternalType.FakeInternalType)
8858 public override Expression CreateExpressionTree (ResolveContext ec)
8863 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8868 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
8873 public class UserCast : Expression {
8877 public UserCast (MethodSpec method, Expression source, Location l)
8879 this.method = method;
8880 this.source = source;
8881 type = method.ReturnType;
8885 public Expression Source {
8891 public override bool ContainsEmitWithAwait ()
8893 return source.ContainsEmitWithAwait ();
8896 public override Expression CreateExpressionTree (ResolveContext ec)
8898 Arguments args = new Arguments (3);
8899 args.Add (new Argument (source.CreateExpressionTree (ec)));
8900 args.Add (new Argument (new TypeOf (type, loc)));
8901 args.Add (new Argument (new TypeOfMethod (method, loc)));
8902 return CreateExpressionFactoryCall (ec, "Convert", args);
8905 protected override Expression DoResolve (ResolveContext ec)
8907 ObsoleteAttribute oa = method.GetAttributeObsolete ();
8909 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
8911 eclass = ExprClass.Value;
8915 public override void Emit (EmitContext ec)
8918 ec.Emit (OpCodes.Call, method);
8921 public override string GetSignatureForError ()
8923 return TypeManager.CSharpSignature (method);
8926 public override SLE.Expression MakeExpression (BuilderContext ctx)
8929 return base.MakeExpression (ctx);
8931 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
8937 // Holds additional type specifiers like ?, *, []
8939 public class ComposedTypeSpecifier
8941 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
8943 public readonly int Dimension;
8944 public readonly Location Location;
8946 public ComposedTypeSpecifier (int specifier, Location loc)
8948 this.Dimension = specifier;
8949 this.Location = loc;
8953 public bool IsNullable {
8955 return Dimension == -1;
8959 public bool IsPointer {
8961 return Dimension == -2;
8965 public ComposedTypeSpecifier Next { get; set; }
8969 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
8971 return new ComposedTypeSpecifier (dimension, loc);
8974 public static ComposedTypeSpecifier CreateNullable (Location loc)
8976 return new ComposedTypeSpecifier (-1, loc);
8979 public static ComposedTypeSpecifier CreatePointer (Location loc)
8981 return new ComposedTypeSpecifier (-2, loc);
8984 public string GetSignatureForError ()
8989 ArrayContainer.GetPostfixSignature (Dimension);
8991 return Next != null ? s + Next.GetSignatureForError () : s;
8996 // This class is used to "construct" the type during a typecast
8997 // operation. Since the Type.GetType class in .NET can parse
8998 // the type specification, we just use this to construct the type
8999 // one bit at a time.
9001 public class ComposedCast : TypeExpr {
9002 FullNamedExpression left;
9003 ComposedTypeSpecifier spec;
9005 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
9008 throw new ArgumentNullException ("spec");
9012 this.loc = spec.Location;
9015 public override TypeSpec ResolveAsType (IMemberContext ec)
9017 type = left.ResolveAsType (ec);
9021 eclass = ExprClass.Type;
9023 var single_spec = spec;
9025 if (single_spec.IsNullable) {
9026 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
9030 single_spec = single_spec.Next;
9031 } else if (single_spec.IsPointer) {
9032 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
9036 UnsafeError (ec.Module.Compiler.Report, loc);
9040 type = PointerContainer.MakeType (ec.Module, type);
9041 single_spec = single_spec.Next;
9042 } while (single_spec != null && single_spec.IsPointer);
9045 if (single_spec != null && single_spec.Dimension > 0) {
9046 if (type.IsSpecialRuntimeType) {
9047 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
9048 } else if (type.IsStatic) {
9049 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
9050 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9051 type.GetSignatureForError ());
9053 MakeArray (ec.Module, single_spec);
9060 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
9062 if (spec.Next != null)
9063 MakeArray (module, spec.Next);
9065 type = ArrayContainer.MakeType (module, type, spec.Dimension);
9068 public override string GetSignatureForError ()
9070 return left.GetSignatureForError () + spec.GetSignatureForError ();
9074 class FixedBufferPtr : Expression
9076 readonly Expression array;
9078 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
9080 this.type = array_type;
9085 public override bool ContainsEmitWithAwait ()
9087 throw new NotImplementedException ();
9090 public override Expression CreateExpressionTree (ResolveContext ec)
9092 Error_PointerInsideExpressionTree (ec);
9096 public override void Emit(EmitContext ec)
9101 protected override Expression DoResolve (ResolveContext ec)
9103 type = PointerContainer.MakeType (ec.Module, type);
9104 eclass = ExprClass.Value;
9111 // This class is used to represent the address of an array, used
9112 // only by the Fixed statement, this generates "&a [0]" construct
9113 // for fixed (char *pa = a)
9115 class ArrayPtr : FixedBufferPtr
9117 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
9118 base (array, array_type, l)
9122 public override void Emit (EmitContext ec)
9127 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
9132 // Encapsulates a conversion rules required for array indexes
9134 public class ArrayIndexCast : TypeCast
9136 public ArrayIndexCast (Expression expr, TypeSpec returnType)
9137 : base (expr, returnType)
9139 if (expr.Type == returnType) // int -> int
9140 throw new ArgumentException ("unnecessary array index conversion");
9143 public override Expression CreateExpressionTree (ResolveContext ec)
9145 using (ec.Set (ResolveContext.Options.CheckedScope)) {
9146 return base.CreateExpressionTree (ec);
9150 public override void Emit (EmitContext ec)
9154 switch (child.Type.BuiltinType) {
9155 case BuiltinTypeSpec.Type.UInt:
9156 ec.Emit (OpCodes.Conv_U);
9158 case BuiltinTypeSpec.Type.Long:
9159 ec.Emit (OpCodes.Conv_Ovf_I);
9161 case BuiltinTypeSpec.Type.ULong:
9162 ec.Emit (OpCodes.Conv_Ovf_I_Un);
9165 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9171 // Implements the `stackalloc' keyword
9173 public class StackAlloc : Expression {
9178 public StackAlloc (Expression type, Expression count, Location l)
9185 public override bool ContainsEmitWithAwait ()
9190 public override Expression CreateExpressionTree (ResolveContext ec)
9192 throw new NotSupportedException ("ET");
9195 protected override Expression DoResolve (ResolveContext ec)
9197 count = count.Resolve (ec);
9201 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
9202 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
9207 Constant c = count as Constant;
9208 if (c != null && c.IsNegative) {
9209 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9212 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9213 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9216 otype = t.ResolveAsType (ec);
9220 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
9223 type = PointerContainer.MakeType (ec.Module, otype);
9224 eclass = ExprClass.Value;
9229 public override void Emit (EmitContext ec)
9231 int size = BuiltinTypeSpec.GetSize (otype);
9236 ec.Emit (OpCodes.Sizeof, otype);
9240 ec.Emit (OpCodes.Mul_Ovf_Un);
9241 ec.Emit (OpCodes.Localloc);
9244 protected override void CloneTo (CloneContext clonectx, Expression t)
9246 StackAlloc target = (StackAlloc) t;
9247 target.count = count.Clone (clonectx);
9248 target.t = t.Clone (clonectx);
9253 // An object initializer expression
9255 public class ElementInitializer : Assign
9257 public readonly string Name;
9259 public ElementInitializer (string name, Expression initializer, Location loc)
9260 : base (null, initializer, loc)
9265 protected override void CloneTo (CloneContext clonectx, Expression t)
9267 ElementInitializer target = (ElementInitializer) t;
9268 target.source = source.Clone (clonectx);
9271 public override Expression CreateExpressionTree (ResolveContext ec)
9273 Arguments args = new Arguments (2);
9274 FieldExpr fe = target as FieldExpr;
9276 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9278 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9280 args.Add (new Argument (source.CreateExpressionTree (ec)));
9281 return CreateExpressionFactoryCall (ec,
9282 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9286 protected override Expression DoResolve (ResolveContext ec)
9289 return EmptyExpressionStatement.Instance;
9291 var t = ec.CurrentInitializerVariable.Type;
9292 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9293 Arguments args = new Arguments (1);
9294 args.Add (new Argument (ec.CurrentInitializerVariable));
9295 target = new DynamicMemberBinder (Name, args, loc);
9298 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9299 if (member == null) {
9300 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9302 if (member != null) {
9303 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
9304 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
9309 if (member == null) {
9310 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
9314 if (!(member is PropertyExpr || member is FieldExpr)) {
9315 ec.Report.Error (1913, loc,
9316 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
9317 member.GetSignatureForError ());
9322 var me = member as MemberExpr;
9324 ec.Report.Error (1914, loc,
9325 "Static field or property `{0}' cannot be assigned in an object initializer",
9326 me.GetSignatureForError ());
9330 me.InstanceExpression = ec.CurrentInitializerVariable;
9333 if (source is CollectionOrObjectInitializers) {
9334 Expression previous = ec.CurrentInitializerVariable;
9335 ec.CurrentInitializerVariable = target;
9336 source = source.Resolve (ec);
9337 ec.CurrentInitializerVariable = previous;
9341 eclass = source.eclass;
9346 return base.DoResolve (ec);
9349 public override void EmitStatement (EmitContext ec)
9351 if (source is CollectionOrObjectInitializers)
9354 base.EmitStatement (ec);
9359 // A collection initializer expression
9361 class CollectionElementInitializer : Invocation
9363 public class ElementInitializerArgument : Argument
9365 public ElementInitializerArgument (Expression e)
9371 sealed class AddMemberAccess : MemberAccess
9373 public AddMemberAccess (Expression expr, Location loc)
9374 : base (expr, "Add", loc)
9378 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9380 if (TypeManager.HasElementType (type))
9383 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9387 public CollectionElementInitializer (Expression argument)
9388 : base (null, new Arguments (1))
9390 base.arguments.Add (new ElementInitializerArgument (argument));
9391 this.loc = argument.Location;
9394 public CollectionElementInitializer (List<Expression> arguments, Location loc)
9395 : base (null, new Arguments (arguments.Count))
9397 foreach (Expression e in arguments)
9398 base.arguments.Add (new ElementInitializerArgument (e));
9403 public override Expression CreateExpressionTree (ResolveContext ec)
9405 Arguments args = new Arguments (2);
9406 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9408 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
9409 foreach (Argument a in arguments)
9410 expr_initializers.Add (a.CreateExpressionTree (ec));
9412 args.Add (new Argument (new ArrayCreation (
9413 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
9414 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9417 protected override void CloneTo (CloneContext clonectx, Expression t)
9419 CollectionElementInitializer target = (CollectionElementInitializer) t;
9420 if (arguments != null)
9421 target.arguments = arguments.Clone (clonectx);
9424 protected override Expression DoResolve (ResolveContext ec)
9426 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9428 return base.DoResolve (ec);
9433 // A block of object or collection initializers
9435 public class CollectionOrObjectInitializers : ExpressionStatement
9437 IList<Expression> initializers;
9438 bool is_collection_initialization;
9440 public static readonly CollectionOrObjectInitializers Empty =
9441 new CollectionOrObjectInitializers (Array.AsReadOnly (new Expression [0]), Location.Null);
9443 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
9445 this.initializers = initializers;
9449 public bool IsEmpty {
9451 return initializers.Count == 0;
9455 public bool IsCollectionInitializer {
9457 return is_collection_initialization;
9461 protected override void CloneTo (CloneContext clonectx, Expression target)
9463 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9465 t.initializers = new List<Expression> (initializers.Count);
9466 foreach (var e in initializers)
9467 t.initializers.Add (e.Clone (clonectx));
9470 public override bool ContainsEmitWithAwait ()
9472 foreach (var e in initializers) {
9473 if (e.ContainsEmitWithAwait ())
9480 public override Expression CreateExpressionTree (ResolveContext ec)
9482 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
9483 foreach (Expression e in initializers) {
9484 Expression expr = e.CreateExpressionTree (ec);
9486 expr_initializers.Add (expr);
9489 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
9492 protected override Expression DoResolve (ResolveContext ec)
9494 List<string> element_names = null;
9495 for (int i = 0; i < initializers.Count; ++i) {
9496 Expression initializer = initializers [i];
9497 ElementInitializer element_initializer = initializer as ElementInitializer;
9500 if (element_initializer != null) {
9501 element_names = new List<string> (initializers.Count);
9502 element_names.Add (element_initializer.Name);
9503 } else if (initializer is CompletingExpression){
9504 initializer.Resolve (ec);
9505 throw new InternalErrorException ("This line should never be reached");
9507 var t = ec.CurrentInitializerVariable.Type;
9508 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
9509 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
9510 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9511 "object initializer because type `{1}' does not implement `{2}' interface",
9512 ec.CurrentInitializerVariable.GetSignatureForError (),
9513 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9514 TypeManager.CSharpName (ec.BuiltinTypes.IEnumerable));
9517 is_collection_initialization = true;
9520 if (is_collection_initialization != (element_initializer == null)) {
9521 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9522 is_collection_initialization ? "collection initializer" : "object initializer");
9526 if (!is_collection_initialization) {
9527 if (element_names.Contains (element_initializer.Name)) {
9528 ec.Report.Error (1912, element_initializer.Location,
9529 "An object initializer includes more than one member `{0}' initialization",
9530 element_initializer.Name);
9532 element_names.Add (element_initializer.Name);
9537 Expression e = initializer.Resolve (ec);
9538 if (e == EmptyExpressionStatement.Instance)
9539 initializers.RemoveAt (i--);
9541 initializers [i] = e;
9544 type = ec.CurrentInitializerVariable.Type;
9545 if (is_collection_initialization) {
9546 if (TypeManager.HasElementType (type)) {
9547 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9548 TypeManager.CSharpName (type));
9552 eclass = ExprClass.Variable;
9556 public override void Emit (EmitContext ec)
9561 public override void EmitStatement (EmitContext ec)
9563 foreach (ExpressionStatement e in initializers)
9564 e.EmitStatement (ec);
9569 // New expression with element/object initializers
9571 public class NewInitialize : New
9574 // This class serves as a proxy for variable initializer target instances.
9575 // A real variable is assigned later when we resolve left side of an
9578 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9580 NewInitialize new_instance;
9582 public InitializerTargetExpression (NewInitialize newInstance)
9584 this.type = newInstance.type;
9585 this.loc = newInstance.loc;
9586 this.eclass = newInstance.eclass;
9587 this.new_instance = newInstance;
9590 public override bool ContainsEmitWithAwait ()
9595 public override Expression CreateExpressionTree (ResolveContext ec)
9597 // Should not be reached
9598 throw new NotSupportedException ("ET");
9601 protected override Expression DoResolve (ResolveContext ec)
9606 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9611 public override void Emit (EmitContext ec)
9613 Expression e = (Expression) new_instance.instance;
9617 public override Expression EmitToField (EmitContext ec)
9619 return (Expression) new_instance.instance;
9622 #region IMemoryLocation Members
9624 public void AddressOf (EmitContext ec, AddressOp mode)
9626 new_instance.instance.AddressOf (ec, mode);
9632 CollectionOrObjectInitializers initializers;
9633 IMemoryLocation instance;
9635 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9636 : base (requested_type, arguments, l)
9638 this.initializers = initializers;
9641 protected override void CloneTo (CloneContext clonectx, Expression t)
9643 base.CloneTo (clonectx, t);
9645 NewInitialize target = (NewInitialize) t;
9646 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9649 public override bool ContainsEmitWithAwait ()
9651 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
9654 public override Expression CreateExpressionTree (ResolveContext ec)
9656 Arguments args = new Arguments (2);
9657 args.Add (new Argument (base.CreateExpressionTree (ec)));
9658 if (!initializers.IsEmpty)
9659 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9661 return CreateExpressionFactoryCall (ec,
9662 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9666 protected override Expression DoResolve (ResolveContext ec)
9668 Expression e = base.DoResolve (ec);
9672 Expression previous = ec.CurrentInitializerVariable;
9673 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9674 initializers.Resolve (ec);
9675 ec.CurrentInitializerVariable = previous;
9679 public override bool Emit (EmitContext ec, IMemoryLocation target)
9681 bool left_on_stack = base.Emit (ec, target);
9683 if (initializers.IsEmpty)
9684 return left_on_stack;
9686 LocalTemporary temp = null;
9688 instance = target as LocalTemporary;
9690 if (instance == null) {
9691 if (!left_on_stack) {
9692 VariableReference vr = target as VariableReference;
9694 // FIXME: This still does not work correctly for pre-set variables
9695 if (vr != null && vr.IsRef)
9696 target.AddressOf (ec, AddressOp.Load);
9698 ((Expression) target).Emit (ec);
9699 left_on_stack = true;
9702 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
9703 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
9705 temp = new LocalTemporary (type);
9710 if (left_on_stack && temp != null)
9713 initializers.Emit (ec);
9715 if (left_on_stack) {
9720 ((Expression) instance).Emit (ec);
9724 return left_on_stack;
9727 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9729 instance = base.EmitAddressOf (ec, Mode);
9731 if (!initializers.IsEmpty)
9732 initializers.Emit (ec);
9738 public class NewAnonymousType : New
9740 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
9742 List<AnonymousTypeParameter> parameters;
9743 readonly TypeContainer parent;
9744 AnonymousTypeClass anonymous_type;
9746 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
9747 : base (null, null, loc)
9749 this.parameters = parameters;
9750 this.parent = parent;
9753 protected override void CloneTo (CloneContext clonectx, Expression target)
9755 if (parameters == null)
9758 NewAnonymousType t = (NewAnonymousType) target;
9759 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
9760 foreach (AnonymousTypeParameter atp in parameters)
9761 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
9764 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
9766 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
9770 type = AnonymousTypeClass.Create (parent, parameters, loc);
9776 type.ResolveTypeParameters ();
9779 if (ec.Report.Errors == 0)
9782 parent.Module.AddAnonymousType (type);
9786 public override Expression CreateExpressionTree (ResolveContext ec)
9788 if (parameters == null)
9789 return base.CreateExpressionTree (ec);
9791 var init = new ArrayInitializer (parameters.Count, loc);
9792 foreach (Property p in anonymous_type.Properties)
9793 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
9795 var ctor_args = new ArrayInitializer (arguments.Count, loc);
9796 foreach (Argument a in arguments)
9797 ctor_args.Add (a.CreateExpressionTree (ec));
9799 Arguments args = new Arguments (3);
9800 args.Add (new Argument (new TypeOfMethod (method, loc)));
9801 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
9802 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
9804 return CreateExpressionFactoryCall (ec, "New", args);
9807 protected override Expression DoResolve (ResolveContext ec)
9809 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
9810 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9814 if (parameters == null) {
9815 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
9816 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
9817 return base.DoResolve (ec);
9821 arguments = new Arguments (parameters.Count);
9822 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9823 for (int i = 0; i < parameters.Count; ++i) {
9824 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9830 arguments.Add (new Argument (e));
9831 t_args [i] = new TypeExpression (e.Type, e.Location);
9837 anonymous_type = CreateAnonymousType (ec, parameters);
9838 if (anonymous_type == null)
9841 RequestedType = new GenericTypeExpr (anonymous_type.Definition, new TypeArguments (t_args), loc);
9842 return base.DoResolve (ec);
9846 public class AnonymousTypeParameter : ShimExpression
9848 public readonly string Name;
9850 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9851 : base (initializer)
9857 public AnonymousTypeParameter (Parameter parameter)
9858 : base (new SimpleName (parameter.Name, parameter.Location))
9860 this.Name = parameter.Name;
9861 this.loc = parameter.Location;
9864 public override bool Equals (object o)
9866 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9867 return other != null && Name == other.Name;
9870 public override int GetHashCode ()
9872 return Name.GetHashCode ();
9875 protected override Expression DoResolve (ResolveContext ec)
9877 Expression e = expr.Resolve (ec);
9881 if (e.eclass == ExprClass.MethodGroup) {
9882 Error_InvalidInitializer (ec, e.ExprClassName);
9887 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
9888 Error_InvalidInitializer (ec, e.GetSignatureForError ());
9895 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
9897 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",