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.
13 using System.Collections.Generic;
15 using SLE = System.Linq.Expressions;
18 using MetaType = IKVM.Reflection.Type;
19 using IKVM.Reflection;
20 using IKVM.Reflection.Emit;
22 using MetaType = System.Type;
23 using System.Reflection;
24 using System.Reflection.Emit;
30 // This is an user operator expression, automatically created during
33 public class UserOperatorCall : Expression {
34 protected readonly Arguments arguments;
35 protected readonly MethodSpec oper;
36 readonly Func<ResolveContext, Expression, Expression> expr_tree;
38 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
41 this.arguments = args;
42 this.expr_tree = expr_tree;
44 type = oper.ReturnType;
45 eclass = ExprClass.Value;
49 public override bool ContainsEmitWithAwait ()
51 return arguments.ContainsEmitWithAwait ();
54 public override Expression CreateExpressionTree (ResolveContext ec)
56 if (expr_tree != null)
57 return expr_tree (ec, new TypeOfMethod (oper, loc));
59 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
60 new NullLiteral (loc),
61 new TypeOfMethod (oper, loc));
63 return CreateExpressionFactoryCall (ec, "Call", args);
66 protected override void CloneTo (CloneContext context, Expression target)
71 protected override Expression DoResolve (ResolveContext ec)
74 // We are born fully resolved
79 public override void Emit (EmitContext ec)
81 var call = new CallEmitter ();
82 call.EmitPredefined (ec, oper, arguments);
85 public override SLE.Expression MakeExpression (BuilderContext ctx)
88 return base.MakeExpression (ctx);
90 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
95 public class ParenthesizedExpression : ShimExpression
97 public ParenthesizedExpression (Expression expr)
103 protected override Expression DoResolve (ResolveContext ec)
105 return expr.Resolve (ec);
108 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
110 return expr.DoResolveLValue (ec, right_side);
115 // Unary implements unary expressions.
117 public class Unary : Expression
119 public enum Operator : byte {
120 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
124 public readonly Operator Oper;
125 public Expression Expr;
126 Expression enum_conversion;
128 public Unary (Operator op, Expression expr, Location loc)
136 // This routine will attempt to simplify the unary expression when the
137 // argument is a constant.
139 Constant TryReduceConstant (ResolveContext ec, Constant e)
141 if (e is EmptyConstantCast)
142 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
144 if (e is SideEffectConstant) {
145 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
146 return r == null ? null : new SideEffectConstant (r, e, r.Location);
149 TypeSpec expr_type = e.Type;
152 case Operator.UnaryPlus:
153 // Unary numeric promotions
154 switch (expr_type.BuiltinType) {
155 case BuiltinTypeSpec.Type.Byte:
156 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
157 case BuiltinTypeSpec.Type.SByte:
158 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
159 case BuiltinTypeSpec.Type.Short:
160 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
161 case BuiltinTypeSpec.Type.UShort:
162 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
163 case BuiltinTypeSpec.Type.Char:
164 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
166 // Predefined operators
167 case BuiltinTypeSpec.Type.Int:
168 case BuiltinTypeSpec.Type.UInt:
169 case BuiltinTypeSpec.Type.Long:
170 case BuiltinTypeSpec.Type.ULong:
171 case BuiltinTypeSpec.Type.Float:
172 case BuiltinTypeSpec.Type.Double:
173 case BuiltinTypeSpec.Type.Decimal:
179 case Operator.UnaryNegation:
180 // Unary numeric promotions
181 switch (expr_type.BuiltinType) {
182 case BuiltinTypeSpec.Type.Byte:
183 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
184 case BuiltinTypeSpec.Type.SByte:
185 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
186 case BuiltinTypeSpec.Type.Short:
187 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
188 case BuiltinTypeSpec.Type.UShort:
189 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
190 case BuiltinTypeSpec.Type.Char:
191 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
193 // Predefined operators
194 case BuiltinTypeSpec.Type.Int:
195 int ivalue = ((IntConstant) e).Value;
196 if (ivalue == int.MinValue) {
197 if (ec.ConstantCheckState) {
198 ConstantFold.Error_CompileTimeOverflow (ec, loc);
203 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
205 case BuiltinTypeSpec.Type.Long:
206 long lvalue = ((LongConstant) e).Value;
207 if (lvalue == long.MinValue) {
208 if (ec.ConstantCheckState) {
209 ConstantFold.Error_CompileTimeOverflow (ec, loc);
214 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
216 case BuiltinTypeSpec.Type.UInt:
217 UIntLiteral uil = e as UIntLiteral;
219 if (uil.Value == int.MaxValue + (uint) 1)
220 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
221 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
223 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
226 case BuiltinTypeSpec.Type.ULong:
227 ULongLiteral ull = e as ULongLiteral;
228 if (ull != null && ull.Value == 9223372036854775808)
229 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
232 case BuiltinTypeSpec.Type.Float:
233 FloatLiteral fl = e as FloatLiteral;
234 // For better error reporting
236 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
238 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
240 case BuiltinTypeSpec.Type.Double:
241 DoubleLiteral dl = e as DoubleLiteral;
242 // For better error reporting
244 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
246 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
248 case BuiltinTypeSpec.Type.Decimal:
249 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
254 case Operator.LogicalNot:
255 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
258 bool b = (bool)e.GetValue ();
259 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
261 case Operator.OnesComplement:
262 // Unary numeric promotions
263 switch (expr_type.BuiltinType) {
264 case BuiltinTypeSpec.Type.Byte:
265 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
266 case BuiltinTypeSpec.Type.SByte:
267 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
268 case BuiltinTypeSpec.Type.Short:
269 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
270 case BuiltinTypeSpec.Type.UShort:
271 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
272 case BuiltinTypeSpec.Type.Char:
273 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
275 // Predefined operators
276 case BuiltinTypeSpec.Type.Int:
277 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
278 case BuiltinTypeSpec.Type.UInt:
279 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
280 case BuiltinTypeSpec.Type.Long:
281 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
282 case BuiltinTypeSpec.Type.ULong:
283 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
285 if (e is EnumConstant) {
286 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
288 e = new EnumConstant (e, expr_type);
293 throw new Exception ("Can not constant fold: " + Oper.ToString());
296 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
298 eclass = ExprClass.Value;
300 TypeSpec expr_type = expr.Type;
301 Expression best_expr;
303 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
306 // Primitive types first
308 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
309 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
310 if (best_expr == null)
313 type = best_expr.Type;
319 // E operator ~(E x);
321 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
322 return ResolveEnumOperator (ec, expr, predefined);
324 return ResolveUserType (ec, expr, predefined);
327 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
329 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
330 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
331 if (best_expr == null)
335 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (best_expr.Type), underlying_type);
337 return EmptyCast.Create (this, type);
340 public override bool ContainsEmitWithAwait ()
342 return Expr.ContainsEmitWithAwait ();
345 public override Expression CreateExpressionTree (ResolveContext ec)
347 return CreateExpressionTree (ec, null);
350 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
354 case Operator.AddressOf:
355 Error_PointerInsideExpressionTree (ec);
357 case Operator.UnaryNegation:
358 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
359 method_name = "NegateChecked";
361 method_name = "Negate";
363 case Operator.OnesComplement:
364 case Operator.LogicalNot:
367 case Operator.UnaryPlus:
368 method_name = "UnaryPlus";
371 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
374 Arguments args = new Arguments (2);
375 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
377 args.Add (new Argument (user_op));
379 return CreateExpressionFactoryCall (ec, method_name, args);
382 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
384 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
387 // 7.6.1 Unary plus operator
389 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
390 types.Int, types.UInt,
391 types.Long, types.ULong,
392 types.Float, types.Double,
397 // 7.6.2 Unary minus operator
399 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
400 types.Int, types.Long,
401 types.Float, types.Double,
406 // 7.6.3 Logical negation operator
408 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
413 // 7.6.4 Bitwise complement operator
415 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
416 types.Int, types.UInt,
417 types.Long, types.ULong
420 return predefined_operators;
424 // Unary numeric promotions
426 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
428 TypeSpec expr_type = expr.Type;
429 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
430 switch (expr_type.BuiltinType) {
431 case BuiltinTypeSpec.Type.Byte:
432 case BuiltinTypeSpec.Type.SByte:
433 case BuiltinTypeSpec.Type.Short:
434 case BuiltinTypeSpec.Type.UShort:
435 case BuiltinTypeSpec.Type.Char:
436 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
440 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
441 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
446 protected override Expression DoResolve (ResolveContext ec)
448 if (Oper == Operator.AddressOf) {
449 return ResolveAddressOf (ec);
452 Expr = Expr.Resolve (ec);
456 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
457 Arguments args = new Arguments (1);
458 args.Add (new Argument (Expr));
459 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
462 if (Expr.Type.IsNullableType)
463 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
466 // Attempt to use a constant folding operation.
468 Constant cexpr = Expr as Constant;
470 cexpr = TryReduceConstant (ec, cexpr);
475 Expression expr = ResolveOperator (ec, Expr);
477 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
480 // Reduce unary operator on predefined types
482 if (expr == this && Oper == Operator.UnaryPlus)
488 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
493 public override void Emit (EmitContext ec)
495 EmitOperator (ec, type);
498 protected void EmitOperator (EmitContext ec, TypeSpec type)
501 case Operator.UnaryPlus:
505 case Operator.UnaryNegation:
506 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
507 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
508 Expr = Expr.EmitToField (ec);
511 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
512 ec.Emit (OpCodes.Conv_U8);
514 ec.Emit (OpCodes.Sub_Ovf);
517 ec.Emit (OpCodes.Neg);
522 case Operator.LogicalNot:
525 ec.Emit (OpCodes.Ceq);
528 case Operator.OnesComplement:
530 ec.Emit (OpCodes.Not);
533 case Operator.AddressOf:
534 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
538 throw new Exception ("This should not happen: Operator = "
543 // Same trick as in Binary expression
545 if (enum_conversion != null)
546 enum_conversion.Emit (ec);
549 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
551 if (Oper == Operator.LogicalNot)
552 Expr.EmitBranchable (ec, target, !on_true);
554 base.EmitBranchable (ec, target, on_true);
557 public override void EmitSideEffect (EmitContext ec)
559 Expr.EmitSideEffect (ec);
562 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Location loc, string oper, TypeSpec t)
564 ec.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
565 oper, TypeManager.CSharpName (t));
569 // Converts operator to System.Linq.Expressions.ExpressionType enum name
571 string GetOperatorExpressionTypeName ()
574 case Operator.OnesComplement:
575 return "OnesComplement";
576 case Operator.LogicalNot:
578 case Operator.UnaryNegation:
580 case Operator.UnaryPlus:
583 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
587 static bool IsFloat (TypeSpec t)
589 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
593 // Returns a stringified representation of the Operator
595 public static string OperName (Operator oper)
598 case Operator.UnaryPlus:
600 case Operator.UnaryNegation:
602 case Operator.LogicalNot:
604 case Operator.OnesComplement:
606 case Operator.AddressOf:
610 throw new NotImplementedException (oper.ToString ());
613 public override SLE.Expression MakeExpression (BuilderContext ctx)
615 var expr = Expr.MakeExpression (ctx);
616 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
619 case Operator.UnaryNegation:
620 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
621 case Operator.LogicalNot:
622 return SLE.Expression.Not (expr);
624 case Operator.OnesComplement:
625 return SLE.Expression.OnesComplement (expr);
628 throw new NotImplementedException (Oper.ToString ());
632 Expression ResolveAddressOf (ResolveContext ec)
635 UnsafeError (ec, loc);
637 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
638 if (Expr == null || Expr.eclass != ExprClass.Variable) {
639 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
643 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
647 IVariableReference vr = Expr as IVariableReference;
650 VariableInfo vi = vr.VariableInfo;
652 if (vi.LocalInfo != null)
653 vi.LocalInfo.SetIsUsed ();
656 // A variable is considered definitely assigned if you take its address.
661 is_fixed = vr.IsFixed;
662 vr.SetHasAddressTaken ();
665 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
668 IFixedExpression fe = Expr as IFixedExpression;
669 is_fixed = fe != null && fe.IsFixed;
672 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
673 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
676 type = PointerContainer.MakeType (ec.Module, Expr.Type);
677 eclass = ExprClass.Value;
681 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
683 expr = DoNumericPromotion (rc, Oper, expr);
684 TypeSpec expr_type = expr.Type;
685 foreach (TypeSpec t in predefined) {
693 // Perform user-operator overload resolution
695 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
697 CSharp.Operator.OpType op_type;
699 case Operator.LogicalNot:
700 op_type = CSharp.Operator.OpType.LogicalNot; break;
701 case Operator.OnesComplement:
702 op_type = CSharp.Operator.OpType.OnesComplement; break;
703 case Operator.UnaryNegation:
704 op_type = CSharp.Operator.OpType.UnaryNegation; break;
705 case Operator.UnaryPlus:
706 op_type = CSharp.Operator.OpType.UnaryPlus; break;
708 throw new InternalErrorException (Oper.ToString ());
711 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
715 Arguments args = new Arguments (1);
716 args.Add (new Argument (expr));
718 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
719 var oper = res.ResolveOperator (ec, ref args);
724 Expr = args [0].Expr;
725 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
729 // Unary user type overload resolution
731 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
733 Expression best_expr = ResolveUserOperator (ec, expr);
734 if (best_expr != null)
737 foreach (TypeSpec t in predefined) {
738 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
739 if (oper_expr == null)
742 if (oper_expr == ErrorExpression.Instance)
746 // decimal type is predefined but has user-operators
748 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
749 oper_expr = ResolveUserType (ec, oper_expr, predefined);
751 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
753 if (oper_expr == null)
756 if (best_expr == null) {
757 best_expr = oper_expr;
761 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
763 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
764 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
765 OperName (Oper), expr.Type.GetSignatureForError ());
767 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
774 best_expr = oper_expr;
777 if (best_expr == null)
781 // HACK: Decimal user-operator is included in standard operators
783 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
787 type = best_expr.Type;
791 protected override void CloneTo (CloneContext clonectx, Expression t)
793 Unary target = (Unary) t;
795 target.Expr = Expr.Clone (clonectx);
800 // Unary operators are turned into Indirection expressions
801 // after semantic analysis (this is so we can take the address
802 // of an indirection).
804 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
806 LocalTemporary temporary;
809 public Indirection (Expression expr, Location l)
815 public bool IsFixed {
819 protected override void CloneTo (CloneContext clonectx, Expression t)
821 Indirection target = (Indirection) t;
822 target.expr = expr.Clone (clonectx);
825 public override bool ContainsEmitWithAwait ()
827 throw new NotImplementedException ();
830 public override Expression CreateExpressionTree (ResolveContext ec)
832 Error_PointerInsideExpressionTree (ec);
836 public override void Emit (EmitContext ec)
841 ec.EmitLoadFromPtr (Type);
844 public void Emit (EmitContext ec, bool leave_copy)
848 ec.Emit (OpCodes.Dup);
849 temporary = new LocalTemporary (expr.Type);
850 temporary.Store (ec);
854 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
856 prepared = isCompound;
861 ec.Emit (OpCodes.Dup);
865 ec.Emit (OpCodes.Dup);
866 temporary = new LocalTemporary (source.Type);
867 temporary.Store (ec);
870 ec.EmitStoreFromPtr (type);
872 if (temporary != null) {
874 temporary.Release (ec);
878 public void AddressOf (EmitContext ec, AddressOp Mode)
883 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
885 return DoResolve (ec);
888 protected override Expression DoResolve (ResolveContext ec)
890 expr = expr.Resolve (ec);
895 UnsafeError (ec, loc);
897 var pc = expr.Type as PointerContainer;
900 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
906 if (type.Kind == MemberKind.Void) {
907 Error_VoidPointerOperation (ec);
911 eclass = ExprClass.Variable;
917 /// Unary Mutator expressions (pre and post ++ and --)
921 /// UnaryMutator implements ++ and -- expressions. It derives from
922 /// ExpressionStatement becuase the pre/post increment/decrement
923 /// operators can be used in a statement context.
925 /// FIXME: Idea, we could split this up in two classes, one simpler
926 /// for the common case, and one with the extra fields for more complex
927 /// classes (indexers require temporary access; overloaded require method)
930 public class UnaryMutator : ExpressionStatement
932 class DynamicPostMutator : Expression, IAssignMethod
937 public DynamicPostMutator (Expression expr)
940 this.type = expr.Type;
941 this.loc = expr.Location;
944 public override Expression CreateExpressionTree (ResolveContext ec)
946 throw new NotImplementedException ("ET");
949 protected override Expression DoResolve (ResolveContext rc)
951 eclass = expr.eclass;
955 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
957 expr.DoResolveLValue (ec, right_side);
958 return DoResolve (ec);
961 public override void Emit (EmitContext ec)
966 public void Emit (EmitContext ec, bool leave_copy)
968 throw new NotImplementedException ();
972 // Emits target assignment using unmodified source value
974 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
977 // Allocate temporary variable to keep original value before it's modified
979 temp = new LocalTemporary (type);
983 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
994 public enum Mode : byte {
1001 PreDecrement = IsDecrement,
1002 PostIncrement = IsPost,
1003 PostDecrement = IsPost | IsDecrement
1007 bool is_expr, recurse;
1009 protected Expression expr;
1011 // Holds the real operation
1012 Expression operation;
1014 public UnaryMutator (Mode m, Expression e, Location loc)
1021 public override bool ContainsEmitWithAwait ()
1023 return expr.ContainsEmitWithAwait ();
1026 public override Expression CreateExpressionTree (ResolveContext ec)
1028 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1031 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1034 // Predefined ++ and -- operators exist for the following types:
1035 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1037 return new TypeSpec[] {
1053 protected override Expression DoResolve (ResolveContext ec)
1055 expr = expr.Resolve (ec);
1060 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1062 // Handle postfix unary operators using local
1063 // temporary variable
1065 if ((mode & Mode.IsPost) != 0)
1066 expr = new DynamicPostMutator (expr);
1068 Arguments args = new Arguments (1);
1069 args.Add (new Argument (expr));
1070 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1073 if (expr.Type.IsNullableType)
1074 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1076 return DoResolveOperation (ec);
1079 protected Expression DoResolveOperation (ResolveContext ec)
1081 eclass = ExprClass.Value;
1084 if (expr is RuntimeValueExpression) {
1087 // Use itself at the top of the stack
1088 operation = new EmptyExpression (type);
1092 // The operand of the prefix/postfix increment decrement operators
1093 // should be an expression that is classified as a variable,
1094 // a property access or an indexer access
1096 // TODO: Move to parser, expr is ATypeNameExpression
1097 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1098 expr = expr.ResolveLValue (ec, expr);
1100 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1104 // Step 1: Try to find a user operator, it has priority over predefined ones
1106 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1107 var methods = MemberCache.GetUserOperator (type, user_op, false);
1109 if (methods != null) {
1110 Arguments args = new Arguments (1);
1111 args.Add (new Argument (expr));
1113 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1114 var method = res.ResolveOperator (ec, ref args);
1118 args[0].Expr = operation;
1119 operation = new UserOperatorCall (method, args, null, loc);
1120 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1125 // Step 2: Try predefined types
1128 Expression source = null;
1129 bool primitive_type;
1132 // Predefined without user conversion first for speed-up
1134 // Predefined ++ and -- operators exist for the following types:
1135 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1137 switch (type.BuiltinType) {
1138 case BuiltinTypeSpec.Type.Byte:
1139 case BuiltinTypeSpec.Type.SByte:
1140 case BuiltinTypeSpec.Type.Short:
1141 case BuiltinTypeSpec.Type.UShort:
1142 case BuiltinTypeSpec.Type.Int:
1143 case BuiltinTypeSpec.Type.UInt:
1144 case BuiltinTypeSpec.Type.Long:
1145 case BuiltinTypeSpec.Type.ULong:
1146 case BuiltinTypeSpec.Type.Char:
1147 case BuiltinTypeSpec.Type.Float:
1148 case BuiltinTypeSpec.Type.Double:
1149 case BuiltinTypeSpec.Type.Decimal:
1151 primitive_type = true;
1154 primitive_type = false;
1156 // ++/-- on pointer variables of all types except void*
1157 if (type.IsPointer) {
1158 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1159 Error_VoidPointerOperation (ec);
1165 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1166 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1168 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1169 if (source != null) {
1175 // ++/-- on enum types
1176 if (source == null && type.IsEnum)
1179 if (source == null) {
1180 Unary.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1187 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1188 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1189 operation = new Binary (op, source, one, loc);
1190 operation = operation.Resolve (ec);
1191 if (operation == null)
1192 throw new NotImplementedException ("should not be reached");
1194 if (operation.Type != type) {
1196 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1198 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1204 void EmitCode (EmitContext ec, bool is_expr)
1207 this.is_expr = is_expr;
1208 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1211 public override void Emit (EmitContext ec)
1214 // We use recurse to allow ourselfs to be the source
1215 // of an assignment. This little hack prevents us from
1216 // having to allocate another expression
1219 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1227 EmitCode (ec, true);
1230 protected virtual void EmitOperation (EmitContext ec)
1232 operation.Emit (ec);
1235 public override void EmitStatement (EmitContext ec)
1237 EmitCode (ec, false);
1241 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1243 string GetOperatorExpressionTypeName ()
1245 return IsDecrement ? "Decrement" : "Increment";
1249 get { return (mode & Mode.IsDecrement) != 0; }
1254 public override SLE.Expression MakeExpression (BuilderContext ctx)
1256 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1257 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1258 return SLE.Expression.Assign (target, source);
1262 protected override void CloneTo (CloneContext clonectx, Expression t)
1264 UnaryMutator target = (UnaryMutator) t;
1266 target.expr = expr.Clone (clonectx);
1271 // Base class for the `is' and `as' operators
1273 public abstract class Probe : Expression
1275 public Expression ProbeType;
1276 protected Expression expr;
1277 protected TypeSpec probe_type_expr;
1279 public Probe (Expression expr, Expression probe_type, Location l)
1281 ProbeType = probe_type;
1286 public Expression Expr {
1292 public override bool ContainsEmitWithAwait ()
1294 return expr.ContainsEmitWithAwait ();
1297 protected override Expression DoResolve (ResolveContext ec)
1299 probe_type_expr = ProbeType.ResolveAsType (ec);
1300 if (probe_type_expr == null)
1303 expr = expr.Resolve (ec);
1307 if (probe_type_expr.IsStatic) {
1308 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1312 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1313 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1318 if (expr.Type == InternalType.AnonymousMethod) {
1319 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1327 protected abstract string OperatorName { get; }
1329 protected override void CloneTo (CloneContext clonectx, Expression t)
1331 Probe target = (Probe) t;
1333 target.expr = expr.Clone (clonectx);
1334 target.ProbeType = ProbeType.Clone (clonectx);
1340 /// Implementation of the `is' operator.
1342 public class Is : Probe
1344 Nullable.Unwrap expr_unwrap;
1346 public Is (Expression expr, Expression probe_type, Location l)
1347 : base (expr, probe_type, l)
1351 public override Expression CreateExpressionTree (ResolveContext ec)
1353 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1354 expr.CreateExpressionTree (ec),
1355 new TypeOf (probe_type_expr, loc));
1357 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1360 public override void Emit (EmitContext ec)
1362 if (expr_unwrap != null) {
1363 expr_unwrap.EmitCheck (ec);
1369 // Only to make verifier happy
1370 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1371 ec.Emit (OpCodes.Box, expr.Type);
1373 ec.Emit (OpCodes.Isinst, probe_type_expr);
1375 ec.Emit (OpCodes.Cgt_Un);
1378 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1380 if (expr_unwrap != null) {
1381 expr_unwrap.EmitCheck (ec);
1384 ec.Emit (OpCodes.Isinst, probe_type_expr);
1386 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1389 Expression CreateConstantResult (ResolveContext ec, bool result)
1392 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1393 TypeManager.CSharpName (probe_type_expr));
1395 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1396 TypeManager.CSharpName (probe_type_expr));
1398 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, result, loc), this);
1401 protected override Expression DoResolve (ResolveContext ec)
1403 if (base.DoResolve (ec) == null)
1406 TypeSpec d = expr.Type;
1407 bool d_is_nullable = false;
1410 // If E is a method group or the null literal, or if the type of E is a reference
1411 // type or a nullable type and the value of E is null, the result is false
1413 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1414 return CreateConstantResult (ec, false);
1416 if (d.IsNullableType) {
1417 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1418 if (!ut.IsGenericParameter) {
1420 d_is_nullable = true;
1424 type = ec.BuiltinTypes.Bool;
1425 eclass = ExprClass.Value;
1426 TypeSpec t = probe_type_expr;
1427 bool t_is_nullable = false;
1428 if (t.IsNullableType) {
1429 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1430 if (!ut.IsGenericParameter) {
1432 t_is_nullable = true;
1439 // D and T are the same value types but D can be null
1441 if (d_is_nullable && !t_is_nullable) {
1442 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1447 // The result is true if D and T are the same value types
1449 return CreateConstantResult (ec, true);
1452 var tp = d as TypeParameterSpec;
1454 return ResolveGenericParameter (ec, t, tp);
1457 // An unboxing conversion exists
1459 if (Convert.ExplicitReferenceConversionExists (d, t))
1462 if (TypeManager.IsGenericParameter (t))
1463 return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
1465 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1466 ec.Report.Warning (1981, 3, loc,
1467 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1468 OperatorName, t.GetSignatureForError ());
1471 if (TypeManager.IsGenericParameter (d))
1472 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1474 if (TypeSpec.IsValueType (d)) {
1475 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1476 if (d_is_nullable && !t_is_nullable) {
1477 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1481 return CreateConstantResult (ec, true);
1484 // if (InflatedTypeSpec.ContainsTypeParameter (d))
1487 if (Convert.ImplicitReferenceConversionExists (d, t) ||
1488 Convert.ExplicitReferenceConversionExists (d, t)) {
1494 return CreateConstantResult (ec, false);
1497 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1499 if (t.IsReferenceType) {
1501 return CreateConstantResult (ec, false);
1504 if (TypeManager.IsGenericParameter (expr.Type)) {
1505 if (expr.Type == d && TypeSpec.IsValueType (t))
1506 return CreateConstantResult (ec, true);
1508 expr = new BoxedCast (expr, d);
1514 protected override string OperatorName {
1515 get { return "is"; }
1520 /// Implementation of the `as' operator.
1522 public class As : Probe {
1523 Expression resolved_type;
1525 public As (Expression expr, Expression probe_type, Location l)
1526 : base (expr, probe_type, l)
1530 public override Expression CreateExpressionTree (ResolveContext ec)
1532 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1533 expr.CreateExpressionTree (ec),
1534 new TypeOf (probe_type_expr, loc));
1536 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1539 public override void Emit (EmitContext ec)
1543 ec.Emit (OpCodes.Isinst, type);
1545 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1546 ec.Emit (OpCodes.Unbox_Any, type);
1549 protected override Expression DoResolve (ResolveContext ec)
1551 if (resolved_type == null) {
1552 resolved_type = base.DoResolve (ec);
1554 if (resolved_type == null)
1558 type = probe_type_expr;
1559 eclass = ExprClass.Value;
1560 TypeSpec etype = expr.Type;
1562 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1563 if (TypeManager.IsGenericParameter (type)) {
1564 ec.Report.Error (413, loc,
1565 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1566 probe_type_expr.GetSignatureForError ());
1568 ec.Report.Error (77, loc,
1569 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1570 TypeManager.CSharpName (type));
1575 if (expr.IsNull && type.IsNullableType) {
1576 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1579 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1580 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1584 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1586 e = EmptyCast.Create (e, type);
1587 return ReducedExpression.Create (e, this).Resolve (ec);
1590 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1591 if (TypeManager.IsGenericParameter (etype))
1592 expr = new BoxedCast (expr, etype);
1597 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1598 expr = new BoxedCast (expr, etype);
1602 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1603 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1608 protected override string OperatorName {
1609 get { return "as"; }
1614 // This represents a typecast in the source language.
1616 public class Cast : ShimExpression {
1617 Expression target_type;
1619 public Cast (Expression cast_type, Expression expr, Location loc)
1622 this.target_type = cast_type;
1626 public Expression TargetType {
1627 get { return target_type; }
1630 protected override Expression DoResolve (ResolveContext ec)
1632 expr = expr.Resolve (ec);
1636 type = target_type.ResolveAsType (ec);
1640 if (type.IsStatic) {
1641 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1645 eclass = ExprClass.Value;
1647 Constant c = expr as Constant;
1649 c = c.TryReduce (ec, type, loc);
1654 if (type.IsPointer && !ec.IsUnsafe) {
1655 UnsafeError (ec, loc);
1658 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1660 return EmptyCast.Create (res, type);
1665 protected override void CloneTo (CloneContext clonectx, Expression t)
1667 Cast target = (Cast) t;
1669 target.target_type = target_type.Clone (clonectx);
1670 target.expr = expr.Clone (clonectx);
1674 public class ImplicitCast : ShimExpression
1678 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1681 this.loc = expr.Location;
1683 this.arrayAccess = arrayAccess;
1686 protected override Expression DoResolve (ResolveContext ec)
1688 expr = expr.Resolve (ec);
1693 expr = ConvertExpressionToArrayIndex (ec, expr);
1695 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1702 // C# 2.0 Default value expression
1704 public class DefaultValueExpression : Expression
1708 public DefaultValueExpression (Expression expr, Location loc)
1714 public override bool IsSideEffectFree {
1720 public override bool ContainsEmitWithAwait ()
1725 public override Expression CreateExpressionTree (ResolveContext ec)
1727 Arguments args = new Arguments (2);
1728 args.Add (new Argument (this));
1729 args.Add (new Argument (new TypeOf (type, loc)));
1730 return CreateExpressionFactoryCall (ec, "Constant", args);
1733 protected override Expression DoResolve (ResolveContext ec)
1735 type = expr.ResolveAsType (ec);
1739 if (type.IsStatic) {
1740 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1744 return new NullLiteral (Location).ConvertImplicitly (type);
1746 if (TypeSpec.IsReferenceType (type))
1747 return new NullConstant (type, loc);
1749 Constant c = New.Constantify (type, expr.Location);
1753 eclass = ExprClass.Variable;
1757 public override void Emit (EmitContext ec)
1759 LocalTemporary temp_storage = new LocalTemporary(type);
1761 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1762 ec.Emit(OpCodes.Initobj, type);
1763 temp_storage.Emit(ec);
1764 temp_storage.Release (ec);
1767 #if NET_4_0 && !STATIC
1768 public override SLE.Expression MakeExpression (BuilderContext ctx)
1770 return SLE.Expression.Default (type.GetMetaInfo ());
1774 protected override void CloneTo (CloneContext clonectx, Expression t)
1776 DefaultValueExpression target = (DefaultValueExpression) t;
1778 target.expr = expr.Clone (clonectx);
1783 /// Binary operators
1785 public class Binary : Expression, IDynamicBinder
1787 public class PredefinedOperator
1789 protected readonly TypeSpec left;
1790 protected readonly TypeSpec right;
1791 public readonly Operator OperatorsMask;
1792 public TypeSpec ReturnType;
1794 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1795 : this (ltype, rtype, op_mask, ltype)
1799 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1800 : this (type, type, op_mask, return_type)
1804 public PredefinedOperator (TypeSpec type, Operator op_mask)
1805 : this (type, type, op_mask, type)
1809 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1811 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1812 throw new InternalErrorException ("Only masked values can be used");
1816 this.OperatorsMask = op_mask;
1817 this.ReturnType = return_type;
1820 public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1822 b.type = ReturnType;
1824 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1825 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1828 // A user operators does not support multiple user conversions, but decimal type
1829 // is considered to be predefined type therefore we apply predefined operators rules
1830 // and then look for decimal user-operator implementation
1832 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal)
1833 return b.ResolveUserOperator (ec, b.left, b.right);
1835 var c = b.right as Constant;
1837 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1838 return ReducedExpression.Create (b.left, b).Resolve (ec);
1839 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
1840 return ReducedExpression.Create (b.left, b).Resolve (ec);
1844 c = b.left as Constant;
1846 if (c.IsDefaultValue && (b.oper == Operator.Addition || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1847 return ReducedExpression.Create (b.right, b).Resolve (ec);
1848 if (b.oper == Operator.Multiply && c.IsOneInteger)
1849 return ReducedExpression.Create (b.right, b).Resolve (ec);
1856 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
1859 // We are dealing with primitive types only
1861 return left == ltype && ltype == rtype;
1864 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1867 if (left == lexpr.Type && right == rexpr.Type)
1870 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1871 Convert.ImplicitConversionExists (ec, rexpr, right);
1874 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1877 if (left != null && best_operator.left != null) {
1878 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left, left);
1882 // When second argument is same as the first one, the result is same
1884 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1885 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right, right);
1888 if (result == 0 || result > 2)
1891 return result == 1 ? best_operator : this;
1895 sealed class PredefinedStringOperator : PredefinedOperator
1897 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
1898 : base (type, type, op_mask, retType)
1902 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
1903 : base (ltype, rtype, op_mask, retType)
1907 public override Expression ConvertResult (ResolveContext ec, Binary b)
1910 // Use original expression for nullable arguments
1912 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1914 b.left = unwrap.Original;
1916 unwrap = b.right as Nullable.Unwrap;
1918 b.right = unwrap.Original;
1920 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1921 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1924 // Start a new concat expression using converted expression
1926 return StringConcat.Create (ec, b.left, b.right, b.loc);
1930 sealed class PredefinedShiftOperator : PredefinedOperator
1932 public PredefinedShiftOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1933 : base (ltype, rtype, op_mask)
1937 public override Expression ConvertResult (ResolveContext ec, Binary b)
1939 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1941 Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1943 int right_mask = left.BuiltinType == BuiltinTypeSpec.Type.Int || left.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
1946 // b = b.left >> b.right & (0x1f|0x3f)
1948 b.right = new Binary (Operator.BitwiseAnd,
1949 b.right, new IntConstant (ec.BuiltinTypes, right_mask, b.right.Location), b.loc).Resolve (ec);
1952 // Expression tree representation does not use & mask
1954 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1955 b.type = ReturnType;
1958 // Optimize shift by 0
1960 var c = b.right as Constant;
1961 if (c != null && c.IsDefaultValue)
1962 return ReducedExpression.Create (b.left, b).Resolve (ec);
1968 sealed class PredefinedEqualityOperator : PredefinedOperator
1970 MethodSpec equal_method, inequal_method;
1972 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
1973 : base (arg, arg, Operator.EqualityMask, retType)
1977 public override Expression ConvertResult (ResolveContext ec, Binary b)
1979 b.type = ReturnType;
1981 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1982 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1984 Arguments args = new Arguments (2);
1985 args.Add (new Argument (b.left));
1986 args.Add (new Argument (b.right));
1989 if (b.oper == Operator.Equality) {
1990 if (equal_method == null) {
1991 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
1992 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
1993 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
1994 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
1996 throw new NotImplementedException (left.GetSignatureForError ());
1999 method = equal_method;
2001 if (inequal_method == null) {
2002 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2003 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2004 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2005 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2007 throw new NotImplementedException (left.GetSignatureForError ());
2010 method = inequal_method;
2013 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2017 class PredefinedPointerOperator : PredefinedOperator
2019 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2020 : base (ltype, rtype, op_mask)
2024 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2025 : base (ltype, rtype, op_mask, retType)
2029 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2030 : base (type, op_mask, return_type)
2034 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2037 if (!lexpr.Type.IsPointer)
2040 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2044 if (right == null) {
2045 if (!rexpr.Type.IsPointer)
2048 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2055 public override Expression ConvertResult (ResolveContext ec, Binary b)
2058 b.left = EmptyCast.Create (b.left, left);
2059 } else if (right != null) {
2060 b.right = EmptyCast.Create (b.right, right);
2063 TypeSpec r_type = ReturnType;
2064 Expression left_arg, right_arg;
2065 if (r_type == null) {
2068 right_arg = b.right;
2069 r_type = b.left.Type;
2073 r_type = b.right.Type;
2077 right_arg = b.right;
2080 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2085 public enum Operator {
2086 Multiply = 0 | ArithmeticMask,
2087 Division = 1 | ArithmeticMask,
2088 Modulus = 2 | ArithmeticMask,
2089 Addition = 3 | ArithmeticMask | AdditionMask,
2090 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2092 LeftShift = 5 | ShiftMask,
2093 RightShift = 6 | ShiftMask,
2095 LessThan = 7 | ComparisonMask | RelationalMask,
2096 GreaterThan = 8 | ComparisonMask | RelationalMask,
2097 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2098 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2099 Equality = 11 | ComparisonMask | EqualityMask,
2100 Inequality = 12 | ComparisonMask | EqualityMask,
2102 BitwiseAnd = 13 | BitwiseMask,
2103 ExclusiveOr = 14 | BitwiseMask,
2104 BitwiseOr = 15 | BitwiseMask,
2106 LogicalAnd = 16 | LogicalMask,
2107 LogicalOr = 17 | LogicalMask,
2112 ValuesOnlyMask = ArithmeticMask - 1,
2113 ArithmeticMask = 1 << 5,
2115 ComparisonMask = 1 << 7,
2116 EqualityMask = 1 << 8,
2117 BitwiseMask = 1 << 9,
2118 LogicalMask = 1 << 10,
2119 AdditionMask = 1 << 11,
2120 SubtractionMask = 1 << 12,
2121 RelationalMask = 1 << 13
2124 protected enum State
2128 LeftNullLifted = 1 << 2,
2129 RightNullLifted = 1 << 3
2132 readonly Operator oper;
2133 protected Expression left, right;
2134 protected State state;
2135 Expression enum_conversion;
2137 public Binary (Operator oper, Expression left, Expression right, bool isCompound, Location loc)
2138 : this (oper, left, right, loc)
2141 state |= State.Compound;
2144 public Binary (Operator oper, Expression left, Expression right, Location loc)
2154 public bool IsCompound {
2156 return (state & State.Compound) != 0;
2160 public Operator Oper {
2169 /// Returns a stringified representation of the Operator
2171 string OperName (Operator oper)
2175 case Operator.Multiply:
2178 case Operator.Division:
2181 case Operator.Modulus:
2184 case Operator.Addition:
2187 case Operator.Subtraction:
2190 case Operator.LeftShift:
2193 case Operator.RightShift:
2196 case Operator.LessThan:
2199 case Operator.GreaterThan:
2202 case Operator.LessThanOrEqual:
2205 case Operator.GreaterThanOrEqual:
2208 case Operator.Equality:
2211 case Operator.Inequality:
2214 case Operator.BitwiseAnd:
2217 case Operator.BitwiseOr:
2220 case Operator.ExclusiveOr:
2223 case Operator.LogicalOr:
2226 case Operator.LogicalAnd:
2230 s = oper.ToString ();
2240 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2242 new Binary (oper, left, right, loc).Error_OperatorCannotBeApplied (ec, left, right);
2245 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2247 if (left.Type == InternalType.FakeInternalType || right.Type == InternalType.FakeInternalType)
2251 l = TypeManager.CSharpName (left.Type);
2252 r = TypeManager.CSharpName (right.Type);
2254 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2258 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2260 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2264 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2266 string GetOperatorExpressionTypeName ()
2269 case Operator.Addition:
2270 return IsCompound ? "AddAssign" : "Add";
2271 case Operator.BitwiseAnd:
2272 return IsCompound ? "AndAssign" : "And";
2273 case Operator.BitwiseOr:
2274 return IsCompound ? "OrAssign" : "Or";
2275 case Operator.Division:
2276 return IsCompound ? "DivideAssign" : "Divide";
2277 case Operator.ExclusiveOr:
2278 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2279 case Operator.Equality:
2281 case Operator.GreaterThan:
2282 return "GreaterThan";
2283 case Operator.GreaterThanOrEqual:
2284 return "GreaterThanOrEqual";
2285 case Operator.Inequality:
2287 case Operator.LeftShift:
2288 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2289 case Operator.LessThan:
2291 case Operator.LessThanOrEqual:
2292 return "LessThanOrEqual";
2293 case Operator.LogicalAnd:
2295 case Operator.LogicalOr:
2297 case Operator.Modulus:
2298 return IsCompound ? "ModuloAssign" : "Modulo";
2299 case Operator.Multiply:
2300 return IsCompound ? "MultiplyAssign" : "Multiply";
2301 case Operator.RightShift:
2302 return IsCompound ? "RightShiftAssign" : "RightShift";
2303 case Operator.Subtraction:
2304 return IsCompound ? "SubtractAssign" : "Subtract";
2306 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2310 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2313 case Operator.Addition:
2314 return CSharp.Operator.OpType.Addition;
2315 case Operator.BitwiseAnd:
2316 case Operator.LogicalAnd:
2317 return CSharp.Operator.OpType.BitwiseAnd;
2318 case Operator.BitwiseOr:
2319 case Operator.LogicalOr:
2320 return CSharp.Operator.OpType.BitwiseOr;
2321 case Operator.Division:
2322 return CSharp.Operator.OpType.Division;
2323 case Operator.Equality:
2324 return CSharp.Operator.OpType.Equality;
2325 case Operator.ExclusiveOr:
2326 return CSharp.Operator.OpType.ExclusiveOr;
2327 case Operator.GreaterThan:
2328 return CSharp.Operator.OpType.GreaterThan;
2329 case Operator.GreaterThanOrEqual:
2330 return CSharp.Operator.OpType.GreaterThanOrEqual;
2331 case Operator.Inequality:
2332 return CSharp.Operator.OpType.Inequality;
2333 case Operator.LeftShift:
2334 return CSharp.Operator.OpType.LeftShift;
2335 case Operator.LessThan:
2336 return CSharp.Operator.OpType.LessThan;
2337 case Operator.LessThanOrEqual:
2338 return CSharp.Operator.OpType.LessThanOrEqual;
2339 case Operator.Modulus:
2340 return CSharp.Operator.OpType.Modulus;
2341 case Operator.Multiply:
2342 return CSharp.Operator.OpType.Multiply;
2343 case Operator.RightShift:
2344 return CSharp.Operator.OpType.RightShift;
2345 case Operator.Subtraction:
2346 return CSharp.Operator.OpType.Subtraction;
2348 throw new InternalErrorException (op.ToString ());
2352 public override bool ContainsEmitWithAwait ()
2354 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2357 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l)
2362 case Operator.Multiply:
2363 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2364 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2365 opcode = OpCodes.Mul_Ovf;
2366 else if (!IsFloat (l))
2367 opcode = OpCodes.Mul_Ovf_Un;
2369 opcode = OpCodes.Mul;
2371 opcode = OpCodes.Mul;
2375 case Operator.Division:
2377 opcode = OpCodes.Div_Un;
2379 opcode = OpCodes.Div;
2382 case Operator.Modulus:
2384 opcode = OpCodes.Rem_Un;
2386 opcode = OpCodes.Rem;
2389 case Operator.Addition:
2390 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2391 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2392 opcode = OpCodes.Add_Ovf;
2393 else if (!IsFloat (l))
2394 opcode = OpCodes.Add_Ovf_Un;
2396 opcode = OpCodes.Add;
2398 opcode = OpCodes.Add;
2401 case Operator.Subtraction:
2402 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2403 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2404 opcode = OpCodes.Sub_Ovf;
2405 else if (!IsFloat (l))
2406 opcode = OpCodes.Sub_Ovf_Un;
2408 opcode = OpCodes.Sub;
2410 opcode = OpCodes.Sub;
2413 case Operator.RightShift:
2415 opcode = OpCodes.Shr_Un;
2417 opcode = OpCodes.Shr;
2420 case Operator.LeftShift:
2421 opcode = OpCodes.Shl;
2424 case Operator.Equality:
2425 opcode = OpCodes.Ceq;
2428 case Operator.Inequality:
2429 ec.Emit (OpCodes.Ceq);
2432 opcode = OpCodes.Ceq;
2435 case Operator.LessThan:
2437 opcode = OpCodes.Clt_Un;
2439 opcode = OpCodes.Clt;
2442 case Operator.GreaterThan:
2444 opcode = OpCodes.Cgt_Un;
2446 opcode = OpCodes.Cgt;
2449 case Operator.LessThanOrEqual:
2450 if (IsUnsigned (l) || IsFloat (l))
2451 ec.Emit (OpCodes.Cgt_Un);
2453 ec.Emit (OpCodes.Cgt);
2456 opcode = OpCodes.Ceq;
2459 case Operator.GreaterThanOrEqual:
2460 if (IsUnsigned (l) || IsFloat (l))
2461 ec.Emit (OpCodes.Clt_Un);
2463 ec.Emit (OpCodes.Clt);
2467 opcode = OpCodes.Ceq;
2470 case Operator.BitwiseOr:
2471 opcode = OpCodes.Or;
2474 case Operator.BitwiseAnd:
2475 opcode = OpCodes.And;
2478 case Operator.ExclusiveOr:
2479 opcode = OpCodes.Xor;
2483 throw new InternalErrorException (oper.ToString ());
2489 static bool IsUnsigned (TypeSpec t)
2491 switch (t.BuiltinType) {
2492 case BuiltinTypeSpec.Type.Char:
2493 case BuiltinTypeSpec.Type.UInt:
2494 case BuiltinTypeSpec.Type.ULong:
2495 case BuiltinTypeSpec.Type.UShort:
2496 case BuiltinTypeSpec.Type.Byte:
2503 static bool IsFloat (TypeSpec t)
2505 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2508 Expression ResolveOperator (ResolveContext ec)
2510 TypeSpec l = left.Type;
2511 TypeSpec r = right.Type;
2513 bool primitives_only = false;
2516 // Handles predefined primitive types
2518 if (BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r)) {
2519 if ((oper & Operator.ShiftMask) == 0) {
2520 if (l.BuiltinType != BuiltinTypeSpec.Type.Bool && !DoBinaryOperatorPromotion (ec))
2523 primitives_only = true;
2527 if (l.IsPointer || r.IsPointer)
2528 return ResolveOperatorPointer (ec, l, r);
2531 bool lenum = l.IsEnum;
2532 bool renum = r.IsEnum;
2533 if (lenum || renum) {
2534 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2541 if ((oper == Operator.Addition || oper == Operator.Subtraction) && (l.IsDelegate || r.IsDelegate)) {
2543 expr = ResolveOperatorDelegate (ec, l, r);
2545 // TODO: Can this be ambiguous
2551 expr = ResolveUserOperator (ec, left, right);
2555 // Predefined reference types equality
2556 if ((oper & Operator.EqualityMask) != 0) {
2557 expr = ResolveOperatorEquality (ec, l, r);
2563 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, primitives_only, null);
2566 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2567 // if 'left' is not an enumeration constant, create one from the type of 'right'
2568 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2571 case Operator.BitwiseOr:
2572 case Operator.BitwiseAnd:
2573 case Operator.ExclusiveOr:
2574 case Operator.Equality:
2575 case Operator.Inequality:
2576 case Operator.LessThan:
2577 case Operator.LessThanOrEqual:
2578 case Operator.GreaterThan:
2579 case Operator.GreaterThanOrEqual:
2580 if (TypeManager.IsEnumType (left.Type))
2583 if (left.IsZeroInteger)
2584 return left.TryReduce (ec, right.Type, loc);
2588 case Operator.Addition:
2589 case Operator.Subtraction:
2592 case Operator.Multiply:
2593 case Operator.Division:
2594 case Operator.Modulus:
2595 case Operator.LeftShift:
2596 case Operator.RightShift:
2597 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2606 // The `|' operator used on types which were extended is dangerous
2608 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2610 OpcodeCast lcast = left as OpcodeCast;
2611 if (lcast != null) {
2612 if (IsUnsigned (lcast.UnderlyingType))
2616 OpcodeCast rcast = right as OpcodeCast;
2617 if (rcast != null) {
2618 if (IsUnsigned (rcast.UnderlyingType))
2622 if (lcast == null && rcast == null)
2625 // FIXME: consider constants
2627 ec.Report.Warning (675, 3, loc,
2628 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2629 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2632 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
2634 return new PredefinedOperator[] {
2636 // Pointer arithmetic:
2638 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2639 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2640 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2641 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2643 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
2644 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
2645 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
2646 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
2649 // T* operator + (int y, T* x);
2650 // T* operator + (uint y, T *x);
2651 // T* operator + (long y, T *x);
2652 // T* operator + (ulong y, T *x);
2654 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
2655 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
2656 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
2657 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
2660 // long operator - (T* x, T *y)
2662 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
2666 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
2668 TypeSpec bool_type = types.Bool;
2669 return new PredefinedOperator[] {
2670 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask),
2671 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
2672 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
2673 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
2674 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
2675 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
2676 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
2678 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
2679 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
2680 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
2681 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
2682 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
2683 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
2684 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
2686 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
2687 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
2688 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
2690 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
2692 new PredefinedShiftOperator (types.Int, types.Int, Operator.ShiftMask),
2693 new PredefinedShiftOperator (types.UInt, types.Int, Operator.ShiftMask),
2694 new PredefinedShiftOperator (types.Long, types.Int, Operator.ShiftMask),
2695 new PredefinedShiftOperator (types.ULong, types.Int, Operator.ShiftMask)
2699 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
2701 TypeSpec bool_type = types.Bool;
2703 return new PredefinedOperator[] {
2704 new PredefinedEqualityOperator (types.String, bool_type),
2705 new PredefinedEqualityOperator (types.Delegate, bool_type),
2706 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type)
2711 // Rules used during binary numeric promotion
2713 static bool DoNumericPromotion (ResolveContext rc, ref Expression prim_expr, ref Expression second_expr, TypeSpec type)
2717 Constant c = prim_expr as Constant;
2719 temp = c.ConvertImplicitly (type);
2726 if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
2727 switch (prim_expr.Type.BuiltinType) {
2728 case BuiltinTypeSpec.Type.Int:
2729 case BuiltinTypeSpec.Type.Short:
2730 case BuiltinTypeSpec.Type.SByte:
2731 case BuiltinTypeSpec.Type.Long:
2732 type = rc.BuiltinTypes.Long;
2734 if (type != second_expr.Type) {
2735 c = second_expr as Constant;
2737 temp = c.ConvertImplicitly (type);
2739 temp = Convert.ImplicitNumericConversion (second_expr, type);
2746 } else if (type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
2748 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2750 switch (type.BuiltinType) {
2751 case BuiltinTypeSpec.Type.Int:
2752 case BuiltinTypeSpec.Type.Long:
2753 case BuiltinTypeSpec.Type.Short:
2754 case BuiltinTypeSpec.Type.SByte:
2759 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2768 // 7.2.6.2 Binary numeric promotions
2770 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2772 TypeSpec ltype = left.Type;
2773 TypeSpec rtype = right.Type;
2776 foreach (TypeSpec t in ec.BuiltinTypes.BinaryPromotionsTypes) {
2778 return t == rtype || DoNumericPromotion (ec, ref right, ref left, t);
2781 return t == ltype || DoNumericPromotion (ec, ref left, ref right, t);
2784 TypeSpec int32 = ec.BuiltinTypes.Int;
2785 if (ltype != int32) {
2786 Constant c = left as Constant;
2788 temp = c.ConvertImplicitly (int32);
2790 temp = Convert.ImplicitNumericConversion (left, int32);
2797 if (rtype != int32) {
2798 Constant c = right as Constant;
2800 temp = c.ConvertImplicitly (int32);
2802 temp = Convert.ImplicitNumericConversion (right, int32);
2812 protected override Expression DoResolve (ResolveContext ec)
2817 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2818 left = ((ParenthesizedExpression) left).Expr;
2819 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2823 if (left.eclass == ExprClass.Type) {
2824 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2828 left = left.Resolve (ec);
2833 Constant lc = left as Constant;
2835 if (lc != null && lc.Type.BuiltinType == BuiltinTypeSpec.Type.Bool &&
2836 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2837 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2839 // FIXME: resolve right expression as unreachable
2840 // right.Resolve (ec);
2842 ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2846 right = right.Resolve (ec);
2850 eclass = ExprClass.Value;
2851 Constant rc = right as Constant;
2853 // The conversion rules are ignored in enum context but why
2854 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2855 lc = EnumLiftUp (ec, lc, rc, loc);
2857 rc = EnumLiftUp (ec, rc, lc, loc);
2860 if (rc != null && lc != null) {
2861 int prev_e = ec.Report.Errors;
2862 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
2863 if (e != null || ec.Report.Errors != prev_e)
2867 // Comparison warnings
2868 if ((oper & Operator.ComparisonMask) != 0) {
2869 if (left.Equals (right)) {
2870 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2872 CheckOutOfRangeComparison (ec, lc, right.Type);
2873 CheckOutOfRangeComparison (ec, rc, left.Type);
2876 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2878 var rt = right.Type;
2879 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
2880 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
2881 Error_OperatorCannotBeApplied (ec, left, right);
2888 // Special handling for logical boolean operators which require rhs not to be
2889 // evaluated based on lhs value
2891 if ((oper & Operator.LogicalMask) != 0) {
2892 Expression cond_left, cond_right, expr;
2894 args = new Arguments (2);
2896 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2897 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, ec.CurrentBlock, loc);
2899 var cond_args = new Arguments (1);
2900 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left).Resolve (ec)));
2903 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
2904 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
2906 left = temp.CreateReferenceExpression (ec, loc);
2907 if (oper == Operator.LogicalAnd) {
2908 expr = DynamicUnaryConversion.CreateIsFalse (ec, cond_args, loc);
2911 expr = DynamicUnaryConversion.CreateIsTrue (ec, cond_args, loc);
2915 args.Add (new Argument (left));
2916 args.Add (new Argument (right));
2917 cond_right = new DynamicExpressionStatement (this, args, loc);
2919 LocalVariable temp = LocalVariable.CreateCompilerGenerated (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
2921 args.Add (new Argument (temp.CreateReferenceExpression (ec, loc).Resolve (ec)));
2922 args.Add (new Argument (right));
2923 right = new DynamicExpressionStatement (this, args, loc);
2926 // bool && dynamic => (temp = left) ? temp && right : temp;
2927 // bool || dynamic => (temp = left) ? temp : temp || right;
2929 if (oper == Operator.LogicalAnd) {
2931 cond_right = temp.CreateReferenceExpression (ec, loc);
2933 cond_left = temp.CreateReferenceExpression (ec, loc);
2937 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left));
2940 return new Conditional (expr, cond_left, cond_right, loc).Resolve (ec);
2943 args = new Arguments (2);
2944 args.Add (new Argument (left));
2945 args.Add (new Argument (right));
2946 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
2949 if (ec.Module.Compiler.Settings.Version >= LanguageVersion.ISO_2 &&
2950 ((left.Type.IsNullableType && (right is NullLiteral || right.Type.IsNullableType || TypeSpec.IsValueType (right.Type))) ||
2951 (TypeSpec.IsValueType (left.Type) && right is NullLiteral) ||
2952 (right.Type.IsNullableType && (left is NullLiteral || left.Type.IsNullableType || TypeSpec.IsValueType (left.Type))) ||
2953 (TypeSpec.IsValueType (right.Type) && left is NullLiteral))) {
2954 var lifted = new Nullable.LiftedBinaryOperator (oper, left, right, loc);
2955 lifted.state = state;
2956 return lifted.Resolve (ec);
2959 return DoResolveCore (ec, left, right);
2962 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
2964 Expression expr = ResolveOperator (ec);
2966 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
2968 if (left == null || right == null)
2969 throw new InternalErrorException ("Invalid conversion");
2971 if (oper == Operator.BitwiseOr)
2972 CheckBitwiseOrOnSignExtended (ec);
2977 public override SLE.Expression MakeExpression (BuilderContext ctx)
2979 var le = left.MakeExpression (ctx);
2980 var re = right.MakeExpression (ctx);
2981 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
2984 case Operator.Addition:
2985 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
2986 case Operator.BitwiseAnd:
2987 return SLE.Expression.And (le, re);
2988 case Operator.BitwiseOr:
2989 return SLE.Expression.Or (le, re);
2990 case Operator.Division:
2991 return SLE.Expression.Divide (le, re);
2992 case Operator.Equality:
2993 return SLE.Expression.Equal (le, re);
2994 case Operator.ExclusiveOr:
2995 return SLE.Expression.ExclusiveOr (le, re);
2996 case Operator.GreaterThan:
2997 return SLE.Expression.GreaterThan (le, re);
2998 case Operator.GreaterThanOrEqual:
2999 return SLE.Expression.GreaterThanOrEqual (le, re);
3000 case Operator.Inequality:
3001 return SLE.Expression.NotEqual (le, re);
3002 case Operator.LeftShift:
3003 return SLE.Expression.LeftShift (le, re);
3004 case Operator.LessThan:
3005 return SLE.Expression.LessThan (le, re);
3006 case Operator.LessThanOrEqual:
3007 return SLE.Expression.LessThanOrEqual (le, re);
3008 case Operator.LogicalAnd:
3009 return SLE.Expression.AndAlso (le, re);
3010 case Operator.LogicalOr:
3011 return SLE.Expression.OrElse (le, re);
3012 case Operator.Modulus:
3013 return SLE.Expression.Modulo (le, re);
3014 case Operator.Multiply:
3015 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3016 case Operator.RightShift:
3017 return SLE.Expression.RightShift (le, re);
3018 case Operator.Subtraction:
3019 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3021 throw new NotImplementedException (oper.ToString ());
3026 // D operator + (D x, D y)
3027 // D operator - (D x, D y)
3029 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3031 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3033 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3034 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3039 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3040 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3050 MethodSpec method = null;
3051 Arguments args = new Arguments (2);
3052 args.Add (new Argument (left));
3053 args.Add (new Argument (right));
3055 if (oper == Operator.Addition) {
3056 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3057 } else if (oper == Operator.Subtraction) {
3058 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3062 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3064 MethodGroupExpr mg = MethodGroupExpr.CreatePredefined (method, ec.BuiltinTypes.Delegate, loc);
3065 Expression expr = new UserOperatorCall (mg.BestCandidate, args, CreateExpressionTree, loc);
3066 return new ClassCast (expr, l);
3070 // Enumeration operators
3072 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3075 // bool operator == (E x, E y);
3076 // bool operator != (E x, E y);
3077 // bool operator < (E x, E y);
3078 // bool operator > (E x, E y);
3079 // bool operator <= (E x, E y);
3080 // bool operator >= (E x, E y);
3082 // E operator & (E x, E y);
3083 // E operator | (E x, E y);
3084 // E operator ^ (E x, E y);
3086 // U operator - (E e, E f)
3087 // E operator - (E e, U x)
3088 // E operator - (U x, E e) // LAMESPEC: Not covered by the specification
3090 // E operator + (E e, U x)
3091 // E operator + (U x, E e)
3093 Expression ltemp = left;
3094 Expression rtemp = right;
3095 TypeSpec underlying_type;
3096 TypeSpec underlying_type_result;
3101 // LAMESPEC: There is never ambiguous conversion between enum operators
3102 // the one which contains more enum parameters always wins even if there
3103 // is an implicit conversion involved
3105 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3107 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3108 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
3115 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3116 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
3126 if ((oper & Operator.BitwiseMask) != 0) {
3128 underlying_type_result = underlying_type;
3131 underlying_type_result = null;
3133 } else if (oper == Operator.Subtraction) {
3135 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3136 if (ltype != rtype) {
3137 expr = Convert.ImplicitConversion (ec, left, rtype, left.Location);
3139 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3145 res_type = underlying_type;
3150 res_type = underlying_type;
3153 underlying_type_result = underlying_type;
3155 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3156 expr = Convert.ImplicitConversion (ec, right, ltype, right.Location);
3157 if (expr == null || expr is EnumConstant) {
3158 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3164 res_type = underlying_type;
3168 underlying_type_result = underlying_type;
3172 } else if (oper == Operator.Addition) {
3174 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3177 if (rtype != underlying_type && (state & (State.RightNullLifted | State.LeftNullLifted)) == 0) {
3178 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3185 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3187 if (ltype != underlying_type) {
3188 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3196 underlying_type_result = underlying_type;
3201 // Unwrap the constant correctly, so DoBinaryOperatorPromotion can do the magic
3202 // with constants and expressions
3203 if (left.Type != underlying_type) {
3204 if (left is Constant)
3205 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
3207 left = EmptyCast.Create (left, underlying_type);
3210 if (right.Type != underlying_type) {
3211 if (right is Constant)
3212 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
3214 right = EmptyCast.Create (right, underlying_type);
3218 // C# specification uses explicit cast syntax which means binary promotion
3219 // should happen, however it seems that csc does not do that
3221 if (!DoBinaryOperatorPromotion (ec)) {
3227 if (underlying_type_result != null && left.Type != underlying_type_result) {
3228 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (left.Type), underlying_type_result);
3231 expr = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, true, res_type);
3243 // If the return type of the selected operator is implicitly convertible to the type of x
3245 if (Convert.ImplicitConversionExists (ec, expr, ltype))
3249 // Otherwise, if the selected operator is a predefined operator, if the return type of the
3250 // selected operator is explicitly convertible to the type of x, and if y is implicitly
3251 // convertible to the type of x or the operator is a shift operator, then the operation
3252 // is evaluated as x = (T)(x op y), where T is the type of x
3254 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
3258 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
3265 // 7.9.6 Reference type equality operators
3267 Expression ResolveOperatorEquality (ResolveContext ec, TypeSpec l, TypeSpec r)
3270 type = ec.BuiltinTypes.Bool;
3273 // a, Both operands are reference-type values or the value null
3274 // b, One operand is a value of type T where T is a type-parameter and
3275 // the other operand is the value null. Furthermore T does not have the
3276 // value type constraint
3278 // LAMESPEC: Very confusing details in the specification, basically any
3279 // reference like type-parameter is allowed
3281 var tparam_l = l as TypeParameterSpec;
3282 var tparam_r = r as TypeParameterSpec;
3283 if (tparam_l != null) {
3284 if (right is NullLiteral && !tparam_l.HasSpecialStruct) {
3285 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3289 if (!tparam_l.IsReferenceType)
3292 l = tparam_l.GetEffectiveBase ();
3293 left = new BoxedCast (left, l);
3294 } else if (left is NullLiteral && tparam_r == null) {
3295 if (!TypeSpec.IsReferenceType (r) || r.Kind == MemberKind.InternalCompilerType)
3301 if (tparam_r != null) {
3302 if (left is NullLiteral && !tparam_r.HasSpecialStruct) {
3303 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3307 if (!tparam_r.IsReferenceType)
3310 r = tparam_r.GetEffectiveBase ();
3311 right = new BoxedCast (right, r);
3312 } else if (right is NullLiteral) {
3313 if (!TypeSpec.IsReferenceType (l) || l.Kind == MemberKind.InternalCompilerType)
3320 // LAMESPEC: method groups can be compared when they convert to other side delegate
3323 if (right.eclass == ExprClass.MethodGroup) {
3324 result = Convert.ImplicitConversion (ec, right, l, loc);
3330 } else if (r.IsDelegate && l != r) {
3333 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3334 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3343 // bool operator != (string a, string b)
3344 // bool operator == (string a, string b)
3346 // bool operator != (Delegate a, Delegate b)
3347 // bool operator == (Delegate a, Delegate b)
3349 // bool operator != (bool a, bool b)
3350 // bool operator == (bool a, bool b)
3352 // LAMESPEC: Reference equality comparison can apply to value types when
3353 // they implement an implicit conversion to any of types above.
3355 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3356 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, false, null);
3362 // bool operator != (object a, object b)
3363 // bool operator == (object a, object b)
3365 // An explicit reference conversion exists from the
3366 // type of either operand to the type of the other operand.
3369 // Optimize common path
3371 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3374 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3375 !Convert.ExplicitReferenceConversionExists (r, l))
3378 // Reject allowed explicit conversions like int->object
3379 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
3382 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3383 ec.Report.Warning (253, 2, loc,
3384 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3385 l.GetSignatureForError ());
3387 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3388 ec.Report.Warning (252, 2, loc,
3389 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3390 r.GetSignatureForError ());
3396 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3399 // bool operator == (void* x, void* y);
3400 // bool operator != (void* x, void* y);
3401 // bool operator < (void* x, void* y);
3402 // bool operator > (void* x, void* y);
3403 // bool operator <= (void* x, void* y);
3404 // bool operator >= (void* x, void* y);
3406 if ((oper & Operator.ComparisonMask) != 0) {
3409 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3416 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3422 type = ec.BuiltinTypes.Bool;
3426 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false, null);
3430 // Build-in operators method overloading
3432 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, TypeSpec enum_type)
3434 PredefinedOperator best_operator = null;
3435 TypeSpec l = left.Type;
3436 TypeSpec r = right.Type;
3437 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3439 foreach (PredefinedOperator po in operators) {
3440 if ((po.OperatorsMask & oper_mask) == 0)
3443 if (primitives_only) {
3444 if (!po.IsPrimitiveApplicable (l, r))
3447 if (!po.IsApplicable (ec, left, right))
3451 if (best_operator == null) {
3453 if (primitives_only)
3459 best_operator = po.ResolveBetterOperator (ec, best_operator);
3461 if (best_operator == null) {
3462 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3463 OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
3470 if (best_operator == null)
3473 Expression expr = best_operator.ConvertResult (ec, this);
3476 // Optimize &/&& constant expressions with 0 value
3478 if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
3479 Constant rc = right as Constant;
3480 Constant lc = left as Constant;
3481 if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
3483 // The result is a constant with side-effect
3485 Constant side_effect = rc == null ?
3486 new SideEffectConstant (lc, right, loc) :
3487 new SideEffectConstant (rc, left, loc);
3489 return ReducedExpression.Create (side_effect, expr);
3493 if (enum_type == null)
3497 // HACK: required by enum_conversion
3499 expr.Type = enum_type;
3500 return EmptyCast.Create (expr, enum_type);
3504 // Performs user-operator overloading
3506 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression left, Expression right)
3508 var op = ConvertBinaryToUserOperator (oper);
3510 if (l.IsNullableType)
3511 l = Nullable.NullableInfo.GetUnderlyingType (l);
3513 if (r.IsNullableType)
3514 r = Nullable.NullableInfo.GetUnderlyingType (r);
3516 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
3517 IList<MemberSpec> right_operators = null;
3520 right_operators = MemberCache.GetUserOperator (r, op, false);
3521 if (right_operators == null && left_operators == null)
3523 } else if (left_operators == null) {
3527 Arguments args = new Arguments (2);
3528 Argument larg = new Argument (left);
3530 Argument rarg = new Argument (right);
3534 // User-defined operator implementations always take precedence
3535 // over predefined operator implementations
3537 if (left_operators != null && right_operators != null) {
3538 left_operators = CombineUserOperators (left_operators, right_operators);
3539 } else if (right_operators != null) {
3540 left_operators = right_operators;
3543 var res = new OverloadResolver (left_operators, OverloadResolver.Restrictions.ProbingOnly |
3544 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded, loc);
3546 var oper_method = res.ResolveOperator (ec, ref args);
3547 if (oper_method == null)
3550 var llifted = (state & State.LeftNullLifted) != 0;
3551 var rlifted = (state & State.RightNullLifted) != 0;
3552 if ((Oper & Operator.EqualityMask) != 0) {
3553 var parameters = oper_method.Parameters;
3554 // LAMESPEC: No idea why this is not allowed
3555 if ((left is Nullable.Unwrap || right is Nullable.Unwrap) && parameters.Types [0] != parameters.Types [1])
3558 // Binary operation was lifted but we have found a user operator
3559 // which requires value-type argument, we downgrade ourself back to
3561 // LAMESPEC: The user operator is not called (it cannot be we are passing null to struct)
3562 // but compilation succeeds
3563 if ((llifted && !parameters.Types[0].IsStruct) || (rlifted && !parameters.Types[1].IsStruct)) {
3564 state &= ~(State.LeftNullLifted | State.RightNullLifted);
3568 Expression oper_expr;
3570 // TODO: CreateExpressionTree is allocated every time
3571 if ((oper & Operator.LogicalMask) != 0) {
3572 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
3573 oper == Operator.LogicalAnd, loc).Resolve (ec);
3575 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
3579 this.left = larg.Expr;
3582 this.right = rarg.Expr;
3588 // Merge two sets of user operators into one, they are mostly distinguish
3589 // expect when they share base type and it contains an operator
3591 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
3593 var combined = new List<MemberSpec> (left.Count + right.Count);
3594 combined.AddRange (left);
3595 foreach (var r in right) {
3597 foreach (var l in left) {
3598 if (l.DeclaringType == r.DeclaringType) {
3611 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
3613 if (c is IntegralConstant || c is CharConstant) {
3615 c.ConvertExplicitly (true, type);
3616 } catch (OverflowException) {
3617 ec.Report.Warning (652, 2, loc,
3618 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
3619 TypeManager.CSharpName (type));
3625 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3626 /// context of a conditional bool expression. This function will return
3627 /// false if it is was possible to use EmitBranchable, or true if it was.
3629 /// The expression's code is generated, and we will generate a branch to `target'
3630 /// if the resulting expression value is equal to isTrue
3632 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3635 // This is more complicated than it looks, but its just to avoid
3636 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3637 // but on top of that we want for == and != to use a special path
3638 // if we are comparing against null
3640 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
3641 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3644 // put the constant on the rhs, for simplicity
3646 if (left is Constant) {
3647 Expression swap = right;
3653 // brtrue/brfalse works with native int only
3655 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
3656 left.EmitBranchable (ec, target, my_on_true);
3659 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
3660 // right is a boolean, and it's not 'false' => it is 'true'
3661 left.EmitBranchable (ec, target, !my_on_true);
3665 } else if (oper == Operator.LogicalAnd) {
3668 Label tests_end = ec.DefineLabel ();
3670 left.EmitBranchable (ec, tests_end, false);
3671 right.EmitBranchable (ec, target, true);
3672 ec.MarkLabel (tests_end);
3675 // This optimizes code like this
3676 // if (true && i > 4)
3678 if (!(left is Constant))
3679 left.EmitBranchable (ec, target, false);
3681 if (!(right is Constant))
3682 right.EmitBranchable (ec, target, false);
3687 } else if (oper == Operator.LogicalOr){
3689 left.EmitBranchable (ec, target, true);
3690 right.EmitBranchable (ec, target, true);
3693 Label tests_end = ec.DefineLabel ();
3694 left.EmitBranchable (ec, tests_end, true);
3695 right.EmitBranchable (ec, target, false);
3696 ec.MarkLabel (tests_end);
3701 } else if ((oper & Operator.ComparisonMask) == 0) {
3702 base.EmitBranchable (ec, target, on_true);
3709 TypeSpec t = left.Type;
3710 bool is_float = IsFloat (t);
3711 bool is_unsigned = is_float || IsUnsigned (t);
3714 case Operator.Equality:
3716 ec.Emit (OpCodes.Beq, target);
3718 ec.Emit (OpCodes.Bne_Un, target);
3721 case Operator.Inequality:
3723 ec.Emit (OpCodes.Bne_Un, target);
3725 ec.Emit (OpCodes.Beq, target);
3728 case Operator.LessThan:
3730 if (is_unsigned && !is_float)
3731 ec.Emit (OpCodes.Blt_Un, target);
3733 ec.Emit (OpCodes.Blt, target);
3736 ec.Emit (OpCodes.Bge_Un, target);
3738 ec.Emit (OpCodes.Bge, target);
3741 case Operator.GreaterThan:
3743 if (is_unsigned && !is_float)
3744 ec.Emit (OpCodes.Bgt_Un, target);
3746 ec.Emit (OpCodes.Bgt, target);
3749 ec.Emit (OpCodes.Ble_Un, target);
3751 ec.Emit (OpCodes.Ble, target);
3754 case Operator.LessThanOrEqual:
3756 if (is_unsigned && !is_float)
3757 ec.Emit (OpCodes.Ble_Un, target);
3759 ec.Emit (OpCodes.Ble, target);
3762 ec.Emit (OpCodes.Bgt_Un, target);
3764 ec.Emit (OpCodes.Bgt, target);
3768 case Operator.GreaterThanOrEqual:
3770 if (is_unsigned && !is_float)
3771 ec.Emit (OpCodes.Bge_Un, target);
3773 ec.Emit (OpCodes.Bge, target);
3776 ec.Emit (OpCodes.Blt_Un, target);
3778 ec.Emit (OpCodes.Blt, target);
3781 throw new InternalErrorException (oper.ToString ());
3785 public override void Emit (EmitContext ec)
3787 EmitOperator (ec, left.Type);
3790 protected virtual void EmitOperator (EmitContext ec, TypeSpec l)
3792 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
3793 left = left.EmitToField (ec);
3795 if ((oper & Operator.LogicalMask) == 0) {
3796 right = right.EmitToField (ec);
3801 // Handle short-circuit operators differently
3804 if ((oper & Operator.LogicalMask) != 0) {
3805 Label load_result = ec.DefineLabel ();
3806 Label end = ec.DefineLabel ();
3808 bool is_or = oper == Operator.LogicalOr;
3809 left.EmitBranchable (ec, load_result, is_or);
3811 ec.Emit (OpCodes.Br_S, end);
3813 ec.MarkLabel (load_result);
3814 ec.EmitInt (is_or ? 1 : 0);
3820 // Optimize zero-based operations which cannot be optimized at expression level
3822 if (oper == Operator.Subtraction) {
3823 var lc = left as IntegralConstant;
3824 if (lc != null && lc.IsDefaultValue) {
3826 ec.Emit (OpCodes.Neg);
3833 EmitOperatorOpcode (ec, oper, l);
3836 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3837 // expression because that would wrap lifted binary operation
3839 if (enum_conversion != null)
3840 enum_conversion.Emit (ec);
3843 public override void EmitSideEffect (EmitContext ec)
3845 if ((oper & Operator.LogicalMask) != 0 ||
3846 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3847 base.EmitSideEffect (ec);
3849 left.EmitSideEffect (ec);
3850 right.EmitSideEffect (ec);
3854 protected override void CloneTo (CloneContext clonectx, Expression t)
3856 Binary target = (Binary) t;
3858 target.left = left.Clone (clonectx);
3859 target.right = right.Clone (clonectx);
3862 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3864 Arguments binder_args = new Arguments (4);
3866 MemberAccess sle = new MemberAccess (new MemberAccess (
3867 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3869 CSharpBinderFlags flags = 0;
3870 if (ec.HasSet (ResolveContext.Options.CheckedScope))
3871 flags = CSharpBinderFlags.CheckedContext;
3873 if ((oper & Operator.LogicalMask) != 0)
3874 flags |= CSharpBinderFlags.BinaryOperationLogical;
3876 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
3877 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3878 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
3879 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
3881 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
3884 public override Expression CreateExpressionTree (ResolveContext ec)
3886 return CreateExpressionTree (ec, null);
3889 Expression CreateExpressionTree (ResolveContext ec, Expression method)
3892 bool lift_arg = false;
3895 case Operator.Addition:
3896 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3897 method_name = "AddChecked";
3899 method_name = "Add";
3901 case Operator.BitwiseAnd:
3902 method_name = "And";
3904 case Operator.BitwiseOr:
3907 case Operator.Division:
3908 method_name = "Divide";
3910 case Operator.Equality:
3911 method_name = "Equal";
3914 case Operator.ExclusiveOr:
3915 method_name = "ExclusiveOr";
3917 case Operator.GreaterThan:
3918 method_name = "GreaterThan";
3921 case Operator.GreaterThanOrEqual:
3922 method_name = "GreaterThanOrEqual";
3925 case Operator.Inequality:
3926 method_name = "NotEqual";
3929 case Operator.LeftShift:
3930 method_name = "LeftShift";
3932 case Operator.LessThan:
3933 method_name = "LessThan";
3936 case Operator.LessThanOrEqual:
3937 method_name = "LessThanOrEqual";
3940 case Operator.LogicalAnd:
3941 method_name = "AndAlso";
3943 case Operator.LogicalOr:
3944 method_name = "OrElse";
3946 case Operator.Modulus:
3947 method_name = "Modulo";
3949 case Operator.Multiply:
3950 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3951 method_name = "MultiplyChecked";
3953 method_name = "Multiply";
3955 case Operator.RightShift:
3956 method_name = "RightShift";
3958 case Operator.Subtraction:
3959 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3960 method_name = "SubtractChecked";
3962 method_name = "Subtract";
3966 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3969 Arguments args = new Arguments (2);
3970 args.Add (new Argument (left.CreateExpressionTree (ec)));
3971 args.Add (new Argument (right.CreateExpressionTree (ec)));
3972 if (method != null) {
3974 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
3976 args.Add (new Argument (method));
3979 return CreateExpressionFactoryCall (ec, method_name, args);
3984 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3985 // b, c, d... may be strings or objects.
3987 public class StringConcat : Expression
3989 Arguments arguments;
3991 StringConcat (Location loc)
3994 arguments = new Arguments (2);
3997 public override bool ContainsEmitWithAwait ()
3999 return arguments.ContainsEmitWithAwait ();
4002 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4004 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4005 throw new ArgumentException ();
4007 var s = new StringConcat (loc);
4008 s.type = rc.BuiltinTypes.String;
4009 s.eclass = ExprClass.Value;
4011 s.Append (rc, left);
4012 s.Append (rc, right);
4016 public override Expression CreateExpressionTree (ResolveContext ec)
4018 Argument arg = arguments [0];
4019 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4023 // Creates nested calls tree from an array of arguments used for IL emit
4025 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4027 Arguments concat_args = new Arguments (2);
4028 Arguments add_args = new Arguments (3);
4030 concat_args.Add (left);
4031 add_args.Add (new Argument (left_etree));
4033 concat_args.Add (arguments [pos]);
4034 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4036 var methods = GetConcatMethodCandidates ();
4037 if (methods == null)
4040 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4041 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4045 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4047 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4048 if (++pos == arguments.Count)
4051 left = new Argument (new EmptyExpression (method.ReturnType));
4052 return CreateExpressionAddCall (ec, left, expr, pos);
4055 protected override Expression DoResolve (ResolveContext ec)
4060 void Append (ResolveContext rc, Expression operand)
4065 StringConstant sc = operand as StringConstant;
4067 if (arguments.Count != 0) {
4068 Argument last_argument = arguments [arguments.Count - 1];
4069 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4070 if (last_expr_constant != null) {
4071 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4077 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4079 StringConcat concat_oper = operand as StringConcat;
4080 if (concat_oper != null) {
4081 arguments.AddRange (concat_oper.arguments);
4086 arguments.Add (new Argument (operand));
4089 IList<MemberSpec> GetConcatMethodCandidates ()
4091 return MemberCache.FindMembers (type, "Concat", true);
4094 public override void Emit (EmitContext ec)
4096 var members = GetConcatMethodCandidates ();
4097 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4098 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4099 if (method != null) {
4100 var call = new CallEmitter ();
4101 call.EmitPredefined (ec, method, arguments);
4105 public override SLE.Expression MakeExpression (BuilderContext ctx)
4107 if (arguments.Count != 2)
4108 throw new NotImplementedException ("arguments.Count != 2");
4110 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4111 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4116 // User-defined conditional logical operator
4118 public class ConditionalLogicalOperator : UserOperatorCall
4120 readonly bool is_and;
4121 Expression oper_expr;
4123 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4124 : base (oper, arguments, expr_tree, loc)
4126 this.is_and = is_and;
4127 eclass = ExprClass.Unresolved;
4130 protected override Expression DoResolve (ResolveContext ec)
4132 AParametersCollection pd = oper.Parameters;
4133 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4134 ec.Report.Error (217, loc,
4135 "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",
4136 oper.GetSignatureForError ());
4140 Expression left_dup = new EmptyExpression (type);
4141 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4142 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4143 if (op_true == null || op_false == null) {
4144 ec.Report.Error (218, loc,
4145 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4146 TypeManager.CSharpName (type), oper.GetSignatureForError ());
4150 oper_expr = is_and ? op_false : op_true;
4151 eclass = ExprClass.Value;
4155 public override void Emit (EmitContext ec)
4157 Label end_target = ec.DefineLabel ();
4160 // Emit and duplicate left argument
4162 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
4163 if (right_contains_await) {
4164 arguments[0] = arguments[0].EmitToField (ec);
4165 arguments[0].Expr.Emit (ec);
4167 arguments[0].Expr.Emit (ec);
4168 ec.Emit (OpCodes.Dup);
4169 arguments.RemoveAt (0);
4172 oper_expr.EmitBranchable (ec, end_target, true);
4176 if (right_contains_await) {
4178 // Special handling when right expression contains await and left argument
4179 // could not be left on stack before logical branch
4181 Label skip_left_load = ec.DefineLabel ();
4182 ec.Emit (OpCodes.Br_S, skip_left_load);
4183 ec.MarkLabel (end_target);
4184 arguments[0].Expr.Emit (ec);
4185 ec.MarkLabel (skip_left_load);
4187 ec.MarkLabel (end_target);
4192 public class PointerArithmetic : Expression {
4193 Expression left, right;
4197 // We assume that `l' is always a pointer
4199 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4208 public override bool ContainsEmitWithAwait ()
4210 throw new NotImplementedException ();
4213 public override Expression CreateExpressionTree (ResolveContext ec)
4215 Error_PointerInsideExpressionTree (ec);
4219 protected override Expression DoResolve (ResolveContext ec)
4221 eclass = ExprClass.Variable;
4223 var pc = left.Type as PointerContainer;
4224 if (pc != null && pc.Element.Kind == MemberKind.Void) {
4225 Error_VoidPointerOperation (ec);
4232 public override void Emit (EmitContext ec)
4234 TypeSpec op_type = left.Type;
4236 // It must be either array or fixed buffer
4238 if (TypeManager.HasElementType (op_type)) {
4239 element = TypeManager.GetElementType (op_type);
4241 FieldExpr fe = left as FieldExpr;
4243 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
4248 int size = BuiltinTypeSpec.GetSize(element);
4249 TypeSpec rtype = right.Type;
4251 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4253 // handle (pointer - pointer)
4257 ec.Emit (OpCodes.Sub);
4261 ec.Emit (OpCodes.Sizeof, element);
4264 ec.Emit (OpCodes.Div);
4266 ec.Emit (OpCodes.Conv_I8);
4269 // handle + and - on (pointer op int)
4271 Constant left_const = left as Constant;
4272 if (left_const != null) {
4274 // Optimize ((T*)null) pointer operations
4276 if (left_const.IsDefaultValue) {
4277 left = EmptyExpression.Null;
4285 var right_const = right as Constant;
4286 if (right_const != null) {
4288 // Optimize 0-based arithmetic
4290 if (right_const.IsDefaultValue)
4294 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
4296 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
4298 // TODO: Should be the checks resolve context sensitive?
4299 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
4300 right = new Binary (Binary.Operator.Multiply, right, right_const, loc).Resolve (rc);
4306 switch (rtype.BuiltinType) {
4307 case BuiltinTypeSpec.Type.SByte:
4308 case BuiltinTypeSpec.Type.Byte:
4309 case BuiltinTypeSpec.Type.Short:
4310 case BuiltinTypeSpec.Type.UShort:
4311 ec.Emit (OpCodes.Conv_I);
4313 case BuiltinTypeSpec.Type.UInt:
4314 ec.Emit (OpCodes.Conv_U);
4318 if (right_const == null && size != 1){
4320 ec.Emit (OpCodes.Sizeof, element);
4323 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4324 ec.Emit (OpCodes.Conv_I8);
4326 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4329 if (left_const == null) {
4330 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
4331 ec.Emit (OpCodes.Conv_I);
4332 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4333 ec.Emit (OpCodes.Conv_U);
4335 Binary.EmitOperatorOpcode (ec, op, op_type);
4342 // A boolean-expression is an expression that yields a result
4345 public class BooleanExpression : ShimExpression
4347 public BooleanExpression (Expression expr)
4350 this.loc = expr.Location;
4353 public override Expression CreateExpressionTree (ResolveContext ec)
4355 // TODO: We should emit IsTrue (v4) instead of direct user operator
4356 // call but that would break csc compatibility
4357 return base.CreateExpressionTree (ec);
4360 protected override Expression DoResolve (ResolveContext ec)
4362 // A boolean-expression is required to be of a type
4363 // that can be implicitly converted to bool or of
4364 // a type that implements operator true
4366 expr = expr.Resolve (ec);
4370 Assign ass = expr as Assign;
4371 if (ass != null && ass.Source is Constant) {
4372 ec.Report.Warning (665, 3, loc,
4373 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4376 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
4379 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4380 Arguments args = new Arguments (1);
4381 args.Add (new Argument (expr));
4382 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
4385 type = ec.BuiltinTypes.Bool;
4386 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4387 if (converted != null)
4391 // If no implicit conversion to bool exists, try using `operator true'
4393 converted = GetOperatorTrue (ec, expr, loc);
4394 if (converted == null) {
4395 expr.Error_ValueCannotBeConverted (ec, loc, type, false);
4403 public class BooleanExpressionFalse : Unary
4405 public BooleanExpressionFalse (Expression expr)
4406 : base (Operator.LogicalNot, expr, expr.Location)
4410 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
4412 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
4417 /// Implements the ternary conditional operator (?:)
4419 public class Conditional : Expression {
4420 Expression expr, true_expr, false_expr;
4422 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
4425 this.true_expr = true_expr;
4426 this.false_expr = false_expr;
4432 public Expression Expr {
4438 public Expression TrueExpr {
4444 public Expression FalseExpr {
4452 public override bool ContainsEmitWithAwait ()
4454 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
4457 public override Expression CreateExpressionTree (ResolveContext ec)
4459 Arguments args = new Arguments (3);
4460 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4461 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4462 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4463 return CreateExpressionFactoryCall (ec, "Condition", args);
4466 protected override Expression DoResolve (ResolveContext ec)
4468 expr = expr.Resolve (ec);
4469 true_expr = true_expr.Resolve (ec);
4470 false_expr = false_expr.Resolve (ec);
4472 if (true_expr == null || false_expr == null || expr == null)
4475 eclass = ExprClass.Value;
4476 TypeSpec true_type = true_expr.Type;
4477 TypeSpec false_type = false_expr.Type;
4481 // First, if an implicit conversion exists from true_expr
4482 // to false_expr, then the result type is of type false_expr.Type
4484 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
4485 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4486 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
4488 // Check if both can convert implicitly to each other's type
4492 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic && Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
4493 ec.Report.Error (172, true_expr.Location,
4494 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
4495 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
4500 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4503 ec.Report.Error (173, true_expr.Location,
4504 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4505 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4510 // Dead code optimalization
4511 Constant c = expr as Constant;
4513 bool is_false = c.IsDefaultValue;
4514 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
4515 return ReducedExpression.Create (
4516 is_false ? false_expr : true_expr, this,
4517 false_expr is Constant && true_expr is Constant).Resolve (ec);
4523 public override void Emit (EmitContext ec)
4525 Label false_target = ec.DefineLabel ();
4526 Label end_target = ec.DefineLabel ();
4528 expr.EmitBranchable (ec, false_target, false);
4529 true_expr.Emit (ec);
4531 ec.Emit (OpCodes.Br, end_target);
4532 ec.MarkLabel (false_target);
4533 false_expr.Emit (ec);
4534 ec.MarkLabel (end_target);
4537 protected override void CloneTo (CloneContext clonectx, Expression t)
4539 Conditional target = (Conditional) t;
4541 target.expr = expr.Clone (clonectx);
4542 target.true_expr = true_expr.Clone (clonectx);
4543 target.false_expr = false_expr.Clone (clonectx);
4547 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
4549 LocalTemporary temp;
4552 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4554 public abstract bool IsLockedByStatement { get; set; }
4556 public abstract bool IsFixed { get; }
4557 public abstract bool IsRef { get; }
4558 public abstract string Name { get; }
4559 public abstract void SetHasAddressTaken ();
4562 // Variable IL data, it has to be protected to encapsulate hoisted variables
4564 protected abstract ILocalVariable Variable { get; }
4567 // Variable flow-analysis data
4569 public abstract VariableInfo VariableInfo { get; }
4572 public virtual void AddressOf (EmitContext ec, AddressOp mode)
4574 HoistedVariable hv = GetHoistedVariable (ec);
4576 hv.AddressOf (ec, mode);
4580 Variable.EmitAddressOf (ec);
4583 public override bool ContainsEmitWithAwait ()
4588 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
4590 if (IsLockedByStatement) {
4591 rc.Report.Warning (728, 2, loc,
4592 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
4599 public override void Emit (EmitContext ec)
4604 public override void EmitSideEffect (EmitContext ec)
4610 // This method is used by parameters that are references, that are
4611 // being passed as references: we only want to pass the pointer (that
4612 // is already stored in the parameter, not the address of the pointer,
4613 // and not the value of the variable).
4615 public void EmitLoad (EmitContext ec)
4620 public void Emit (EmitContext ec, bool leave_copy)
4622 HoistedVariable hv = GetHoistedVariable (ec);
4624 hv.Emit (ec, leave_copy);
4632 // If we are a reference, we loaded on the stack a pointer
4633 // Now lets load the real value
4635 ec.EmitLoadFromPtr (type);
4639 ec.Emit (OpCodes.Dup);
4642 temp = new LocalTemporary (Type);
4648 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4649 bool prepare_for_load)
4651 HoistedVariable hv = GetHoistedVariable (ec);
4653 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4657 New n_source = source as New;
4658 if (n_source != null) {
4659 if (!n_source.Emit (ec, this)) {
4663 ec.EmitLoadFromPtr (type);
4675 ec.Emit (OpCodes.Dup);
4677 temp = new LocalTemporary (Type);
4683 ec.EmitStoreFromPtr (type);
4685 Variable.EmitAssign (ec);
4693 public override Expression EmitToField (EmitContext ec)
4695 HoistedVariable hv = GetHoistedVariable (ec);
4697 return hv.EmitToField (ec);
4700 return base.EmitToField (ec);
4703 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4705 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4708 public HoistedVariable GetHoistedVariable (EmitContext ec)
4710 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4713 public override string GetSignatureForError ()
4718 public bool IsHoisted {
4719 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4724 // Resolved reference to a local variable
4726 public class LocalVariableReference : VariableReference
4728 public LocalVariable local_info;
4730 public LocalVariableReference (LocalVariable li, Location l)
4732 this.local_info = li;
4736 public override VariableInfo VariableInfo {
4737 get { return local_info.VariableInfo; }
4740 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4742 return local_info.HoistedVariant;
4748 // A local variable is always fixed
4750 public override bool IsFixed {
4756 public override bool IsLockedByStatement {
4758 return local_info.IsLocked;
4761 local_info.IsLocked = value;
4765 public override bool IsRef {
4766 get { return false; }
4769 public override string Name {
4770 get { return local_info.Name; }
4775 public bool VerifyAssigned (ResolveContext ec)
4777 VariableInfo variable_info = local_info.VariableInfo;
4778 return variable_info == null || variable_info.IsAssigned (ec, loc);
4781 public override void SetHasAddressTaken ()
4783 local_info.AddressTaken = true;
4786 public override Expression CreateExpressionTree (ResolveContext ec)
4788 HoistedVariable hv = GetHoistedVariable (ec);
4790 return hv.CreateExpressionTree ();
4792 Arguments arg = new Arguments (1);
4793 arg.Add (new Argument (this));
4794 return CreateExpressionFactoryCall (ec, "Constant", arg);
4797 void DoResolveBase (ResolveContext ec)
4799 VerifyAssigned (ec);
4802 // If we are referencing a variable from the external block
4803 // flag it for capturing
4805 if (ec.MustCaptureVariable (local_info)) {
4806 if (local_info.AddressTaken) {
4807 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4808 } else if (local_info.IsFixed) {
4809 ec.Report.Error (1764, loc,
4810 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
4811 GetSignatureForError ());
4814 if (ec.IsVariableCapturingRequired) {
4815 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4816 storey.CaptureLocalVariable (ec, local_info);
4820 eclass = ExprClass.Variable;
4821 type = local_info.Type;
4824 protected override Expression DoResolve (ResolveContext ec)
4826 local_info.SetIsUsed ();
4832 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4835 if (right_side == EmptyExpression.OutAccess)
4836 local_info.SetIsUsed ();
4838 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
4841 if (right_side == EmptyExpression.OutAccess) {
4842 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4843 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4844 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4845 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4846 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4847 } else if (right_side == EmptyExpression.UnaryAddress) {
4848 code = 459; msg = "Cannot take the address of {1} `{0}'";
4850 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4852 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4853 } else if (VariableInfo != null) {
4854 VariableInfo.SetAssigned (ec);
4859 return base.DoResolveLValue (ec, right_side);
4862 public override int GetHashCode ()
4864 return local_info.GetHashCode ();
4867 public override bool Equals (object obj)
4869 LocalVariableReference lvr = obj as LocalVariableReference;
4873 return local_info == lvr.local_info;
4876 protected override ILocalVariable Variable {
4877 get { return local_info; }
4880 public override string ToString ()
4882 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4885 protected override void CloneTo (CloneContext clonectx, Expression t)
4892 /// This represents a reference to a parameter in the intermediate
4895 public class ParameterReference : VariableReference
4897 protected ParametersBlock.ParameterInfo pi;
4899 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
4907 public override bool IsLockedByStatement {
4912 pi.IsLocked = value;
4916 public override bool IsRef {
4917 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4920 bool HasOutModifier {
4921 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4924 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4926 return pi.Parameter.HoistedVariant;
4930 // A ref or out parameter is classified as a moveable variable, even
4931 // if the argument given for the parameter is a fixed variable
4933 public override bool IsFixed {
4934 get { return !IsRef; }
4937 public override string Name {
4938 get { return Parameter.Name; }
4941 public Parameter Parameter {
4942 get { return pi.Parameter; }
4945 public override VariableInfo VariableInfo {
4946 get { return pi.VariableInfo; }
4949 protected override ILocalVariable Variable {
4950 get { return Parameter; }
4955 public bool IsAssigned (ResolveContext ec, Location loc)
4957 // HACK: Variables are not captured in probing mode
4958 if (ec.IsInProbingMode)
4961 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4964 ec.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4968 public override void SetHasAddressTaken ()
4970 Parameter.HasAddressTaken = true;
4973 void SetAssigned (ResolveContext ec)
4975 if (HasOutModifier && ec.DoFlowAnalysis)
4976 ec.CurrentBranching.SetAssigned (VariableInfo);
4979 bool DoResolveBase (ResolveContext ec)
4981 if (eclass != ExprClass.Unresolved)
4984 type = pi.ParameterType;
4985 eclass = ExprClass.Variable;
4988 // If we are referencing a parameter from the external block
4989 // flag it for capturing
4991 if (ec.MustCaptureVariable (pi)) {
4992 if (Parameter.HasAddressTaken)
4993 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4996 ec.Report.Error (1628, loc,
4997 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4998 Name, ec.CurrentAnonymousMethod.ContainerType);
5001 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5002 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5003 storey.CaptureParameter (ec, this);
5010 public override int GetHashCode ()
5012 return Name.GetHashCode ();
5015 public override bool Equals (object obj)
5017 ParameterReference pr = obj as ParameterReference;
5021 return Name == pr.Name;
5024 public override void AddressOf (EmitContext ec, AddressOp mode)
5027 // ParameterReferences might already be a reference
5034 base.AddressOf (ec, mode);
5037 protected override void CloneTo (CloneContext clonectx, Expression target)
5043 public override Expression CreateExpressionTree (ResolveContext ec)
5045 HoistedVariable hv = GetHoistedVariable (ec);
5047 return hv.CreateExpressionTree ();
5049 return Parameter.ExpressionTreeVariableReference ();
5053 // Notice that for ref/out parameters, the type exposed is not the
5054 // same type exposed externally.
5057 // externally we expose "int&"
5058 // here we expose "int".
5060 // We record this in "is_ref". This means that the type system can treat
5061 // the type as it is expected, but when we generate the code, we generate
5062 // the alternate kind of code.
5064 protected override Expression DoResolve (ResolveContext ec)
5066 if (!DoResolveBase (ec))
5069 // HACK: Variables are not captured in probing mode
5070 if (ec.IsInProbingMode)
5073 if (HasOutModifier && ec.DoFlowAnalysis &&
5074 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
5080 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5082 if (!DoResolveBase (ec))
5086 return base.DoResolveLValue (ec, right_side);
5091 /// Invocation of methods or delegates.
5093 public class Invocation : ExpressionStatement
5095 protected Arguments arguments;
5096 protected Expression expr;
5097 protected MethodGroupExpr mg;
5099 public Invocation (Expression expr, Arguments arguments)
5102 this.arguments = arguments;
5104 loc = expr.Location;
5108 public Arguments Arguments {
5114 public Expression Expression {
5121 protected override void CloneTo (CloneContext clonectx, Expression t)
5123 Invocation target = (Invocation) t;
5125 if (arguments != null)
5126 target.arguments = arguments.Clone (clonectx);
5128 target.expr = expr.Clone (clonectx);
5131 public override bool ContainsEmitWithAwait ()
5133 if (arguments != null && arguments.ContainsEmitWithAwait ())
5136 return mg.ContainsEmitWithAwait ();
5139 public override Expression CreateExpressionTree (ResolveContext ec)
5141 Expression instance = mg.IsInstance ?
5142 mg.InstanceExpression.CreateExpressionTree (ec) :
5143 new NullLiteral (loc);
5145 var args = Arguments.CreateForExpressionTree (ec, arguments,
5147 mg.CreateExpressionTree (ec));
5149 return CreateExpressionFactoryCall (ec, "Call", args);
5152 protected override Expression DoResolve (ResolveContext ec)
5154 Expression member_expr;
5155 var atn = expr as ATypeNameExpression;
5157 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
5158 if (member_expr != null)
5159 member_expr = member_expr.Resolve (ec);
5161 member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5164 if (member_expr == null)
5168 // Next, evaluate all the expressions in the argument list
5170 bool dynamic_arg = false;
5171 if (arguments != null)
5172 arguments.Resolve (ec, out dynamic_arg);
5174 TypeSpec expr_type = member_expr.Type;
5175 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5176 return DoResolveDynamic (ec, member_expr);
5178 mg = member_expr as MethodGroupExpr;
5179 Expression invoke = null;
5182 if (expr_type != null && TypeManager.IsDelegateType (expr_type)) {
5183 invoke = new DelegateInvocation (member_expr, arguments, loc);
5184 invoke = invoke.Resolve (ec);
5185 if (invoke == null || !dynamic_arg)
5188 if (member_expr is RuntimeValueExpression) {
5189 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
5190 member_expr.Type.GetSignatureForError ()); ;
5194 MemberExpr me = member_expr as MemberExpr;
5196 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5200 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
5201 member_expr.GetSignatureForError ());
5206 if (invoke == null) {
5207 mg = DoResolveOverload (ec);
5213 return DoResolveDynamic (ec, member_expr);
5215 var method = mg.BestCandidate;
5216 type = mg.BestCandidateReturnType;
5218 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
5220 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5222 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5226 IsSpecialMethodInvocation (ec, method, loc);
5228 eclass = ExprClass.Value;
5232 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
5235 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
5237 args = dmb.Arguments;
5238 if (arguments != null)
5239 args.AddRange (arguments);
5240 } else if (mg == null) {
5241 if (arguments == null)
5242 args = new Arguments (1);
5246 args.Insert (0, new Argument (memberExpr));
5250 ec.Report.Error (1971, loc,
5251 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
5256 if (arguments == null)
5257 args = new Arguments (1);
5261 MemberAccess ma = expr as MemberAccess;
5263 var left_type = ma.LeftExpression as TypeExpr;
5264 if (left_type != null) {
5265 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5268 // Any value type has to be pass as by-ref to get back the same
5269 // instance on which the member was called
5271 var mod = TypeSpec.IsValueType (ma.LeftExpression.Type) ? Argument.AType.Ref : Argument.AType.None;
5272 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
5274 } else { // is SimpleName
5276 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5278 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5283 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5286 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5288 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
5291 static MetaType[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
5293 AParametersCollection pd = mb.Parameters;
5295 Argument a = arguments[pd.Count - 1];
5296 Arglist list = (Arglist) a.Expr;
5298 return list.ArgumentTypes;
5302 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
5303 // or the type dynamic, then the member is invocable
5305 public static bool IsMemberInvocable (MemberSpec member)
5307 switch (member.Kind) {
5308 case MemberKind.Event:
5310 case MemberKind.Field:
5311 case MemberKind.Property:
5312 var m = member as IInterfaceMemberSpec;
5313 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
5319 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
5321 if (!method.IsReservedMethod)
5324 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
5327 ec.Report.SymbolRelatedToPreviousError (method);
5328 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5329 method.GetSignatureForError ());
5334 public override void Emit (EmitContext ec)
5336 mg.EmitCall (ec, arguments);
5339 public override void EmitStatement (EmitContext ec)
5344 // Pop the return value if there is one
5346 if (type.Kind != MemberKind.Void)
5347 ec.Emit (OpCodes.Pop);
5350 public override SLE.Expression MakeExpression (BuilderContext ctx)
5352 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
5355 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
5358 throw new NotSupportedException ();
5360 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5361 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
5367 // Implements simple new expression
5369 public class New : ExpressionStatement, IMemoryLocation
5371 protected Arguments arguments;
5374 // During bootstrap, it contains the RequestedType,
5375 // but if `type' is not null, it *might* contain a NewDelegate
5376 // (because of field multi-initialization)
5378 protected Expression RequestedType;
5380 protected MethodSpec method;
5382 public New (Expression requested_type, Arguments arguments, Location l)
5384 RequestedType = requested_type;
5385 this.arguments = arguments;
5390 public Arguments Arguments {
5397 // Returns true for resolved `new S()'
5399 public bool IsDefaultStruct {
5401 return arguments == null && type.IsStruct && GetType () == typeof (New);
5408 /// Converts complex core type syntax like 'new int ()' to simple constant
5410 public static Constant Constantify (TypeSpec t, Location loc)
5412 switch (t.BuiltinType) {
5413 case BuiltinTypeSpec.Type.Int:
5414 return new IntConstant (t, 0, loc);
5415 case BuiltinTypeSpec.Type.UInt:
5416 return new UIntConstant (t, 0, loc);
5417 case BuiltinTypeSpec.Type.Long:
5418 return new LongConstant (t, 0, loc);
5419 case BuiltinTypeSpec.Type.ULong:
5420 return new ULongConstant (t, 0, loc);
5421 case BuiltinTypeSpec.Type.Float:
5422 return new FloatConstant (t, 0, loc);
5423 case BuiltinTypeSpec.Type.Double:
5424 return new DoubleConstant (t, 0, loc);
5425 case BuiltinTypeSpec.Type.Short:
5426 return new ShortConstant (t, 0, loc);
5427 case BuiltinTypeSpec.Type.UShort:
5428 return new UShortConstant (t, 0, loc);
5429 case BuiltinTypeSpec.Type.SByte:
5430 return new SByteConstant (t, 0, loc);
5431 case BuiltinTypeSpec.Type.Byte:
5432 return new ByteConstant (t, 0, loc);
5433 case BuiltinTypeSpec.Type.Char:
5434 return new CharConstant (t, '\0', loc);
5435 case BuiltinTypeSpec.Type.Bool:
5436 return new BoolConstant (t, false, loc);
5437 case BuiltinTypeSpec.Type.Decimal:
5438 return new DecimalConstant (t, 0, loc);
5442 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
5444 if (t.IsNullableType)
5445 return Nullable.LiftedNull.Create (t, loc);
5450 public override bool ContainsEmitWithAwait ()
5452 return arguments != null && arguments.ContainsEmitWithAwait ();
5456 // Checks whether the type is an interface that has the
5457 // [ComImport, CoClass] attributes and must be treated
5460 public Expression CheckComImport (ResolveContext ec)
5462 if (!type.IsInterface)
5466 // Turn the call into:
5467 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5469 var real_class = type.MemberDefinition.GetAttributeCoClass ();
5470 if (real_class == null)
5473 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
5474 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5475 return cast.Resolve (ec);
5478 public override Expression CreateExpressionTree (ResolveContext ec)
5481 if (method == null) {
5482 args = new Arguments (1);
5483 args.Add (new Argument (new TypeOf (type, loc)));
5485 args = Arguments.CreateForExpressionTree (ec,
5486 arguments, new TypeOfMethod (method, loc));
5489 return CreateExpressionFactoryCall (ec, "New", args);
5492 protected override Expression DoResolve (ResolveContext ec)
5494 type = RequestedType.ResolveAsType (ec);
5498 eclass = ExprClass.Value;
5500 if (type.IsPointer) {
5501 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5502 TypeManager.CSharpName (type));
5506 if (arguments == null) {
5507 Constant c = Constantify (type, RequestedType.Location);
5509 return ReducedExpression.Create (c, this);
5512 if (TypeManager.IsDelegateType (type)) {
5513 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
5516 var tparam = type as TypeParameterSpec;
5517 if (tparam != null) {
5519 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
5520 // where type parameter constraint is inflated to struct
5522 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !tparam.BaseType.IsStruct) {
5523 ec.Report.Error (304, loc,
5524 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
5525 TypeManager.CSharpName (type));
5528 if ((arguments != null) && (arguments.Count != 0)) {
5529 ec.Report.Error (417, loc,
5530 "`{0}': cannot provide arguments when creating an instance of a variable type",
5531 TypeManager.CSharpName (type));
5537 if (type.IsStatic) {
5538 ec.Report.SymbolRelatedToPreviousError (type);
5539 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5543 if (type.IsInterface || type.IsAbstract){
5544 if (!TypeManager.IsGenericType (type)) {
5545 RequestedType = CheckComImport (ec);
5546 if (RequestedType != null)
5547 return RequestedType;
5550 ec.Report.SymbolRelatedToPreviousError (type);
5551 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5556 // Any struct always defines parameterless constructor
5558 if (type.IsStruct && arguments == null)
5562 if (arguments != null) {
5563 arguments.Resolve (ec, out dynamic);
5568 method = ConstructorLookup (ec, type, ref arguments, loc);
5571 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5572 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
5578 bool DoEmitTypeParameter (EmitContext ec)
5580 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
5584 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
5585 var tparam = (TypeParameterSpec) type;
5587 if (tparam.IsReferenceType) {
5588 ec.Emit (OpCodes.Call, ctor_factory);
5592 // Allow DoEmit() to be called multiple times.
5593 // We need to create a new LocalTemporary each time since
5594 // you can't share LocalBuilders among ILGeneators.
5595 LocalTemporary temp = new LocalTemporary (type);
5597 Label label_activator = ec.DefineLabel ();
5598 Label label_end = ec.DefineLabel ();
5600 temp.AddressOf (ec, AddressOp.Store);
5601 ec.Emit (OpCodes.Initobj, type);
5604 ec.Emit (OpCodes.Box, type);
5605 ec.Emit (OpCodes.Brfalse, label_activator);
5607 temp.AddressOf (ec, AddressOp.Store);
5608 ec.Emit (OpCodes.Initobj, type);
5611 ec.Emit (OpCodes.Br_S, label_end);
5613 ec.MarkLabel (label_activator);
5615 ec.Emit (OpCodes.Call, ctor_factory);
5616 ec.MarkLabel (label_end);
5621 // This Emit can be invoked in two contexts:
5622 // * As a mechanism that will leave a value on the stack (new object)
5623 // * As one that wont (init struct)
5625 // If we are dealing with a ValueType, we have a few
5626 // situations to deal with:
5628 // * The target is a ValueType, and we have been provided
5629 // the instance (this is easy, we are being assigned).
5631 // * The target of New is being passed as an argument,
5632 // to a boxing operation or a function that takes a
5635 // In this case, we need to create a temporary variable
5636 // that is the argument of New.
5638 // Returns whether a value is left on the stack
5640 // *** Implementation note ***
5642 // To benefit from this optimization, each assignable expression
5643 // has to manually cast to New and call this Emit.
5645 // TODO: It's worth to implement it for arrays and fields
5647 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5649 bool is_value_type = TypeSpec.IsValueType (type);
5650 VariableReference vr = target as VariableReference;
5652 if (target != null && is_value_type && (vr != null || method == null)) {
5653 target.AddressOf (ec, AddressOp.Store);
5654 } else if (vr != null && vr.IsRef) {
5658 if (arguments != null) {
5659 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
5660 arguments = arguments.Emit (ec, false, true);
5662 arguments.Emit (ec);
5665 if (is_value_type) {
5666 if (method == null) {
5667 ec.Emit (OpCodes.Initobj, type);
5672 ec.Emit (OpCodes.Call, method);
5677 if (type is TypeParameterSpec)
5678 return DoEmitTypeParameter (ec);
5680 ec.Emit (OpCodes.Newobj, method);
5684 public override void Emit (EmitContext ec)
5686 LocalTemporary v = null;
5687 if (method == null && TypeSpec.IsValueType (type)) {
5688 // TODO: Use temporary variable from pool
5689 v = new LocalTemporary (type);
5696 public override void EmitStatement (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);
5705 ec.Emit (OpCodes.Pop);
5708 public void AddressOf (EmitContext ec, AddressOp mode)
5710 EmitAddressOf (ec, mode);
5713 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5715 LocalTemporary value_target = new LocalTemporary (type);
5717 if (type is TypeParameterSpec) {
5718 DoEmitTypeParameter (ec);
5719 value_target.Store (ec);
5720 value_target.AddressOf (ec, mode);
5721 return value_target;
5724 value_target.AddressOf (ec, AddressOp.Store);
5726 if (method == null) {
5727 ec.Emit (OpCodes.Initobj, type);
5729 if (arguments != null)
5730 arguments.Emit (ec);
5732 ec.Emit (OpCodes.Call, method);
5735 value_target.AddressOf (ec, mode);
5736 return value_target;
5739 protected override void CloneTo (CloneContext clonectx, Expression t)
5741 New target = (New) t;
5743 target.RequestedType = RequestedType.Clone (clonectx);
5744 if (arguments != null){
5745 target.arguments = arguments.Clone (clonectx);
5749 public override SLE.Expression MakeExpression (BuilderContext ctx)
5752 return base.MakeExpression (ctx);
5754 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
5760 // Array initializer expression, the expression is allowed in
5761 // variable or field initialization only which makes it tricky as
5762 // the type has to be infered based on the context either from field
5763 // type or variable type (think of multiple declarators)
5765 public class ArrayInitializer : Expression
5767 List<Expression> elements;
5768 BlockVariableDeclaration variable;
5770 public ArrayInitializer (List<Expression> init, Location loc)
5776 public ArrayInitializer (int count, Location loc)
5777 : this (new List<Expression> (count), loc)
5781 public ArrayInitializer (Location loc)
5789 get { return elements.Count; }
5792 public Expression this [int index] {
5794 return elements [index];
5798 public BlockVariableDeclaration VariableDeclaration {
5809 public void Add (Expression expr)
5811 elements.Add (expr);
5814 public override bool ContainsEmitWithAwait ()
5816 throw new NotSupportedException ();
5819 public override Expression CreateExpressionTree (ResolveContext ec)
5821 throw new NotSupportedException ("ET");
5824 protected override void CloneTo (CloneContext clonectx, Expression t)
5826 var target = (ArrayInitializer) t;
5828 target.elements = new List<Expression> (elements.Count);
5829 foreach (var element in elements)
5830 target.elements.Add (element.Clone (clonectx));
5833 protected override Expression DoResolve (ResolveContext rc)
5835 var current_field = rc.CurrentMemberDefinition as FieldBase;
5836 TypeExpression type;
5837 if (current_field != null) {
5838 type = new TypeExpression (current_field.MemberType, current_field.Location);
5839 } else if (variable != null) {
5840 if (variable.TypeExpression is VarExpr) {
5841 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5842 return EmptyExpression.Null;
5845 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
5847 throw new NotImplementedException ("Unexpected array initializer context");
5850 return new ArrayCreation (type, this).Resolve (rc);
5853 public override void Emit (EmitContext ec)
5855 throw new InternalErrorException ("Missing Resolve call");
5860 /// 14.5.10.2: Represents an array creation expression.
5864 /// There are two possible scenarios here: one is an array creation
5865 /// expression that specifies the dimensions and optionally the
5866 /// initialization data and the other which does not need dimensions
5867 /// specified but where initialization data is mandatory.
5869 public class ArrayCreation : Expression
5871 FullNamedExpression requested_base_type;
5872 ArrayInitializer initializers;
5875 // The list of Argument types.
5876 // This is used to construct the `newarray' or constructor signature
5878 protected List<Expression> arguments;
5880 protected TypeSpec array_element_type;
5881 int num_arguments = 0;
5882 protected int dimensions;
5883 protected readonly ComposedTypeSpecifier rank;
5884 Expression first_emit;
5885 LocalTemporary first_emit_temp;
5887 protected List<Expression> array_data;
5889 Dictionary<int, int> bounds;
5891 // The number of constants in array initializers
5892 int const_initializers_count;
5893 bool only_constant_initializers;
5895 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
5896 : this (requested_base_type, rank, initializers, l)
5898 arguments = new List<Expression> (exprs);
5899 num_arguments = arguments.Count;
5903 // For expressions like int[] foo = new int[] { 1, 2, 3 };
5905 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
5907 this.requested_base_type = requested_base_type;
5909 this.initializers = initializers;
5913 num_arguments = rank.Dimension;
5917 // For compiler generated single dimensional arrays only
5919 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
5920 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
5925 // For expressions like int[] foo = { 1, 2, 3 };
5927 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
5928 : this (requested_base_type, null, initializers, initializers.Location)
5932 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
5934 if (initializers != null && bounds == null) {
5936 // We use this to store all the date values in the order in which we
5937 // will need to store them in the byte blob later
5939 array_data = new List<Expression> ();
5940 bounds = new Dictionary<int, int> ();
5943 if (specified_dims) {
5944 Expression a = arguments [idx];
5949 a = ConvertExpressionToArrayIndex (ec, a);
5955 if (initializers != null) {
5956 Constant c = a as Constant;
5957 if (c == null && a is ArrayIndexCast)
5958 c = ((ArrayIndexCast) a).Child as Constant;
5961 ec.Report.Error (150, a.Location, "A constant value is expected");
5967 value = System.Convert.ToInt32 (c.GetValue ());
5969 ec.Report.Error (150, a.Location, "A constant value is expected");
5973 // TODO: probe.Count does not fit ulong in
5974 if (value != probe.Count) {
5975 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
5979 bounds[idx] = value;
5983 if (initializers == null)
5986 for (int i = 0; i < probe.Count; ++i) {
5988 if (o is ArrayInitializer) {
5989 var sub_probe = o as ArrayInitializer;
5990 if (idx + 1 >= dimensions){
5991 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5995 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
5998 } else if (child_bounds > 1) {
5999 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6001 Expression element = ResolveArrayElement (ec, o);
6002 if (element == null)
6005 // Initializers with the default values can be ignored
6006 Constant c = element as Constant;
6008 if (!c.IsDefaultInitializer (array_element_type)) {
6009 ++const_initializers_count;
6012 only_constant_initializers = false;
6015 array_data.Add (element);
6022 public override bool ContainsEmitWithAwait ()
6024 foreach (var arg in arguments) {
6025 if (arg.ContainsEmitWithAwait ())
6029 return InitializersContainAwait ();
6032 public override Expression CreateExpressionTree (ResolveContext ec)
6036 if (array_data == null) {
6037 args = new Arguments (arguments.Count + 1);
6038 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6039 foreach (Expression a in arguments)
6040 args.Add (new Argument (a.CreateExpressionTree (ec)));
6042 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6045 if (dimensions > 1) {
6046 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6050 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6051 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6052 if (array_data != null) {
6053 for (int i = 0; i < array_data.Count; ++i) {
6054 Expression e = array_data [i];
6055 args.Add (new Argument (e.CreateExpressionTree (ec)));
6059 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6062 void UpdateIndices (ResolveContext rc)
6065 for (var probe = initializers; probe != null;) {
6066 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
6068 bounds[i++] = probe.Count;
6070 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
6071 probe = (ArrayInitializer) probe[0];
6072 } else if (dimensions > i) {
6080 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
6082 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
6085 bool InitializersContainAwait ()
6087 if (array_data == null)
6090 foreach (var expr in array_data) {
6091 if (expr.ContainsEmitWithAwait ())
6098 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
6100 element = element.Resolve (ec);
6101 if (element == null)
6104 if (element is CompoundAssign.TargetExpression) {
6105 if (first_emit != null)
6106 throw new InternalErrorException ("Can only handle one mutator at a time");
6107 first_emit = element;
6108 element = first_emit_temp = new LocalTemporary (element.Type);
6111 return Convert.ImplicitConversionRequired (
6112 ec, element, array_element_type, loc);
6115 protected bool ResolveInitializers (ResolveContext ec)
6117 only_constant_initializers = true;
6119 if (arguments != null) {
6121 for (int i = 0; i < arguments.Count; ++i) {
6122 res &= CheckIndices (ec, initializers, i, true, dimensions);
6123 if (initializers != null)
6130 arguments = new List<Expression> ();
6132 if (!CheckIndices (ec, initializers, 0, false, dimensions))
6141 // Resolved the type of the array
6143 bool ResolveArrayType (ResolveContext ec)
6148 FullNamedExpression array_type_expr;
6149 if (num_arguments > 0) {
6150 array_type_expr = new ComposedCast (requested_base_type, rank);
6152 array_type_expr = requested_base_type;
6155 type = array_type_expr.ResolveAsType (ec);
6156 if (array_type_expr == null)
6159 var ac = type as ArrayContainer;
6161 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6165 array_element_type = ac.Element;
6166 dimensions = ac.Rank;
6171 protected override Expression DoResolve (ResolveContext ec)
6176 if (!ResolveArrayType (ec))
6180 // validate the initializers and fill in any missing bits
6182 if (!ResolveInitializers (ec))
6185 eclass = ExprClass.Value;
6189 byte [] MakeByteBlob ()
6194 int count = array_data.Count;
6196 TypeSpec element_type = array_element_type;
6197 if (TypeManager.IsEnumType (element_type))
6198 element_type = EnumSpec.GetUnderlyingType (element_type);
6200 factor = BuiltinTypeSpec.GetSize (element_type);
6202 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6204 data = new byte [(count * factor + 3) & ~3];
6207 for (int i = 0; i < count; ++i) {
6208 var c = array_data[i] as Constant;
6214 object v = c.GetValue ();
6216 switch (element_type.BuiltinType) {
6217 case BuiltinTypeSpec.Type.Long:
6218 long lval = (long) v;
6220 for (int j = 0; j < factor; ++j) {
6221 data[idx + j] = (byte) (lval & 0xFF);
6225 case BuiltinTypeSpec.Type.ULong:
6226 ulong ulval = (ulong) v;
6228 for (int j = 0; j < factor; ++j) {
6229 data[idx + j] = (byte) (ulval & 0xFF);
6230 ulval = (ulval >> 8);
6233 case BuiltinTypeSpec.Type.Float:
6234 element = BitConverter.GetBytes ((float) v);
6236 for (int j = 0; j < factor; ++j)
6237 data[idx + j] = element[j];
6238 if (!BitConverter.IsLittleEndian)
6239 System.Array.Reverse (data, idx, 4);
6241 case BuiltinTypeSpec.Type.Double:
6242 element = BitConverter.GetBytes ((double) v);
6244 for (int j = 0; j < factor; ++j)
6245 data[idx + j] = element[j];
6247 // FIXME: Handle the ARM float format.
6248 if (!BitConverter.IsLittleEndian)
6249 System.Array.Reverse (data, idx, 8);
6251 case BuiltinTypeSpec.Type.Char:
6252 int chval = (int) ((char) v);
6254 data[idx] = (byte) (chval & 0xff);
6255 data[idx + 1] = (byte) (chval >> 8);
6257 case BuiltinTypeSpec.Type.Short:
6258 int sval = (int) ((short) v);
6260 data[idx] = (byte) (sval & 0xff);
6261 data[idx + 1] = (byte) (sval >> 8);
6263 case BuiltinTypeSpec.Type.UShort:
6264 int usval = (int) ((ushort) v);
6266 data[idx] = (byte) (usval & 0xff);
6267 data[idx + 1] = (byte) (usval >> 8);
6269 case BuiltinTypeSpec.Type.Int:
6272 data[idx] = (byte) (val & 0xff);
6273 data[idx + 1] = (byte) ((val >> 8) & 0xff);
6274 data[idx + 2] = (byte) ((val >> 16) & 0xff);
6275 data[idx + 3] = (byte) (val >> 24);
6277 case BuiltinTypeSpec.Type.UInt:
6278 uint uval = (uint) v;
6280 data[idx] = (byte) (uval & 0xff);
6281 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
6282 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
6283 data[idx + 3] = (byte) (uval >> 24);
6285 case BuiltinTypeSpec.Type.SByte:
6286 data[idx] = (byte) (sbyte) v;
6288 case BuiltinTypeSpec.Type.Byte:
6289 data[idx] = (byte) v;
6291 case BuiltinTypeSpec.Type.Bool:
6292 data[idx] = (byte) ((bool) v ? 1 : 0);
6294 case BuiltinTypeSpec.Type.Decimal:
6295 int[] bits = Decimal.GetBits ((decimal) v);
6298 // FIXME: For some reason, this doesn't work on the MS runtime.
6299 int[] nbits = new int[4];
6305 for (int j = 0; j < 4; j++) {
6306 data[p++] = (byte) (nbits[j] & 0xff);
6307 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
6308 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
6309 data[p++] = (byte) (nbits[j] >> 24);
6313 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6323 public override SLE.Expression MakeExpression (BuilderContext ctx)
6326 return base.MakeExpression (ctx);
6328 var initializers = new SLE.Expression [array_data.Count];
6329 for (var i = 0; i < initializers.Length; i++) {
6330 if (array_data [i] == null)
6331 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
6333 initializers [i] = array_data [i].MakeExpression (ctx);
6336 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
6342 // Emits the initializers for the array
6344 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
6346 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
6351 // First, the static data
6353 byte [] data = MakeByteBlob ();
6354 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
6356 if (stackArray == null) {
6357 ec.Emit (OpCodes.Dup);
6359 stackArray.Emit (ec);
6362 ec.Emit (OpCodes.Ldtoken, fb);
6363 ec.Emit (OpCodes.Call, m);
6368 // Emits pieces of the array that can not be computed at compile
6369 // time (variables and string locations).
6371 // This always expect the top value on the stack to be the array
6373 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
6375 int dims = bounds.Count;
6376 var current_pos = new int [dims];
6378 for (int i = 0; i < array_data.Count; i++){
6380 Expression e = array_data [i];
6381 var c = e as Constant;
6383 // Constant can be initialized via StaticInitializer
6384 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
6388 if (stackArray != null) {
6389 if (e.ContainsEmitWithAwait ()) {
6390 e = e.EmitToField (ec);
6393 stackArray.Emit (ec);
6395 ec.Emit (OpCodes.Dup);
6398 for (int idx = 0; idx < dims; idx++)
6399 ec.EmitInt (current_pos [idx]);
6402 // If we are dealing with a struct, get the
6403 // address of it, so we can store it.
6405 if (dims == 1 && etype.IsStruct) {
6406 switch (etype.BuiltinType) {
6407 case BuiltinTypeSpec.Type.Byte:
6408 case BuiltinTypeSpec.Type.SByte:
6409 case BuiltinTypeSpec.Type.Bool:
6410 case BuiltinTypeSpec.Type.Short:
6411 case BuiltinTypeSpec.Type.UShort:
6412 case BuiltinTypeSpec.Type.Char:
6413 case BuiltinTypeSpec.Type.Int:
6414 case BuiltinTypeSpec.Type.UInt:
6415 case BuiltinTypeSpec.Type.Long:
6416 case BuiltinTypeSpec.Type.ULong:
6417 case BuiltinTypeSpec.Type.Float:
6418 case BuiltinTypeSpec.Type.Double:
6421 ec.Emit (OpCodes.Ldelema, etype);
6428 ec.EmitArrayStore ((ArrayContainer) type);
6434 for (int j = dims - 1; j >= 0; j--){
6436 if (current_pos [j] < bounds [j])
6438 current_pos [j] = 0;
6443 public override void Emit (EmitContext ec)
6445 if (first_emit != null) {
6446 first_emit.Emit (ec);
6447 first_emit_temp.Store (ec);
6450 FieldExpr await_stack_field;
6451 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
6452 await_stack_field = ec.GetTemporaryField (type);
6455 await_stack_field = null;
6458 EmitExpressionsList (ec, arguments);
6460 ec.EmitArrayNew ((ArrayContainer) type);
6462 if (initializers == null)
6465 if (await_stack_field != null)
6466 await_stack_field.EmitAssignFromStack (ec);
6470 // Emit static initializer for arrays which contain more than 2 items and
6471 // the static initializer will initialize at least 25% of array values or there
6472 // is more than 10 items to be initialized
6474 // NOTE: const_initializers_count does not contain default constant values.
6476 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
6477 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
6478 EmitStaticInitializers (ec, await_stack_field);
6480 if (!only_constant_initializers)
6481 EmitDynamicInitializers (ec, false, await_stack_field);
6485 EmitDynamicInitializers (ec, true, await_stack_field);
6488 if (await_stack_field != null)
6489 await_stack_field.Emit (ec);
6491 if (first_emit_temp != null)
6492 first_emit_temp.Release (ec);
6495 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
6497 // no multi dimensional or jagged arrays
6498 if (arguments.Count != 1 || array_element_type.IsArray) {
6499 base.EncodeAttributeValue (rc, enc, targetType);
6503 // No array covariance, except for array -> object
6504 if (type != targetType) {
6505 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
6506 base.EncodeAttributeValue (rc, enc, targetType);
6510 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
6511 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
6516 // Single dimensional array of 0 size
6517 if (array_data == null) {
6518 IntConstant ic = arguments[0] as IntConstant;
6519 if (ic == null || !ic.IsDefaultValue) {
6520 base.EncodeAttributeValue (rc, enc, targetType);
6528 enc.Encode (array_data.Count);
6529 foreach (var element in array_data) {
6530 element.EncodeAttributeValue (rc, enc, array_element_type);
6534 protected override void CloneTo (CloneContext clonectx, Expression t)
6536 ArrayCreation target = (ArrayCreation) t;
6538 if (requested_base_type != null)
6539 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6541 if (arguments != null){
6542 target.arguments = new List<Expression> (arguments.Count);
6543 foreach (Expression e in arguments)
6544 target.arguments.Add (e.Clone (clonectx));
6547 if (initializers != null)
6548 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
6553 // Represents an implicitly typed array epxression
6555 class ImplicitlyTypedArrayCreation : ArrayCreation
6557 sealed class InferenceContext : TypeInferenceContext
6559 class ExpressionBoundInfo : BoundInfo
6561 readonly Expression expr;
6563 public ExpressionBoundInfo (Expression expr)
6564 : base (expr.Type, BoundKind.Lower)
6569 public override bool Equals (BoundInfo other)
6571 // We are using expression not type for conversion check
6572 // no optimization based on types is possible
6576 public override Expression GetTypeExpression ()
6582 public void AddExpression (Expression expr)
6584 AddToBounds (new ExpressionBoundInfo (expr), 0);
6588 InferenceContext best_type_inference;
6590 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6591 : base (null, rank, initializers, loc)
6595 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
6596 : base (null, initializers, loc)
6600 protected override Expression DoResolve (ResolveContext ec)
6605 dimensions = rank.Dimension;
6607 best_type_inference = new InferenceContext ();
6609 if (!ResolveInitializers (ec))
6612 best_type_inference.FixAllTypes (ec);
6613 array_element_type = best_type_inference.InferredTypeArguments[0];
6614 best_type_inference = null;
6616 if (array_element_type == null || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
6617 arguments.Count != rank.Dimension) {
6618 ec.Report.Error (826, loc,
6619 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6624 // At this point we found common base type for all initializer elements
6625 // but we have to be sure that all static initializer elements are of
6628 UnifyInitializerElement (ec);
6630 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
6631 eclass = ExprClass.Value;
6636 // Converts static initializer only
6638 void UnifyInitializerElement (ResolveContext ec)
6640 for (int i = 0; i < array_data.Count; ++i) {
6641 Expression e = array_data[i];
6643 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6647 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6649 element = element.Resolve (ec);
6650 if (element != null)
6651 best_type_inference.AddExpression (element);
6657 sealed class CompilerGeneratedThis : This
6659 public CompilerGeneratedThis (TypeSpec type, Location loc)
6663 eclass = ExprClass.Variable;
6666 protected override Expression DoResolve (ResolveContext ec)
6671 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6678 /// Represents the `this' construct
6681 public class This : VariableReference
6683 sealed class ThisVariable : ILocalVariable
6685 public static readonly ILocalVariable Instance = new ThisVariable ();
6687 public void Emit (EmitContext ec)
6692 public void EmitAssign (EmitContext ec)
6694 throw new InvalidOperationException ();
6697 public void EmitAddressOf (EmitContext ec)
6703 VariableInfo variable_info;
6705 public This (Location loc)
6712 public override string Name {
6713 get { return "this"; }
6716 public override bool IsLockedByStatement {
6724 public override bool IsRef {
6725 get { return type.IsStruct; }
6728 public override bool IsSideEffectFree {
6734 protected override ILocalVariable Variable {
6735 get { return ThisVariable.Instance; }
6738 public override VariableInfo VariableInfo {
6739 get { return variable_info; }
6742 public override bool IsFixed {
6743 get { return false; }
6748 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
6750 if (variable_info != null && !variable_info.IsAssigned (rc)) {
6751 rc.Report.Error (188, loc,
6752 "The `this' object cannot be used before all of its fields are assigned to");
6756 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
6758 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6759 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6760 } else if (ec.CurrentAnonymousMethod != null) {
6761 ec.Report.Error (1673, loc,
6762 "Anonymous methods inside structs cannot access instance members of `this'. " +
6763 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6765 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6769 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6774 AnonymousMethodStorey storey = ae.Storey;
6775 while (storey != null) {
6776 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6778 return storey.HoistedThis;
6786 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
6788 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
6791 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
6794 if (ec.CurrentType.IsStruct && ec.CurrentIterator == null)
6800 public virtual void ResolveBase (ResolveContext ec)
6802 eclass = ExprClass.Variable;
6803 type = ec.CurrentType;
6805 if (!IsThisAvailable (ec, false)) {
6806 Error_ThisNotAvailable (ec);
6810 var block = ec.CurrentBlock;
6811 if (block != null) {
6812 if (block.ParametersBlock.TopBlock.ThisVariable != null)
6813 variable_info = block.ParametersBlock.TopBlock.ThisVariable.VariableInfo;
6815 AnonymousExpression am = ec.CurrentAnonymousMethod;
6816 if (am != null && ec.IsVariableCapturingRequired) {
6817 am.SetHasThisAccess ();
6822 public override Expression CreateExpressionTree (ResolveContext ec)
6824 Arguments args = new Arguments (1);
6825 args.Add (new Argument (this));
6827 // Use typeless constant for ldarg.0 to save some
6828 // space and avoid problems with anonymous stories
6829 return CreateExpressionFactoryCall (ec, "Constant", args);
6832 protected override Expression DoResolve (ResolveContext ec)
6836 if (variable_info != null && type.IsStruct) {
6837 CheckStructThisDefiniteAssignment (ec);
6843 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6847 if (variable_info != null)
6848 variable_info.SetAssigned (ec);
6851 if (right_side == EmptyExpression.UnaryAddress)
6852 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6853 else if (right_side == EmptyExpression.OutAccess)
6854 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6856 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6862 public override int GetHashCode()
6864 throw new NotImplementedException ();
6867 public override bool Equals (object obj)
6869 This t = obj as This;
6876 protected override void CloneTo (CloneContext clonectx, Expression t)
6881 public override void SetHasAddressTaken ()
6888 /// Represents the `__arglist' construct
6890 public class ArglistAccess : Expression
6892 public ArglistAccess (Location loc)
6897 protected override void CloneTo (CloneContext clonectx, Expression target)
6902 public override bool ContainsEmitWithAwait ()
6907 public override Expression CreateExpressionTree (ResolveContext ec)
6909 throw new NotSupportedException ("ET");
6912 protected override Expression DoResolve (ResolveContext ec)
6914 eclass = ExprClass.Variable;
6915 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
6917 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
6918 ec.Report.Error (190, loc,
6919 "The __arglist construct is valid only within a variable argument method");
6925 public override void Emit (EmitContext ec)
6927 ec.Emit (OpCodes.Arglist);
6932 /// Represents the `__arglist (....)' construct
6934 public class Arglist : Expression
6936 Arguments Arguments;
6938 public Arglist (Location loc)
6943 public Arglist (Arguments args, Location l)
6949 public MetaType[] ArgumentTypes {
6951 if (Arguments == null)
6952 return MetaType.EmptyTypes;
6954 var retval = new MetaType[Arguments.Count];
6955 for (int i = 0; i < retval.Length; i++)
6956 retval[i] = Arguments[i].Expr.Type.GetMetaInfo ();
6962 public override bool ContainsEmitWithAwait ()
6964 throw new NotImplementedException ();
6967 public override Expression CreateExpressionTree (ResolveContext ec)
6969 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6973 protected override Expression DoResolve (ResolveContext ec)
6975 eclass = ExprClass.Variable;
6976 type = InternalType.Arglist;
6977 if (Arguments != null) {
6978 bool dynamic; // Can be ignored as there is always only 1 overload
6979 Arguments.Resolve (ec, out dynamic);
6985 public override void Emit (EmitContext ec)
6987 if (Arguments != null)
6988 Arguments.Emit (ec);
6991 protected override void CloneTo (CloneContext clonectx, Expression t)
6993 Arglist target = (Arglist) t;
6995 if (Arguments != null)
6996 target.Arguments = Arguments.Clone (clonectx);
7000 class RefValueExpr : ShimExpression
7002 FullNamedExpression texpr;
7004 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7011 public override bool ContainsEmitWithAwait ()
7016 protected override Expression DoResolve (ResolveContext rc)
7018 expr = expr.Resolve (rc);
7019 type = texpr.ResolveAsType (rc);
7020 if (expr == null || type == null)
7023 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7024 eclass = ExprClass.Value;
7028 public override void Emit (EmitContext ec)
7031 ec.Emit (OpCodes.Refanyval, type);
7032 ec.EmitLoadFromPtr (type);
7036 class RefTypeExpr : ShimExpression
7038 public RefTypeExpr (Expression expr, Location loc)
7044 protected override Expression DoResolve (ResolveContext rc)
7046 expr = expr.Resolve (rc);
7050 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7054 type = rc.BuiltinTypes.Type;
7055 eclass = ExprClass.Value;
7059 public override void Emit (EmitContext ec)
7062 ec.Emit (OpCodes.Refanytype);
7063 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7065 ec.Emit (OpCodes.Call, m);
7069 class MakeRefExpr : ShimExpression
7071 public MakeRefExpr (Expression expr, Location loc)
7077 public override bool ContainsEmitWithAwait ()
7079 throw new NotImplementedException ();
7082 protected override Expression DoResolve (ResolveContext rc)
7084 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
7085 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
7086 eclass = ExprClass.Value;
7090 public override void Emit (EmitContext ec)
7092 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
7093 ec.Emit (OpCodes.Mkrefany, expr.Type);
7098 /// Implements the typeof operator
7100 public class TypeOf : Expression {
7101 FullNamedExpression QueriedType;
7104 public TypeOf (FullNamedExpression queried_type, Location l)
7106 QueriedType = queried_type;
7111 // Use this constructor for any compiler generated typeof expression
7113 public TypeOf (TypeSpec type, Location loc)
7115 this.typearg = type;
7121 public override bool IsSideEffectFree {
7127 public TypeSpec TypeArgument {
7133 public FullNamedExpression TypeExpression {
7142 protected override void CloneTo (CloneContext clonectx, Expression t)
7144 TypeOf target = (TypeOf) t;
7145 if (QueriedType != null)
7146 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
7149 public override bool ContainsEmitWithAwait ()
7154 public override Expression CreateExpressionTree (ResolveContext ec)
7156 Arguments args = new Arguments (2);
7157 args.Add (new Argument (this));
7158 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7159 return CreateExpressionFactoryCall (ec, "Constant", args);
7162 protected override Expression DoResolve (ResolveContext ec)
7164 if (eclass != ExprClass.Unresolved)
7167 if (typearg == null) {
7169 // Pointer types are allowed without explicit unsafe, they are just tokens
7171 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
7172 typearg = QueriedType.ResolveAsType (ec);
7175 if (typearg == null)
7178 if (typearg.Kind == MemberKind.Void && !(QueriedType is TypeExpression)) {
7179 ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
7180 } else if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7181 ec.Report.Error (1962, QueriedType.Location,
7182 "The typeof operator cannot be used on the dynamic type");
7186 type = ec.BuiltinTypes.Type;
7188 // Even though what is returned is a type object, it's treated as a value by the compiler.
7189 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7190 eclass = ExprClass.Value;
7194 static bool ContainsDynamicType (TypeSpec type)
7196 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7199 var element_container = type as ElementTypeSpec;
7200 if (element_container != null)
7201 return ContainsDynamicType (element_container.Element);
7203 foreach (var t in type.TypeArguments) {
7204 if (ContainsDynamicType (t)) {
7212 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7214 // Target type is not System.Type therefore must be object
7215 // and we need to use different encoding sequence
7216 if (targetType != type)
7219 if (typearg is InflatedTypeSpec) {
7222 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
7223 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7224 typearg.GetSignatureForError ());
7228 gt = gt.DeclaringType;
7229 } while (gt != null);
7232 if (ContainsDynamicType (typearg)) {
7233 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7237 enc.EncodeTypeName (typearg);
7240 public override void Emit (EmitContext ec)
7242 ec.Emit (OpCodes.Ldtoken, typearg);
7243 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7245 ec.Emit (OpCodes.Call, m);
7249 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
7251 public TypeOfMethod (MethodSpec method, Location loc)
7252 : base (method, loc)
7256 protected override Expression DoResolve (ResolveContext ec)
7258 if (member.IsConstructor) {
7259 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
7261 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
7267 return base.DoResolve (ec);
7270 public override void Emit (EmitContext ec)
7272 ec.Emit (OpCodes.Ldtoken, member);
7275 ec.Emit (OpCodes.Castclass, type);
7278 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7280 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
7283 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7285 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
7289 abstract class TypeOfMember<T> : Expression where T : MemberSpec
7291 protected readonly T member;
7293 protected TypeOfMember (T member, Location loc)
7295 this.member = member;
7299 public override bool IsSideEffectFree {
7305 public override bool ContainsEmitWithAwait ()
7310 public override Expression CreateExpressionTree (ResolveContext ec)
7312 Arguments args = new Arguments (2);
7313 args.Add (new Argument (this));
7314 args.Add (new Argument (new TypeOf (type, loc)));
7315 return CreateExpressionFactoryCall (ec, "Constant", args);
7318 protected override Expression DoResolve (ResolveContext ec)
7320 eclass = ExprClass.Value;
7324 public override void Emit (EmitContext ec)
7326 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
7327 PredefinedMember<MethodSpec> p;
7329 p = GetTypeFromHandleGeneric (ec);
7330 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
7332 p = GetTypeFromHandle (ec);
7335 var mi = p.Resolve (loc);
7337 ec.Emit (OpCodes.Call, mi);
7340 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
7341 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
7344 sealed class TypeOfField : TypeOfMember<FieldSpec>
7346 public TypeOfField (FieldSpec field, Location loc)
7351 protected override Expression DoResolve (ResolveContext ec)
7353 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
7357 return base.DoResolve (ec);
7360 public override void Emit (EmitContext ec)
7362 ec.Emit (OpCodes.Ldtoken, member);
7366 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7368 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
7371 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7373 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
7378 /// Implements the sizeof expression
7380 public class SizeOf : Expression {
7381 readonly Expression QueriedType;
7382 TypeSpec type_queried;
7384 public SizeOf (Expression queried_type, Location l)
7386 this.QueriedType = queried_type;
7390 public override bool IsSideEffectFree {
7396 public override bool ContainsEmitWithAwait ()
7401 public override Expression CreateExpressionTree (ResolveContext ec)
7403 Error_PointerInsideExpressionTree (ec);
7407 protected override Expression DoResolve (ResolveContext ec)
7409 type_queried = QueriedType.ResolveAsType (ec);
7410 if (type_queried == null)
7413 if (TypeManager.IsEnumType (type_queried))
7414 type_queried = EnumSpec.GetUnderlyingType (type_queried);
7416 int size_of = BuiltinTypeSpec.GetSize (type_queried);
7418 return new IntConstant (ec.BuiltinTypes, size_of, loc);
7421 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
7426 ec.Report.Error (233, loc,
7427 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7428 TypeManager.CSharpName (type_queried));
7431 type = ec.BuiltinTypes.Int;
7432 eclass = ExprClass.Value;
7436 public override void Emit (EmitContext ec)
7438 ec.Emit (OpCodes.Sizeof, type_queried);
7441 protected override void CloneTo (CloneContext clonectx, Expression t)
7447 /// Implements the qualified-alias-member (::) expression.
7449 public class QualifiedAliasMember : MemberAccess
7451 readonly string alias;
7452 public static readonly string GlobalAlias = "global";
7454 public QualifiedAliasMember (string alias, string identifier, Location l)
7455 : base (null, identifier, l)
7460 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7461 : base (null, identifier, targs, l)
7466 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
7467 : base (null, identifier, arity, l)
7472 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
7474 if (alias == GlobalAlias) {
7475 expr = ec.Module.GlobalRootNamespace;
7476 return base.ResolveAsTypeOrNamespace (ec);
7479 int errors = ec.Module.Compiler.Report.Errors;
7480 expr = ec.LookupNamespaceAlias (alias);
7482 if (errors == ec.Module.Compiler.Report.Errors)
7483 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7487 FullNamedExpression fne = base.ResolveAsTypeOrNamespace (ec);
7491 if (expr.eclass == ExprClass.Type) {
7492 ec.Module.Compiler.Report.Error (431, loc,
7493 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7501 protected override Expression DoResolve (ResolveContext ec)
7503 return ResolveAsTypeOrNamespace (ec);
7506 protected override void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7508 rc.Module.Compiler.Report.Error (687, loc,
7509 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7510 GetSignatureForError ());
7513 public override string GetSignatureForError ()
7516 if (targs != null) {
7517 name = Name + "<" + targs.GetSignatureForError () + ">";
7520 return alias + "::" + name;
7523 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7525 return DoResolve (rc);
7528 protected override void CloneTo (CloneContext clonectx, Expression t)
7535 /// Implements the member access expression
7537 public class MemberAccess : ATypeNameExpression
7539 protected Expression expr;
7541 public MemberAccess (Expression expr, string id)
7542 : base (id, expr.Location)
7547 public MemberAccess (Expression expr, string identifier, Location loc)
7548 : base (identifier, loc)
7553 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7554 : base (identifier, args, loc)
7559 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
7560 : base (identifier, arity, loc)
7565 public Expression LeftExpression {
7571 protected override Expression DoResolve (ResolveContext ec)
7573 return DoResolveName (ec, null);
7576 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7578 return DoResolveName (ec, right_side);
7581 Expression DoResolveName (ResolveContext rc, Expression right_side)
7583 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
7587 if (right_side != null) {
7588 if (e is TypeExpr) {
7589 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
7593 e = e.ResolveLValue (rc, right_side);
7595 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
7601 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
7603 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
7604 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
7606 Unary.Error_OperatorCannotBeApplied (rc, loc, ".", type);
7609 public static bool IsValidDotExpression (TypeSpec type)
7611 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
7612 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
7614 return (type.Kind & dot_kinds) != 0;
7617 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7619 var sn = expr as SimpleName;
7620 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
7623 // Resolve the expression with flow analysis turned off, we'll do the definite
7624 // assignment checks later. This is because we don't know yet what the expression
7625 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7626 // definite assignment check on the actual field and not on the whole struct.
7628 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
7630 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
7632 // Call resolve on expression which does have type set as we need expression type
7633 // TODO: I should probably ensure that the type is always set and leave resolve for the final
7634 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
7635 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
7636 expr = expr.Resolve (rc);
7638 } else if (expr is TypeParameterExpr) {
7639 expr.Error_UnexpectedKind (rc, flags, sn.Location);
7643 expr = expr.Resolve (rc, flags);
7650 Namespace ns = expr as Namespace;
7652 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
7654 if (retval == null) {
7655 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
7659 if (HasTypeArguments)
7660 return new GenericTypeExpr (retval.Type, targs, loc);
7666 TypeSpec expr_type = expr.Type;
7667 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7668 me = expr as MemberExpr;
7670 me.ResolveInstanceExpression (rc, null);
7672 Arguments args = new Arguments (1);
7673 args.Add (new Argument (expr));
7674 return new DynamicMemberBinder (Name, args, loc);
7677 if (!IsValidDotExpression (expr_type)) {
7678 Error_OperatorCannotBeApplied (rc, expr_type);
7682 var lookup_arity = Arity;
7683 bool errorMode = false;
7684 Expression member_lookup;
7686 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
7687 if (member_lookup == null) {
7689 // Try to look for extension method when member lookup failed
7691 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
7692 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
7693 if (methods != null) {
7694 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
7695 if (HasTypeArguments) {
7696 if (!targs.Resolve (rc))
7699 emg.SetTypeArguments (rc, targs);
7702 // TODO: it should really skip the checks bellow
7703 return emg.Resolve (rc);
7709 if (member_lookup == null) {
7710 var dep = expr_type.GetMissingDependencies ();
7712 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
7713 } else if (expr is TypeExpr) {
7714 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
7716 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
7722 if (member_lookup is MethodGroupExpr) {
7723 // Leave it to overload resolution to report correct error
7724 } else if (!(member_lookup is TypeExpr)) {
7725 // TODO: rc.SymbolRelatedToPreviousError
7726 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
7731 if (member_lookup != null)
7735 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
7739 TypeExpr texpr = member_lookup as TypeExpr;
7740 if (texpr != null) {
7741 if (!(expr is TypeExpr)) {
7742 me = expr as MemberExpr;
7743 if (me == null || me.ProbeIdenticalTypeName (rc, expr, sn) == expr) {
7744 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7745 Name, member_lookup.GetSignatureForError ());
7750 if (!texpr.Type.IsAccessible (rc)) {
7751 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
7752 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
7756 if (HasTypeArguments) {
7757 return new GenericTypeExpr (member_lookup.Type, targs, loc);
7760 return member_lookup;
7763 me = member_lookup as MemberExpr;
7765 if (sn != null && me.IsStatic)
7766 expr = me.ProbeIdenticalTypeName (rc, expr, sn);
7768 me = me.ResolveMemberAccess (rc, expr, sn);
7771 if (!targs.Resolve (rc))
7774 me.SetTypeArguments (rc, targs);
7777 if (sn != null && (!TypeSpec.IsValueType (expr_type) || me is PropertyExpr)) {
7778 if (me.IsInstance) {
7779 LocalVariableReference var = expr as LocalVariableReference;
7780 if (var != null && !var.VerifyAssigned (rc))
7788 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
7790 FullNamedExpression fexpr = expr as FullNamedExpression;
7791 if (fexpr == null) {
7792 expr.ResolveAsType (rc);
7796 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
7798 if (expr_resolved == null)
7801 Namespace ns = expr_resolved as Namespace;
7803 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
7805 if (retval == null) {
7806 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
7807 } else if (HasTypeArguments) {
7808 retval = new GenericTypeExpr (retval.Type, targs, loc);
7809 if (retval.ResolveAsType (rc) == null)
7816 var tnew_expr = expr_resolved.ResolveAsType (rc);
7817 if (tnew_expr == null)
7820 TypeSpec expr_type = tnew_expr;
7821 if (TypeManager.IsGenericParameter (expr_type)) {
7822 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7823 tnew_expr.GetSignatureForError ());
7827 TypeSpec nested = null;
7828 while (expr_type != null) {
7829 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7830 if (nested == null) {
7831 if (expr_type == tnew_expr) {
7832 Error_IdentifierNotFound (rc, expr_type, Name);
7836 expr_type = tnew_expr;
7837 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7838 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
7842 if (nested.IsAccessible (rc))
7845 // Keep looking after inaccessible candidate
7846 expr_type = nested.DeclaringType.BaseType;
7851 if (HasTypeArguments) {
7852 texpr = new GenericTypeExpr (nested, targs, loc);
7854 texpr = new GenericOpenTypeExpr (nested, loc);
7857 texpr = new TypeExpression (nested, loc);
7860 if (texpr.ResolveAsType (rc) == null)
7866 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7868 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
7870 if (nested != null) {
7871 Error_TypeArgumentsCannotBeUsed (rc, nested, Arity, expr.Location);
7875 var any_other_member = MemberLookup (rc, true, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
7876 if (any_other_member != null) {
7877 any_other_member.Error_UnexpectedKind (rc.Module.Compiler.Report, null, "type", loc);
7881 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7882 Name, expr_type.GetSignatureForError ());
7885 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
7887 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
7888 ec.Report.SymbolRelatedToPreviousError (type);
7889 ec.Report.Error (1061, loc,
7890 "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?)",
7891 type.GetSignatureForError (), name);
7895 base.Error_TypeDoesNotContainDefinition (ec, type, name);
7898 public override string GetSignatureForError ()
7900 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7903 protected override void CloneTo (CloneContext clonectx, Expression t)
7905 MemberAccess target = (MemberAccess) t;
7907 target.expr = expr.Clone (clonectx);
7912 /// Implements checked expressions
7914 public class CheckedExpr : Expression {
7916 public Expression Expr;
7918 public CheckedExpr (Expression e, Location l)
7924 public override bool ContainsEmitWithAwait ()
7926 return Expr.ContainsEmitWithAwait ();
7929 public override Expression CreateExpressionTree (ResolveContext ec)
7931 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7932 return Expr.CreateExpressionTree (ec);
7935 protected override Expression DoResolve (ResolveContext ec)
7937 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7938 Expr = Expr.Resolve (ec);
7943 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7946 eclass = Expr.eclass;
7951 public override void Emit (EmitContext ec)
7953 using (ec.With (EmitContext.Options.CheckedScope, true))
7957 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7959 using (ec.With (EmitContext.Options.CheckedScope, true))
7960 Expr.EmitBranchable (ec, target, on_true);
7963 public override SLE.Expression MakeExpression (BuilderContext ctx)
7965 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
7966 return Expr.MakeExpression (ctx);
7970 protected override void CloneTo (CloneContext clonectx, Expression t)
7972 CheckedExpr target = (CheckedExpr) t;
7974 target.Expr = Expr.Clone (clonectx);
7979 /// Implements the unchecked expression
7981 public class UnCheckedExpr : Expression {
7983 public Expression Expr;
7985 public UnCheckedExpr (Expression e, Location l)
7991 public override bool ContainsEmitWithAwait ()
7993 return Expr.ContainsEmitWithAwait ();
7996 public override Expression CreateExpressionTree (ResolveContext ec)
7998 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7999 return Expr.CreateExpressionTree (ec);
8002 protected override Expression DoResolve (ResolveContext ec)
8004 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8005 Expr = Expr.Resolve (ec);
8010 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8013 eclass = Expr.eclass;
8018 public override void Emit (EmitContext ec)
8020 using (ec.With (EmitContext.Options.CheckedScope, false))
8024 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8026 using (ec.With (EmitContext.Options.CheckedScope, false))
8027 Expr.EmitBranchable (ec, target, on_true);
8030 protected override void CloneTo (CloneContext clonectx, Expression t)
8032 UnCheckedExpr target = (UnCheckedExpr) t;
8034 target.Expr = Expr.Clone (clonectx);
8039 /// An Element Access expression.
8041 /// During semantic analysis these are transformed into
8042 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
8044 public class ElementAccess : Expression
8046 public Arguments Arguments;
8047 public Expression Expr;
8049 public ElementAccess (Expression e, Arguments args, Location loc)
8053 this.Arguments = args;
8056 public override bool ContainsEmitWithAwait ()
8058 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
8062 // We perform some simple tests, and then to "split" the emit and store
8063 // code we create an instance of a different class, and return that.
8065 Expression CreateAccessExpression (ResolveContext ec)
8068 return (new ArrayAccess (this, loc));
8071 return MakePointerAccess (ec, type);
8073 FieldExpr fe = Expr as FieldExpr;
8075 var ff = fe.Spec as FixedFieldSpec;
8077 return MakePointerAccess (ec, ff.ElementType);
8081 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
8082 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8083 return new IndexerExpr (indexers, type, this);
8086 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8087 type.GetSignatureForError ());
8091 public override Expression CreateExpressionTree (ResolveContext ec)
8093 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
8094 Expr.CreateExpressionTree (ec));
8096 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
8099 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
8101 if (Arguments.Count != 1){
8102 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
8106 if (Arguments [0] is NamedArgument)
8107 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
8109 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
8110 return new Indirection (p, loc);
8113 protected override Expression DoResolve (ResolveContext ec)
8115 Expr = Expr.Resolve (ec);
8121 // TODO: Create 1 result for Resolve and ResolveLValue ?
8122 var res = CreateAccessExpression (ec);
8126 return res.Resolve (ec);
8129 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8131 Expr = Expr.Resolve (ec);
8137 var res = CreateAccessExpression (ec);
8141 return res.ResolveLValue (ec, right_side);
8144 public override void Emit (EmitContext ec)
8146 throw new Exception ("Should never be reached");
8149 public static void Error_NamedArgument (NamedArgument na, Report Report)
8151 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
8154 public override string GetSignatureForError ()
8156 return Expr.GetSignatureForError ();
8159 protected override void CloneTo (CloneContext clonectx, Expression t)
8161 ElementAccess target = (ElementAccess) t;
8163 target.Expr = Expr.Clone (clonectx);
8164 if (Arguments != null)
8165 target.Arguments = Arguments.Clone (clonectx);
8170 /// Implements array access
8172 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
8174 // Points to our "data" repository
8178 LocalTemporary temp;
8180 bool? has_await_args;
8182 public ArrayAccess (ElementAccess ea_data, Location l)
8188 public void AddressOf (EmitContext ec, AddressOp mode)
8190 var ac = (ArrayContainer) ea.Expr.Type;
8192 LoadInstanceAndArguments (ec, false, false);
8194 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
8195 ec.Emit (OpCodes.Readonly);
8197 ec.EmitArrayAddress (ac);
8200 public override Expression CreateExpressionTree (ResolveContext ec)
8202 return ea.CreateExpressionTree (ec);
8205 public override bool ContainsEmitWithAwait ()
8207 return ea.ContainsEmitWithAwait ();
8210 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8212 return DoResolve (ec);
8215 protected override Expression DoResolve (ResolveContext ec)
8217 // dynamic is used per argument in ConvertExpressionToArrayIndex case
8219 ea.Arguments.Resolve (ec, out dynamic);
8221 var ac = ea.Expr.Type as ArrayContainer;
8222 int rank = ea.Arguments.Count;
8223 if (ac.Rank != rank) {
8224 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8225 rank.ToString (), ac.Rank.ToString ());
8230 if (type.IsPointer && !ec.IsUnsafe) {
8231 UnsafeError (ec, ea.Location);
8234 foreach (Argument a in ea.Arguments) {
8235 if (a is NamedArgument)
8236 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
8238 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
8241 eclass = ExprClass.Variable;
8246 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8248 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8252 // Load the array arguments into the stack.
8254 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
8257 ea.Expr = ea.Expr.EmitToField (ec);
8258 } else if (duplicateArguments) {
8260 ec.Emit (OpCodes.Dup);
8262 var copy = new LocalTemporary (ea.Expr.Type);
8269 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
8270 if (dup_args != null)
8271 ea.Arguments = dup_args;
8274 public void Emit (EmitContext ec, bool leave_copy)
8276 var ac = ea.Expr.Type as ArrayContainer;
8279 ec.EmitLoadFromPtr (type);
8281 if (!has_await_args.HasValue && ea.Arguments.ContainsEmitWithAwait ()) {
8282 LoadInstanceAndArguments (ec, false, true);
8285 LoadInstanceAndArguments (ec, false, false);
8286 ec.EmitArrayLoad (ac);
8290 ec.Emit (OpCodes.Dup);
8291 temp = new LocalTemporary (this.type);
8296 public override void Emit (EmitContext ec)
8301 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8303 var ac = (ArrayContainer) ea.Expr.Type;
8304 TypeSpec t = source.Type;
8306 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
8309 // When we are dealing with a struct, get the address of it to avoid value copy
8310 // Same cannot be done for reference type because array covariance and the
8311 // check in ldelema requires to specify the type of array element stored at the index
8313 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
8314 LoadInstanceAndArguments (ec, false, has_await_args.Value);
8316 if (has_await_args.Value) {
8317 if (source.ContainsEmitWithAwait ()) {
8318 source = source.EmitToField (ec);
8323 LoadInstanceAndArguments (ec, isCompound, false);
8328 ec.EmitArrayAddress (ac);
8331 ec.Emit (OpCodes.Dup);
8335 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
8337 if (has_await_args.Value) {
8338 if (source.ContainsEmitWithAwait ())
8339 source = source.EmitToField (ec);
8341 LoadInstanceAndArguments (ec, false, false);
8348 var lt = ea.Expr as LocalTemporary;
8354 ec.Emit (OpCodes.Dup);
8355 temp = new LocalTemporary (this.type);
8360 ec.EmitStoreFromPtr (t);
8362 ec.EmitArrayStore (ac);
8371 public override Expression EmitToField (EmitContext ec)
8374 // Have to be specialized for arrays to get access to
8375 // underlying element. Instead of another result copy we
8376 // need direct access to element
8380 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
8382 ea.Expr = ea.Expr.EmitToField (ec);
8386 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8389 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8391 throw new NotImplementedException ();
8395 public override SLE.Expression MakeExpression (BuilderContext ctx)
8397 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8400 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
8402 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
8403 return Arguments.MakeExpression (ea.Arguments, ctx);
8409 // Indexer access expression
8411 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
8413 IList<MemberSpec> indexers;
8414 Arguments arguments;
8415 TypeSpec queried_type;
8417 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
8418 : base (ea.Location)
8420 this.indexers = indexers;
8421 this.queried_type = queriedType;
8422 this.InstanceExpression = ea.Expr;
8423 this.arguments = ea.Arguments;
8428 protected override Arguments Arguments {
8437 protected override TypeSpec DeclaringType {
8439 return best_candidate.DeclaringType;
8443 public override bool IsInstance {
8449 public override bool IsStatic {
8455 public override string Name {
8463 public override bool ContainsEmitWithAwait ()
8465 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
8468 public override Expression CreateExpressionTree (ResolveContext ec)
8470 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8471 InstanceExpression.CreateExpressionTree (ec),
8472 new TypeOfMethod (Getter, loc));
8474 return CreateExpressionFactoryCall (ec, "Call", args);
8477 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8479 LocalTemporary await_source_arg = null;
8482 emitting_compound_assignment = true;
8483 if (source is DynamicExpressionStatement) {
8488 emitting_compound_assignment = false;
8490 if (has_await_arguments) {
8491 await_source_arg = new LocalTemporary (Type);
8492 await_source_arg.Store (ec);
8494 arguments.Add (new Argument (await_source_arg));
8497 temp = await_source_arg;
8500 has_await_arguments = false;
8505 ec.Emit (OpCodes.Dup);
8506 temp = new LocalTemporary (Type);
8512 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
8513 source = source.EmitToField (ec);
8515 temp = new LocalTemporary (Type);
8522 arguments.Add (new Argument (source));
8525 var call = new CallEmitter ();
8526 call.InstanceExpression = InstanceExpression;
8527 if (arguments == null)
8528 call.InstanceExpressionOnStack = true;
8530 call.Emit (ec, Setter, arguments, loc);
8535 } else if (leave_copy) {
8539 if (await_source_arg != null) {
8540 await_source_arg.Release (ec);
8544 public override string GetSignatureForError ()
8546 return best_candidate.GetSignatureForError ();
8549 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8552 throw new NotSupportedException ();
8554 var value = new[] { source.MakeExpression (ctx) };
8555 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
8557 return SLE.Expression.Block (
8558 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
8561 return args.First ();
8566 public override SLE.Expression MakeExpression (BuilderContext ctx)
8569 return base.MakeExpression (ctx);
8571 var args = Arguments.MakeExpression (arguments, ctx);
8572 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
8576 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
8578 if (best_candidate != null)
8581 eclass = ExprClass.IndexerAccess;
8584 arguments.Resolve (rc, out dynamic);
8586 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8589 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
8590 res.BaseMembersProvider = this;
8592 // TODO: Do I need 2 argument sets?
8593 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
8594 if (best_candidate != null)
8595 type = res.BestCandidateReturnType;
8596 else if (!res.BestCandidateIsDynamic)
8601 // It has dynamic arguments
8604 Arguments args = new Arguments (arguments.Count + 1);
8606 rc.Report.Error (1972, loc,
8607 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8609 args.Add (new Argument (InstanceExpression));
8611 args.AddRange (arguments);
8613 best_candidate = null;
8614 return new DynamicIndexBinder (args, loc);
8617 ResolveInstanceExpression (rc, right_side);
8618 CheckProtectedMemberAccess (rc, best_candidate);
8622 protected override void CloneTo (CloneContext clonectx, Expression t)
8624 IndexerExpr target = (IndexerExpr) t;
8626 if (arguments != null)
8627 target.arguments = arguments.Clone (clonectx);
8630 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
8632 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
8635 #region IBaseMembersProvider Members
8637 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
8639 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
8642 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
8644 if (queried_type == member.DeclaringType)
8647 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
8648 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
8651 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
8660 // A base access expression
8662 public class BaseThis : This
8664 public BaseThis (Location loc)
8669 public BaseThis (TypeSpec type, Location loc)
8673 eclass = ExprClass.Variable;
8678 public override string Name {
8686 public override Expression CreateExpressionTree (ResolveContext ec)
8688 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
8689 return base.CreateExpressionTree (ec);
8692 public override void Emit (EmitContext ec)
8696 var context_type = ec.CurrentType;
8697 if (context_type.IsStruct) {
8698 ec.Emit (OpCodes.Ldobj, context_type);
8699 ec.Emit (OpCodes.Box, context_type);
8703 protected override void Error_ThisNotAvailable (ResolveContext ec)
8706 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
8708 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
8712 public override void ResolveBase (ResolveContext ec)
8714 base.ResolveBase (ec);
8715 type = ec.CurrentType.BaseType;
8720 /// This class exists solely to pass the Type around and to be a dummy
8721 /// that can be passed to the conversion functions (this is used by
8722 /// foreach implementation to typecast the object return value from
8723 /// get_Current into the proper type. All code has been generated and
8724 /// we only care about the side effect conversions to be performed
8726 /// This is also now used as a placeholder where a no-action expression
8727 /// is needed (the `New' class).
8729 class EmptyExpression : Expression
8731 sealed class OutAccessExpression : EmptyExpression
8733 public OutAccessExpression (TypeSpec t)
8738 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8740 rc.Report.Error (206, right_side.Location,
8741 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
8747 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
8748 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
8749 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
8750 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
8751 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
8752 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
8753 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
8754 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
8756 public EmptyExpression (TypeSpec t)
8759 eclass = ExprClass.Value;
8760 loc = Location.Null;
8763 public override bool ContainsEmitWithAwait ()
8768 public override Expression CreateExpressionTree (ResolveContext ec)
8770 throw new NotSupportedException ("ET");
8773 protected override Expression DoResolve (ResolveContext ec)
8778 public override void Emit (EmitContext ec)
8780 // nothing, as we only exist to not do anything.
8783 public override void EmitSideEffect (EmitContext ec)
8789 // Empty statement expression
8791 public sealed class EmptyExpressionStatement : ExpressionStatement
8793 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8795 private EmptyExpressionStatement ()
8797 loc = Location.Null;
8800 public override bool ContainsEmitWithAwait ()
8805 public override Expression CreateExpressionTree (ResolveContext ec)
8810 public override void EmitStatement (EmitContext ec)
8815 protected override Expression DoResolve (ResolveContext ec)
8817 eclass = ExprClass.Value;
8818 type = ec.BuiltinTypes.Object;
8822 public override void Emit (EmitContext ec)
8828 class ErrorExpression : EmptyExpression
8830 public static readonly ErrorExpression Instance = new ErrorExpression ();
8832 private ErrorExpression ()
8833 : base (InternalType.FakeInternalType)
8837 public override Expression CreateExpressionTree (ResolveContext ec)
8842 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8847 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
8852 public class UserCast : Expression {
8856 public UserCast (MethodSpec method, Expression source, Location l)
8858 this.method = method;
8859 this.source = source;
8860 type = method.ReturnType;
8864 public Expression Source {
8870 public override bool ContainsEmitWithAwait ()
8872 return source.ContainsEmitWithAwait ();
8875 public override Expression CreateExpressionTree (ResolveContext ec)
8877 Arguments args = new Arguments (3);
8878 args.Add (new Argument (source.CreateExpressionTree (ec)));
8879 args.Add (new Argument (new TypeOf (type, loc)));
8880 args.Add (new Argument (new TypeOfMethod (method, loc)));
8881 return CreateExpressionFactoryCall (ec, "Convert", args);
8884 protected override Expression DoResolve (ResolveContext ec)
8886 ObsoleteAttribute oa = method.GetAttributeObsolete ();
8888 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
8890 eclass = ExprClass.Value;
8894 public override void Emit (EmitContext ec)
8897 ec.Emit (OpCodes.Call, method);
8900 public override string GetSignatureForError ()
8902 return TypeManager.CSharpSignature (method);
8905 public override SLE.Expression MakeExpression (BuilderContext ctx)
8908 return base.MakeExpression (ctx);
8910 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
8916 // Holds additional type specifiers like ?, *, []
8918 public class ComposedTypeSpecifier
8920 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
8922 public readonly int Dimension;
8923 public readonly Location Location;
8925 public ComposedTypeSpecifier (int specifier, Location loc)
8927 this.Dimension = specifier;
8928 this.Location = loc;
8932 public bool IsNullable {
8934 return Dimension == -1;
8938 public bool IsPointer {
8940 return Dimension == -2;
8944 public ComposedTypeSpecifier Next { get; set; }
8948 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
8950 return new ComposedTypeSpecifier (dimension, loc);
8953 public static ComposedTypeSpecifier CreateNullable (Location loc)
8955 return new ComposedTypeSpecifier (-1, loc);
8958 public static ComposedTypeSpecifier CreatePointer (Location loc)
8960 return new ComposedTypeSpecifier (-2, loc);
8963 public string GetSignatureForError ()
8968 ArrayContainer.GetPostfixSignature (Dimension);
8970 return Next != null ? s + Next.GetSignatureForError () : s;
8975 // This class is used to "construct" the type during a typecast
8976 // operation. Since the Type.GetType class in .NET can parse
8977 // the type specification, we just use this to construct the type
8978 // one bit at a time.
8980 public class ComposedCast : TypeExpr {
8981 FullNamedExpression left;
8982 ComposedTypeSpecifier spec;
8984 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
8987 throw new ArgumentNullException ("spec");
8991 this.loc = spec.Location;
8994 public override TypeSpec ResolveAsType (IMemberContext ec)
8996 type = left.ResolveAsType (ec);
9000 eclass = ExprClass.Type;
9002 var single_spec = spec;
9004 if (single_spec.IsNullable) {
9005 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
9009 single_spec = single_spec.Next;
9010 } else if (single_spec.IsPointer) {
9011 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
9015 UnsafeError (ec.Module.Compiler.Report, loc);
9019 type = PointerContainer.MakeType (ec.Module, type);
9020 single_spec = single_spec.Next;
9021 } while (single_spec != null && single_spec.IsPointer);
9024 if (single_spec != null && single_spec.Dimension > 0) {
9025 if (type.IsSpecialRuntimeType) {
9026 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
9027 } else if (type.IsStatic) {
9028 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
9029 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9030 type.GetSignatureForError ());
9032 MakeArray (ec.Module, single_spec);
9039 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
9041 if (spec.Next != null)
9042 MakeArray (module, spec.Next);
9044 type = ArrayContainer.MakeType (module, type, spec.Dimension);
9047 public override string GetSignatureForError ()
9049 return left.GetSignatureForError () + spec.GetSignatureForError ();
9053 class FixedBufferPtr : Expression
9055 readonly Expression array;
9057 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
9059 this.type = array_type;
9064 public override bool ContainsEmitWithAwait ()
9066 throw new NotImplementedException ();
9069 public override Expression CreateExpressionTree (ResolveContext ec)
9071 Error_PointerInsideExpressionTree (ec);
9075 public override void Emit(EmitContext ec)
9080 protected override Expression DoResolve (ResolveContext ec)
9082 type = PointerContainer.MakeType (ec.Module, type);
9083 eclass = ExprClass.Value;
9090 // This class is used to represent the address of an array, used
9091 // only by the Fixed statement, this generates "&a [0]" construct
9092 // for fixed (char *pa = a)
9094 class ArrayPtr : FixedBufferPtr
9096 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
9097 base (array, array_type, l)
9101 public override void Emit (EmitContext ec)
9106 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
9111 // Encapsulates a conversion rules required for array indexes
9113 public class ArrayIndexCast : TypeCast
9115 public ArrayIndexCast (Expression expr, TypeSpec returnType)
9116 : base (expr, returnType)
9118 if (expr.Type == returnType) // int -> int
9119 throw new ArgumentException ("unnecessary array index conversion");
9122 public override Expression CreateExpressionTree (ResolveContext ec)
9124 using (ec.Set (ResolveContext.Options.CheckedScope)) {
9125 return base.CreateExpressionTree (ec);
9129 public override void Emit (EmitContext ec)
9133 switch (child.Type.BuiltinType) {
9134 case BuiltinTypeSpec.Type.UInt:
9135 ec.Emit (OpCodes.Conv_U);
9137 case BuiltinTypeSpec.Type.Long:
9138 ec.Emit (OpCodes.Conv_Ovf_I);
9140 case BuiltinTypeSpec.Type.ULong:
9141 ec.Emit (OpCodes.Conv_Ovf_I_Un);
9144 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9150 // Implements the `stackalloc' keyword
9152 public class StackAlloc : Expression {
9157 public StackAlloc (Expression type, Expression count, Location l)
9164 public override bool ContainsEmitWithAwait ()
9169 public override Expression CreateExpressionTree (ResolveContext ec)
9171 throw new NotSupportedException ("ET");
9174 protected override Expression DoResolve (ResolveContext ec)
9176 count = count.Resolve (ec);
9180 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
9181 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
9186 Constant c = count as Constant;
9187 if (c != null && c.IsNegative) {
9188 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9191 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9192 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9195 otype = t.ResolveAsType (ec);
9199 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
9202 type = PointerContainer.MakeType (ec.Module, otype);
9203 eclass = ExprClass.Value;
9208 public override void Emit (EmitContext ec)
9210 int size = BuiltinTypeSpec.GetSize (otype);
9215 ec.Emit (OpCodes.Sizeof, otype);
9219 ec.Emit (OpCodes.Mul_Ovf_Un);
9220 ec.Emit (OpCodes.Localloc);
9223 protected override void CloneTo (CloneContext clonectx, Expression t)
9225 StackAlloc target = (StackAlloc) t;
9226 target.count = count.Clone (clonectx);
9227 target.t = t.Clone (clonectx);
9232 // An object initializer expression
9234 public class ElementInitializer : Assign
9236 public readonly string Name;
9238 public ElementInitializer (string name, Expression initializer, Location loc)
9239 : base (null, initializer, loc)
9244 protected override void CloneTo (CloneContext clonectx, Expression t)
9246 ElementInitializer target = (ElementInitializer) t;
9247 target.source = source.Clone (clonectx);
9250 public override Expression CreateExpressionTree (ResolveContext ec)
9252 Arguments args = new Arguments (2);
9253 FieldExpr fe = target as FieldExpr;
9255 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9257 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9259 args.Add (new Argument (source.CreateExpressionTree (ec)));
9260 return CreateExpressionFactoryCall (ec,
9261 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9265 protected override Expression DoResolve (ResolveContext ec)
9268 return EmptyExpressionStatement.Instance;
9270 var t = ec.CurrentInitializerVariable.Type;
9271 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9272 Arguments args = new Arguments (1);
9273 args.Add (new Argument (ec.CurrentInitializerVariable));
9274 target = new DynamicMemberBinder (Name, args, loc);
9277 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9278 if (member == null) {
9279 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9281 if (member != null) {
9282 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
9283 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
9288 if (member == null) {
9289 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
9293 if (!(member is PropertyExpr || member is FieldExpr)) {
9294 ec.Report.Error (1913, loc,
9295 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
9296 member.GetSignatureForError ());
9301 var me = member as MemberExpr;
9303 ec.Report.Error (1914, loc,
9304 "Static field or property `{0}' cannot be assigned in an object initializer",
9305 me.GetSignatureForError ());
9309 me.InstanceExpression = ec.CurrentInitializerVariable;
9312 if (source is CollectionOrObjectInitializers) {
9313 Expression previous = ec.CurrentInitializerVariable;
9314 ec.CurrentInitializerVariable = target;
9315 source = source.Resolve (ec);
9316 ec.CurrentInitializerVariable = previous;
9320 eclass = source.eclass;
9325 return base.DoResolve (ec);
9328 public override void EmitStatement (EmitContext ec)
9330 if (source is CollectionOrObjectInitializers)
9333 base.EmitStatement (ec);
9338 // A collection initializer expression
9340 class CollectionElementInitializer : Invocation
9342 public class ElementInitializerArgument : Argument
9344 public ElementInitializerArgument (Expression e)
9350 sealed class AddMemberAccess : MemberAccess
9352 public AddMemberAccess (Expression expr, Location loc)
9353 : base (expr, "Add", loc)
9357 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9359 if (TypeManager.HasElementType (type))
9362 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9366 public CollectionElementInitializer (Expression argument)
9367 : base (null, new Arguments (1))
9369 base.arguments.Add (new ElementInitializerArgument (argument));
9370 this.loc = argument.Location;
9373 public CollectionElementInitializer (List<Expression> arguments, Location loc)
9374 : base (null, new Arguments (arguments.Count))
9376 foreach (Expression e in arguments)
9377 base.arguments.Add (new ElementInitializerArgument (e));
9382 public override Expression CreateExpressionTree (ResolveContext ec)
9384 Arguments args = new Arguments (2);
9385 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9387 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
9388 foreach (Argument a in arguments)
9389 expr_initializers.Add (a.CreateExpressionTree (ec));
9391 args.Add (new Argument (new ArrayCreation (
9392 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
9393 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9396 protected override void CloneTo (CloneContext clonectx, Expression t)
9398 CollectionElementInitializer target = (CollectionElementInitializer) t;
9399 if (arguments != null)
9400 target.arguments = arguments.Clone (clonectx);
9403 protected override Expression DoResolve (ResolveContext ec)
9405 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9407 return base.DoResolve (ec);
9412 // A block of object or collection initializers
9414 public class CollectionOrObjectInitializers : ExpressionStatement
9416 IList<Expression> initializers;
9417 bool is_collection_initialization;
9419 public static readonly CollectionOrObjectInitializers Empty =
9420 new CollectionOrObjectInitializers (Array.AsReadOnly (new Expression [0]), Location.Null);
9422 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
9424 this.initializers = initializers;
9428 public bool IsEmpty {
9430 return initializers.Count == 0;
9434 public bool IsCollectionInitializer {
9436 return is_collection_initialization;
9440 protected override void CloneTo (CloneContext clonectx, Expression target)
9442 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9444 t.initializers = new List<Expression> (initializers.Count);
9445 foreach (var e in initializers)
9446 t.initializers.Add (e.Clone (clonectx));
9449 public override bool ContainsEmitWithAwait ()
9451 foreach (var e in initializers) {
9452 if (e.ContainsEmitWithAwait ())
9459 public override Expression CreateExpressionTree (ResolveContext ec)
9461 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
9462 foreach (Expression e in initializers) {
9463 Expression expr = e.CreateExpressionTree (ec);
9465 expr_initializers.Add (expr);
9468 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
9471 protected override Expression DoResolve (ResolveContext ec)
9473 List<string> element_names = null;
9474 for (int i = 0; i < initializers.Count; ++i) {
9475 Expression initializer = initializers [i];
9476 ElementInitializer element_initializer = initializer as ElementInitializer;
9479 if (element_initializer != null) {
9480 element_names = new List<string> (initializers.Count);
9481 element_names.Add (element_initializer.Name);
9482 } else if (initializer is CompletingExpression){
9483 initializer.Resolve (ec);
9484 throw new InternalErrorException ("This line should never be reached");
9486 var t = ec.CurrentInitializerVariable.Type;
9487 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
9488 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
9489 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9490 "object initializer because type `{1}' does not implement `{2}' interface",
9491 ec.CurrentInitializerVariable.GetSignatureForError (),
9492 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9493 TypeManager.CSharpName (ec.BuiltinTypes.IEnumerable));
9496 is_collection_initialization = true;
9499 if (is_collection_initialization != (element_initializer == null)) {
9500 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9501 is_collection_initialization ? "collection initializer" : "object initializer");
9505 if (!is_collection_initialization) {
9506 if (element_names.Contains (element_initializer.Name)) {
9507 ec.Report.Error (1912, element_initializer.Location,
9508 "An object initializer includes more than one member `{0}' initialization",
9509 element_initializer.Name);
9511 element_names.Add (element_initializer.Name);
9516 Expression e = initializer.Resolve (ec);
9517 if (e == EmptyExpressionStatement.Instance)
9518 initializers.RemoveAt (i--);
9520 initializers [i] = e;
9523 type = ec.CurrentInitializerVariable.Type;
9524 if (is_collection_initialization) {
9525 if (TypeManager.HasElementType (type)) {
9526 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9527 TypeManager.CSharpName (type));
9531 eclass = ExprClass.Variable;
9535 public override void Emit (EmitContext ec)
9540 public override void EmitStatement (EmitContext ec)
9542 foreach (ExpressionStatement e in initializers)
9543 e.EmitStatement (ec);
9548 // New expression with element/object initializers
9550 public class NewInitialize : New
9553 // This class serves as a proxy for variable initializer target instances.
9554 // A real variable is assigned later when we resolve left side of an
9557 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9559 NewInitialize new_instance;
9561 public InitializerTargetExpression (NewInitialize newInstance)
9563 this.type = newInstance.type;
9564 this.loc = newInstance.loc;
9565 this.eclass = newInstance.eclass;
9566 this.new_instance = newInstance;
9569 public override bool ContainsEmitWithAwait ()
9574 public override Expression CreateExpressionTree (ResolveContext ec)
9576 // Should not be reached
9577 throw new NotSupportedException ("ET");
9580 protected override Expression DoResolve (ResolveContext ec)
9585 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9590 public override void Emit (EmitContext ec)
9592 Expression e = (Expression) new_instance.instance;
9596 public override Expression EmitToField (EmitContext ec)
9598 return (Expression) new_instance.instance;
9601 #region IMemoryLocation Members
9603 public void AddressOf (EmitContext ec, AddressOp mode)
9605 new_instance.instance.AddressOf (ec, mode);
9611 CollectionOrObjectInitializers initializers;
9612 IMemoryLocation instance;
9614 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9615 : base (requested_type, arguments, l)
9617 this.initializers = initializers;
9620 protected override void CloneTo (CloneContext clonectx, Expression t)
9622 base.CloneTo (clonectx, t);
9624 NewInitialize target = (NewInitialize) t;
9625 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9628 public override bool ContainsEmitWithAwait ()
9630 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
9633 public override Expression CreateExpressionTree (ResolveContext ec)
9635 Arguments args = new Arguments (2);
9636 args.Add (new Argument (base.CreateExpressionTree (ec)));
9637 if (!initializers.IsEmpty)
9638 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9640 return CreateExpressionFactoryCall (ec,
9641 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9645 protected override Expression DoResolve (ResolveContext ec)
9647 Expression e = base.DoResolve (ec);
9651 Expression previous = ec.CurrentInitializerVariable;
9652 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9653 initializers.Resolve (ec);
9654 ec.CurrentInitializerVariable = previous;
9658 public override bool Emit (EmitContext ec, IMemoryLocation target)
9660 bool left_on_stack = base.Emit (ec, target);
9662 if (initializers.IsEmpty)
9663 return left_on_stack;
9665 LocalTemporary temp = null;
9667 instance = target as LocalTemporary;
9669 if (instance == null) {
9670 if (!left_on_stack) {
9671 VariableReference vr = target as VariableReference;
9673 // FIXME: This still does not work correctly for pre-set variables
9674 if (vr != null && vr.IsRef)
9675 target.AddressOf (ec, AddressOp.Load);
9677 ((Expression) target).Emit (ec);
9678 left_on_stack = true;
9681 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
9682 instance = new EmptyExpression (Type).EmitToField (ec) as IMemoryLocation;
9684 temp = new LocalTemporary (type);
9689 if (left_on_stack && temp != null)
9692 initializers.Emit (ec);
9694 if (left_on_stack) {
9699 ((Expression) instance).Emit (ec);
9703 return left_on_stack;
9706 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9708 instance = base.EmitAddressOf (ec, Mode);
9710 if (!initializers.IsEmpty)
9711 initializers.Emit (ec);
9717 public class NewAnonymousType : New
9719 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
9721 List<AnonymousTypeParameter> parameters;
9722 readonly TypeContainer parent;
9723 AnonymousTypeClass anonymous_type;
9725 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
9726 : base (null, null, loc)
9728 this.parameters = parameters;
9729 this.parent = parent;
9732 protected override void CloneTo (CloneContext clonectx, Expression target)
9734 if (parameters == null)
9737 NewAnonymousType t = (NewAnonymousType) target;
9738 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
9739 foreach (AnonymousTypeParameter atp in parameters)
9740 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
9743 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
9745 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
9749 type = AnonymousTypeClass.Create (parent, parameters, loc);
9755 type.ResolveTypeParameters ();
9758 if (ec.Report.Errors == 0)
9761 parent.Module.AddAnonymousType (type);
9765 public override Expression CreateExpressionTree (ResolveContext ec)
9767 if (parameters == null)
9768 return base.CreateExpressionTree (ec);
9770 var init = new ArrayInitializer (parameters.Count, loc);
9771 foreach (Property p in anonymous_type.Properties)
9772 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
9774 var ctor_args = new ArrayInitializer (arguments.Count, loc);
9775 foreach (Argument a in arguments)
9776 ctor_args.Add (a.CreateExpressionTree (ec));
9778 Arguments args = new Arguments (3);
9779 args.Add (new Argument (new TypeOfMethod (method, loc)));
9780 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
9781 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
9783 return CreateExpressionFactoryCall (ec, "New", args);
9786 protected override Expression DoResolve (ResolveContext ec)
9788 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
9789 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9793 if (parameters == null) {
9794 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
9795 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
9796 return base.DoResolve (ec);
9800 arguments = new Arguments (parameters.Count);
9801 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9802 for (int i = 0; i < parameters.Count; ++i) {
9803 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9809 arguments.Add (new Argument (e));
9810 t_args [i] = new TypeExpression (e.Type, e.Location);
9816 anonymous_type = CreateAnonymousType (ec, parameters);
9817 if (anonymous_type == null)
9820 RequestedType = new GenericTypeExpr (anonymous_type.Definition, new TypeArguments (t_args), loc);
9821 return base.DoResolve (ec);
9825 public class AnonymousTypeParameter : ShimExpression
9827 public readonly string Name;
9829 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9830 : base (initializer)
9836 public AnonymousTypeParameter (Parameter parameter)
9837 : base (new SimpleName (parameter.Name, parameter.Location))
9839 this.Name = parameter.Name;
9840 this.loc = parameter.Location;
9843 public override bool Equals (object o)
9845 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9846 return other != null && Name == other.Name;
9849 public override int GetHashCode ()
9851 return Name.GetHashCode ();
9854 protected override Expression DoResolve (ResolveContext ec)
9856 Expression e = expr.Resolve (ec);
9860 if (e.eclass == ExprClass.MethodGroup) {
9861 Error_InvalidInitializer (ec, e.ExprClassName);
9866 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
9867 Error_InvalidInitializer (ec, e.GetSignatureForError ());
9874 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
9876 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",