2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
19 using MetaType = IKVM.Reflection.Type;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
23 using MetaType = System.Type;
24 using System.Reflection;
25 using System.Reflection.Emit;
31 // This is an user operator expression, automatically created during
34 public class UserOperatorCall : Expression {
35 protected readonly Arguments arguments;
36 protected readonly MethodSpec oper;
37 readonly Func<ResolveContext, Expression, Expression> expr_tree;
39 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
42 this.arguments = args;
43 this.expr_tree = expr_tree;
45 type = oper.ReturnType;
46 eclass = ExprClass.Value;
50 public override bool ContainsEmitWithAwait ()
52 return arguments.ContainsEmitWithAwait ();
55 public override Expression CreateExpressionTree (ResolveContext ec)
57 if (expr_tree != null)
58 return expr_tree (ec, new TypeOfMethod (oper, loc));
60 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
61 new NullLiteral (loc),
62 new TypeOfMethod (oper, loc));
64 return CreateExpressionFactoryCall (ec, "Call", args);
67 protected override void CloneTo (CloneContext context, Expression target)
72 protected override Expression DoResolve (ResolveContext ec)
75 // We are born fully resolved
80 public override void Emit (EmitContext ec)
82 var call = new CallEmitter ();
83 call.EmitPredefined (ec, oper, arguments);
86 public override SLE.Expression MakeExpression (BuilderContext ctx)
89 return base.MakeExpression (ctx);
91 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
96 public class ParenthesizedExpression : ShimExpression
98 public ParenthesizedExpression (Expression expr)
104 protected override Expression DoResolve (ResolveContext ec)
106 return expr.Resolve (ec);
109 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
111 return expr.DoResolveLValue (ec, right_side);
116 // Unary implements unary expressions.
118 public class Unary : Expression
120 public enum Operator : byte {
121 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
125 public readonly Operator Oper;
126 public Expression Expr;
127 Expression enum_conversion;
129 public Unary (Operator op, Expression expr, Location loc)
137 // This routine will attempt to simplify the unary expression when the
138 // argument is a constant.
140 Constant TryReduceConstant (ResolveContext ec, Constant e)
142 if (e is EmptyConstantCast)
143 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
145 if (e is SideEffectConstant) {
146 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
147 return r == null ? null : new SideEffectConstant (r, e, r.Location);
150 TypeSpec expr_type = e.Type;
153 case Operator.UnaryPlus:
154 // Unary numeric promotions
155 switch (expr_type.BuiltinType) {
156 case BuiltinTypeSpec.Type.Byte:
157 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
158 case BuiltinTypeSpec.Type.SByte:
159 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
160 case BuiltinTypeSpec.Type.Short:
161 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
162 case BuiltinTypeSpec.Type.UShort:
163 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
164 case BuiltinTypeSpec.Type.Char:
165 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
167 // Predefined operators
168 case BuiltinTypeSpec.Type.Int:
169 case BuiltinTypeSpec.Type.UInt:
170 case BuiltinTypeSpec.Type.Long:
171 case BuiltinTypeSpec.Type.ULong:
172 case BuiltinTypeSpec.Type.Float:
173 case BuiltinTypeSpec.Type.Double:
174 case BuiltinTypeSpec.Type.Decimal:
180 case Operator.UnaryNegation:
181 // Unary numeric promotions
182 switch (expr_type.BuiltinType) {
183 case BuiltinTypeSpec.Type.Byte:
184 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
185 case BuiltinTypeSpec.Type.SByte:
186 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
187 case BuiltinTypeSpec.Type.Short:
188 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
189 case BuiltinTypeSpec.Type.UShort:
190 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
191 case BuiltinTypeSpec.Type.Char:
192 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
194 // Predefined operators
195 case BuiltinTypeSpec.Type.Int:
196 int ivalue = ((IntConstant) e).Value;
197 if (ivalue == int.MinValue) {
198 if (ec.ConstantCheckState) {
199 ConstantFold.Error_CompileTimeOverflow (ec, loc);
204 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
206 case BuiltinTypeSpec.Type.Long:
207 long lvalue = ((LongConstant) e).Value;
208 if (lvalue == long.MinValue) {
209 if (ec.ConstantCheckState) {
210 ConstantFold.Error_CompileTimeOverflow (ec, loc);
215 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
217 case BuiltinTypeSpec.Type.UInt:
218 UIntLiteral uil = e as UIntLiteral;
220 if (uil.Value == int.MaxValue + (uint) 1)
221 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
222 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
224 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
227 case BuiltinTypeSpec.Type.ULong:
228 ULongLiteral ull = e as ULongLiteral;
229 if (ull != null && ull.Value == 9223372036854775808)
230 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
233 case BuiltinTypeSpec.Type.Float:
234 FloatLiteral fl = e as FloatLiteral;
235 // For better error reporting
237 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
239 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
241 case BuiltinTypeSpec.Type.Double:
242 DoubleLiteral dl = e as DoubleLiteral;
243 // For better error reporting
245 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
247 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
249 case BuiltinTypeSpec.Type.Decimal:
250 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
255 case Operator.LogicalNot:
256 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
259 bool b = (bool)e.GetValue ();
260 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
262 case Operator.OnesComplement:
263 // Unary numeric promotions
264 switch (expr_type.BuiltinType) {
265 case BuiltinTypeSpec.Type.Byte:
266 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
267 case BuiltinTypeSpec.Type.SByte:
268 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
269 case BuiltinTypeSpec.Type.Short:
270 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
271 case BuiltinTypeSpec.Type.UShort:
272 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
273 case BuiltinTypeSpec.Type.Char:
274 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
276 // Predefined operators
277 case BuiltinTypeSpec.Type.Int:
278 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
279 case BuiltinTypeSpec.Type.UInt:
280 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
281 case BuiltinTypeSpec.Type.Long:
282 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
283 case BuiltinTypeSpec.Type.ULong:
284 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
286 if (e is EnumConstant) {
287 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
289 e = new EnumConstant (e, expr_type);
294 throw new Exception ("Can not constant fold: " + Oper.ToString());
297 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
299 eclass = ExprClass.Value;
301 TypeSpec expr_type = expr.Type;
302 Expression best_expr;
304 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
307 // Primitive types first
309 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
310 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
311 if (best_expr == null)
314 type = best_expr.Type;
320 // E operator ~(E x);
322 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
323 return ResolveEnumOperator (ec, expr, predefined);
325 return ResolveUserType (ec, expr, predefined);
328 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
330 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
331 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
332 if (best_expr == null)
336 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (best_expr.Type), underlying_type);
338 return EmptyCast.Create (this, type);
341 public override bool ContainsEmitWithAwait ()
343 return Expr.ContainsEmitWithAwait ();
346 public override Expression CreateExpressionTree (ResolveContext ec)
348 return CreateExpressionTree (ec, null);
351 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
355 case Operator.AddressOf:
356 Error_PointerInsideExpressionTree (ec);
358 case Operator.UnaryNegation:
359 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
360 method_name = "NegateChecked";
362 method_name = "Negate";
364 case Operator.OnesComplement:
365 case Operator.LogicalNot:
368 case Operator.UnaryPlus:
369 method_name = "UnaryPlus";
372 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
375 Arguments args = new Arguments (2);
376 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
378 args.Add (new Argument (user_op));
380 return CreateExpressionFactoryCall (ec, method_name, args);
383 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
385 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
388 // 7.6.1 Unary plus operator
390 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
391 types.Int, types.UInt,
392 types.Long, types.ULong,
393 types.Float, types.Double,
398 // 7.6.2 Unary minus operator
400 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
401 types.Int, types.Long,
402 types.Float, types.Double,
407 // 7.6.3 Logical negation operator
409 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
414 // 7.6.4 Bitwise complement operator
416 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
417 types.Int, types.UInt,
418 types.Long, types.ULong
421 return predefined_operators;
425 // Unary numeric promotions
427 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
429 TypeSpec expr_type = expr.Type;
430 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
431 switch (expr_type.BuiltinType) {
432 case BuiltinTypeSpec.Type.Byte:
433 case BuiltinTypeSpec.Type.SByte:
434 case BuiltinTypeSpec.Type.Short:
435 case BuiltinTypeSpec.Type.UShort:
436 case BuiltinTypeSpec.Type.Char:
437 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
441 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
442 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
447 protected override Expression DoResolve (ResolveContext ec)
449 if (Oper == Operator.AddressOf) {
450 return ResolveAddressOf (ec);
453 Expr = Expr.Resolve (ec);
457 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
458 Arguments args = new Arguments (1);
459 args.Add (new Argument (Expr));
460 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
463 if (Expr.Type.IsNullableType)
464 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
467 // Attempt to use a constant folding operation.
469 Constant cexpr = Expr as Constant;
471 cexpr = TryReduceConstant (ec, cexpr);
476 Expression expr = ResolveOperator (ec, Expr);
478 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
481 // Reduce unary operator on predefined types
483 if (expr == this && Oper == Operator.UnaryPlus)
489 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
494 public override void Emit (EmitContext ec)
496 EmitOperator (ec, type);
499 protected void EmitOperator (EmitContext ec, TypeSpec type)
502 case Operator.UnaryPlus:
506 case Operator.UnaryNegation:
507 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
508 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
509 Expr = Expr.EmitToField (ec);
512 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
513 ec.Emit (OpCodes.Conv_U8);
515 ec.Emit (OpCodes.Sub_Ovf);
518 ec.Emit (OpCodes.Neg);
523 case Operator.LogicalNot:
526 ec.Emit (OpCodes.Ceq);
529 case Operator.OnesComplement:
531 ec.Emit (OpCodes.Not);
534 case Operator.AddressOf:
535 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
539 throw new Exception ("This should not happen: Operator = "
544 // Same trick as in Binary expression
546 if (enum_conversion != null)
547 enum_conversion.Emit (ec);
550 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
552 if (Oper == Operator.LogicalNot)
553 Expr.EmitBranchable (ec, target, !on_true);
555 base.EmitBranchable (ec, target, on_true);
558 public override void EmitSideEffect (EmitContext ec)
560 Expr.EmitSideEffect (ec);
564 // Converts operator to System.Linq.Expressions.ExpressionType enum name
566 string GetOperatorExpressionTypeName ()
569 case Operator.OnesComplement:
570 return "OnesComplement";
571 case Operator.LogicalNot:
573 case Operator.UnaryNegation:
575 case Operator.UnaryPlus:
578 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
582 static bool IsFloat (TypeSpec t)
584 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
588 // Returns a stringified representation of the Operator
590 public static string OperName (Operator oper)
593 case Operator.UnaryPlus:
595 case Operator.UnaryNegation:
597 case Operator.LogicalNot:
599 case Operator.OnesComplement:
601 case Operator.AddressOf:
605 throw new NotImplementedException (oper.ToString ());
608 public override SLE.Expression MakeExpression (BuilderContext ctx)
610 var expr = Expr.MakeExpression (ctx);
611 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
614 case Operator.UnaryNegation:
615 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
616 case Operator.LogicalNot:
617 return SLE.Expression.Not (expr);
619 case Operator.OnesComplement:
620 return SLE.Expression.OnesComplement (expr);
623 throw new NotImplementedException (Oper.ToString ());
627 Expression ResolveAddressOf (ResolveContext ec)
630 UnsafeError (ec, loc);
632 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
633 if (Expr == null || Expr.eclass != ExprClass.Variable) {
634 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
638 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
642 IVariableReference vr = Expr as IVariableReference;
645 is_fixed = vr.IsFixed;
646 vr.SetHasAddressTaken ();
649 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
652 IFixedExpression fe = Expr as IFixedExpression;
653 is_fixed = fe != null && fe.IsFixed;
656 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
657 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
660 type = PointerContainer.MakeType (ec.Module, Expr.Type);
661 eclass = ExprClass.Value;
665 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
667 expr = DoNumericPromotion (rc, Oper, expr);
668 TypeSpec expr_type = expr.Type;
669 foreach (TypeSpec t in predefined) {
677 // Perform user-operator overload resolution
679 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
681 CSharp.Operator.OpType op_type;
683 case Operator.LogicalNot:
684 op_type = CSharp.Operator.OpType.LogicalNot; break;
685 case Operator.OnesComplement:
686 op_type = CSharp.Operator.OpType.OnesComplement; break;
687 case Operator.UnaryNegation:
688 op_type = CSharp.Operator.OpType.UnaryNegation; break;
689 case Operator.UnaryPlus:
690 op_type = CSharp.Operator.OpType.UnaryPlus; break;
692 throw new InternalErrorException (Oper.ToString ());
695 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
699 Arguments args = new Arguments (1);
700 args.Add (new Argument (expr));
702 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
703 var oper = res.ResolveOperator (ec, ref args);
708 Expr = args [0].Expr;
709 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
713 // Unary user type overload resolution
715 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
717 Expression best_expr = ResolveUserOperator (ec, expr);
718 if (best_expr != null)
721 foreach (TypeSpec t in predefined) {
722 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
723 if (oper_expr == null)
726 if (oper_expr == ErrorExpression.Instance)
730 // decimal type is predefined but has user-operators
732 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
733 oper_expr = ResolveUserType (ec, oper_expr, predefined);
735 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
737 if (oper_expr == null)
740 if (best_expr == null) {
741 best_expr = oper_expr;
745 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
747 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
748 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
749 OperName (Oper), expr.Type.GetSignatureForError ());
751 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
758 best_expr = oper_expr;
761 if (best_expr == null)
765 // HACK: Decimal user-operator is included in standard operators
767 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
771 type = best_expr.Type;
775 protected override void CloneTo (CloneContext clonectx, Expression t)
777 Unary target = (Unary) t;
779 target.Expr = Expr.Clone (clonectx);
784 // Unary operators are turned into Indirection expressions
785 // after semantic analysis (this is so we can take the address
786 // of an indirection).
788 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
790 LocalTemporary temporary;
793 public Indirection (Expression expr, Location l)
799 public bool IsFixed {
803 protected override void CloneTo (CloneContext clonectx, Expression t)
805 Indirection target = (Indirection) t;
806 target.expr = expr.Clone (clonectx);
809 public override bool ContainsEmitWithAwait ()
811 throw new NotImplementedException ();
814 public override Expression CreateExpressionTree (ResolveContext ec)
816 Error_PointerInsideExpressionTree (ec);
820 public override void Emit (EmitContext ec)
825 ec.EmitLoadFromPtr (Type);
828 public void Emit (EmitContext ec, bool leave_copy)
832 ec.Emit (OpCodes.Dup);
833 temporary = new LocalTemporary (expr.Type);
834 temporary.Store (ec);
838 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
840 prepared = isCompound;
845 ec.Emit (OpCodes.Dup);
849 ec.Emit (OpCodes.Dup);
850 temporary = new LocalTemporary (source.Type);
851 temporary.Store (ec);
854 ec.EmitStoreFromPtr (type);
856 if (temporary != null) {
858 temporary.Release (ec);
862 public void AddressOf (EmitContext ec, AddressOp Mode)
867 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
869 return DoResolve (ec);
872 protected override Expression DoResolve (ResolveContext ec)
874 expr = expr.Resolve (ec);
879 UnsafeError (ec, loc);
881 var pc = expr.Type as PointerContainer;
884 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
890 if (type.Kind == MemberKind.Void) {
891 Error_VoidPointerOperation (ec);
895 eclass = ExprClass.Variable;
901 /// Unary Mutator expressions (pre and post ++ and --)
905 /// UnaryMutator implements ++ and -- expressions. It derives from
906 /// ExpressionStatement becuase the pre/post increment/decrement
907 /// operators can be used in a statement context.
909 /// FIXME: Idea, we could split this up in two classes, one simpler
910 /// for the common case, and one with the extra fields for more complex
911 /// classes (indexers require temporary access; overloaded require method)
914 public class UnaryMutator : ExpressionStatement
916 class DynamicPostMutator : Expression, IAssignMethod
921 public DynamicPostMutator (Expression expr)
924 this.type = expr.Type;
925 this.loc = expr.Location;
928 public override Expression CreateExpressionTree (ResolveContext ec)
930 throw new NotImplementedException ("ET");
933 protected override Expression DoResolve (ResolveContext rc)
935 eclass = expr.eclass;
939 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
941 expr.DoResolveLValue (ec, right_side);
942 return DoResolve (ec);
945 public override void Emit (EmitContext ec)
950 public void Emit (EmitContext ec, bool leave_copy)
952 throw new NotImplementedException ();
956 // Emits target assignment using unmodified source value
958 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
961 // Allocate temporary variable to keep original value before it's modified
963 temp = new LocalTemporary (type);
967 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
978 public enum Mode : byte {
985 PreDecrement = IsDecrement,
986 PostIncrement = IsPost,
987 PostDecrement = IsPost | IsDecrement
991 bool is_expr, recurse;
993 protected Expression expr;
995 // Holds the real operation
996 Expression operation;
998 public UnaryMutator (Mode m, Expression e, Location loc)
1005 public override bool ContainsEmitWithAwait ()
1007 return expr.ContainsEmitWithAwait ();
1010 public override Expression CreateExpressionTree (ResolveContext ec)
1012 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1015 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1018 // Predefined ++ and -- operators exist for the following types:
1019 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1021 return new TypeSpec[] {
1037 protected override Expression DoResolve (ResolveContext ec)
1039 expr = expr.Resolve (ec);
1044 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1046 // Handle postfix unary operators using local
1047 // temporary variable
1049 if ((mode & Mode.IsPost) != 0)
1050 expr = new DynamicPostMutator (expr);
1052 Arguments args = new Arguments (1);
1053 args.Add (new Argument (expr));
1054 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1057 if (expr.Type.IsNullableType)
1058 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1060 return DoResolveOperation (ec);
1063 protected Expression DoResolveOperation (ResolveContext ec)
1065 eclass = ExprClass.Value;
1068 if (expr is RuntimeValueExpression) {
1071 // Use itself at the top of the stack
1072 operation = new EmptyExpression (type);
1076 // The operand of the prefix/postfix increment decrement operators
1077 // should be an expression that is classified as a variable,
1078 // a property access or an indexer access
1080 // TODO: Move to parser, expr is ATypeNameExpression
1081 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1082 expr = expr.ResolveLValue (ec, expr);
1084 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1088 // Step 1: Try to find a user operator, it has priority over predefined ones
1090 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1091 var methods = MemberCache.GetUserOperator (type, user_op, false);
1093 if (methods != null) {
1094 Arguments args = new Arguments (1);
1095 args.Add (new Argument (expr));
1097 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1098 var method = res.ResolveOperator (ec, ref args);
1102 args[0].Expr = operation;
1103 operation = new UserOperatorCall (method, args, null, loc);
1104 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1109 // Step 2: Try predefined types
1112 Expression source = null;
1113 bool primitive_type;
1116 // Predefined without user conversion first for speed-up
1118 // Predefined ++ and -- operators exist for the following types:
1119 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1121 switch (type.BuiltinType) {
1122 case BuiltinTypeSpec.Type.Byte:
1123 case BuiltinTypeSpec.Type.SByte:
1124 case BuiltinTypeSpec.Type.Short:
1125 case BuiltinTypeSpec.Type.UShort:
1126 case BuiltinTypeSpec.Type.Int:
1127 case BuiltinTypeSpec.Type.UInt:
1128 case BuiltinTypeSpec.Type.Long:
1129 case BuiltinTypeSpec.Type.ULong:
1130 case BuiltinTypeSpec.Type.Char:
1131 case BuiltinTypeSpec.Type.Float:
1132 case BuiltinTypeSpec.Type.Double:
1133 case BuiltinTypeSpec.Type.Decimal:
1135 primitive_type = true;
1138 primitive_type = false;
1140 // ++/-- on pointer variables of all types except void*
1141 if (type.IsPointer) {
1142 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1143 Error_VoidPointerOperation (ec);
1149 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1150 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1152 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1153 if (source != null) {
1159 // ++/-- on enum types
1160 if (source == null && type.IsEnum)
1163 if (source == null) {
1164 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1171 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1172 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1173 operation = new Binary (op, source, one, loc);
1174 operation = operation.Resolve (ec);
1175 if (operation == null)
1176 throw new NotImplementedException ("should not be reached");
1178 if (operation.Type != type) {
1180 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1182 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1188 void EmitCode (EmitContext ec, bool is_expr)
1191 this.is_expr = is_expr;
1192 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1195 public override void Emit (EmitContext ec)
1198 // We use recurse to allow ourselfs to be the source
1199 // of an assignment. This little hack prevents us from
1200 // having to allocate another expression
1203 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1211 EmitCode (ec, true);
1214 protected virtual void EmitOperation (EmitContext ec)
1216 operation.Emit (ec);
1219 public override void EmitStatement (EmitContext ec)
1221 EmitCode (ec, false);
1225 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1227 string GetOperatorExpressionTypeName ()
1229 return IsDecrement ? "Decrement" : "Increment";
1233 get { return (mode & Mode.IsDecrement) != 0; }
1238 public override SLE.Expression MakeExpression (BuilderContext ctx)
1240 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1241 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1242 return SLE.Expression.Assign (target, source);
1246 protected override void CloneTo (CloneContext clonectx, Expression t)
1248 UnaryMutator target = (UnaryMutator) t;
1250 target.expr = expr.Clone (clonectx);
1255 // Base class for the `is' and `as' operators
1257 public abstract class Probe : Expression
1259 public Expression ProbeType;
1260 protected Expression expr;
1261 protected TypeSpec probe_type_expr;
1263 public Probe (Expression expr, Expression probe_type, Location l)
1265 ProbeType = probe_type;
1270 public Expression Expr {
1276 public override bool ContainsEmitWithAwait ()
1278 return expr.ContainsEmitWithAwait ();
1281 protected override Expression DoResolve (ResolveContext ec)
1283 probe_type_expr = ProbeType.ResolveAsType (ec);
1284 if (probe_type_expr == null)
1287 expr = expr.Resolve (ec);
1291 if (probe_type_expr.IsStatic) {
1292 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1296 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1297 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1302 if (expr.Type == InternalType.AnonymousMethod) {
1303 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1311 protected abstract string OperatorName { get; }
1313 protected override void CloneTo (CloneContext clonectx, Expression t)
1315 Probe target = (Probe) t;
1317 target.expr = expr.Clone (clonectx);
1318 target.ProbeType = ProbeType.Clone (clonectx);
1324 /// Implementation of the `is' operator.
1326 public class Is : Probe
1328 Nullable.Unwrap expr_unwrap;
1330 public Is (Expression expr, Expression probe_type, Location l)
1331 : base (expr, probe_type, l)
1335 public override Expression CreateExpressionTree (ResolveContext ec)
1337 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1338 expr.CreateExpressionTree (ec),
1339 new TypeOf (probe_type_expr, loc));
1341 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1344 public override void Emit (EmitContext ec)
1346 if (expr_unwrap != null) {
1347 expr_unwrap.EmitCheck (ec);
1353 // Only to make verifier happy
1354 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1355 ec.Emit (OpCodes.Box, expr.Type);
1357 ec.Emit (OpCodes.Isinst, probe_type_expr);
1359 ec.Emit (OpCodes.Cgt_Un);
1362 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1364 if (expr_unwrap != null) {
1365 expr_unwrap.EmitCheck (ec);
1368 ec.Emit (OpCodes.Isinst, probe_type_expr);
1370 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1373 Expression CreateConstantResult (ResolveContext ec, bool result)
1376 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1377 TypeManager.CSharpName (probe_type_expr));
1379 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1380 TypeManager.CSharpName (probe_type_expr));
1382 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, result, loc), this);
1385 protected override Expression DoResolve (ResolveContext ec)
1387 if (base.DoResolve (ec) == null)
1390 TypeSpec d = expr.Type;
1391 bool d_is_nullable = false;
1394 // If E is a method group or the null literal, or if the type of E is a reference
1395 // type or a nullable type and the value of E is null, the result is false
1397 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1398 return CreateConstantResult (ec, false);
1400 if (d.IsNullableType) {
1401 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1402 if (!ut.IsGenericParameter) {
1404 d_is_nullable = true;
1408 type = ec.BuiltinTypes.Bool;
1409 eclass = ExprClass.Value;
1410 TypeSpec t = probe_type_expr;
1411 bool t_is_nullable = false;
1412 if (t.IsNullableType) {
1413 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1414 if (!ut.IsGenericParameter) {
1416 t_is_nullable = true;
1423 // D and T are the same value types but D can be null
1425 if (d_is_nullable && !t_is_nullable) {
1426 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1431 // The result is true if D and T are the same value types
1433 return CreateConstantResult (ec, true);
1436 var tp = d as TypeParameterSpec;
1438 return ResolveGenericParameter (ec, t, tp);
1441 // An unboxing conversion exists
1443 if (Convert.ExplicitReferenceConversionExists (d, t))
1446 if (TypeManager.IsGenericParameter (t))
1447 return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
1449 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1450 ec.Report.Warning (1981, 3, loc,
1451 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1452 OperatorName, t.GetSignatureForError ());
1455 if (TypeManager.IsGenericParameter (d))
1456 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1458 if (TypeSpec.IsValueType (d)) {
1459 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1460 if (d_is_nullable && !t_is_nullable) {
1461 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1465 return CreateConstantResult (ec, true);
1468 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1470 // Do not optimize for imported type
1472 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None)
1476 // Turn is check into simple null check for implicitly convertible reference types
1478 return ReducedExpression.Create (
1479 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), loc).Resolve (ec),
1483 if (Convert.ExplicitReferenceConversionExists (d, t)) {
1489 return CreateConstantResult (ec, false);
1492 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1494 if (t.IsReferenceType) {
1496 return CreateConstantResult (ec, false);
1499 if (TypeManager.IsGenericParameter (expr.Type)) {
1500 if (expr.Type == d && TypeSpec.IsValueType (t))
1501 return CreateConstantResult (ec, true);
1503 expr = new BoxedCast (expr, d);
1509 protected override string OperatorName {
1510 get { return "is"; }
1515 /// Implementation of the `as' operator.
1517 public class As : Probe {
1518 Expression resolved_type;
1520 public As (Expression expr, Expression probe_type, Location l)
1521 : base (expr, probe_type, l)
1525 public override Expression CreateExpressionTree (ResolveContext ec)
1527 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1528 expr.CreateExpressionTree (ec),
1529 new TypeOf (probe_type_expr, loc));
1531 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1534 public override void Emit (EmitContext ec)
1538 ec.Emit (OpCodes.Isinst, type);
1540 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1541 ec.Emit (OpCodes.Unbox_Any, type);
1544 protected override Expression DoResolve (ResolveContext ec)
1546 if (resolved_type == null) {
1547 resolved_type = base.DoResolve (ec);
1549 if (resolved_type == null)
1553 type = probe_type_expr;
1554 eclass = ExprClass.Value;
1555 TypeSpec etype = expr.Type;
1557 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1558 if (TypeManager.IsGenericParameter (type)) {
1559 ec.Report.Error (413, loc,
1560 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1561 probe_type_expr.GetSignatureForError ());
1563 ec.Report.Error (77, loc,
1564 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1565 TypeManager.CSharpName (type));
1570 if (expr.IsNull && type.IsNullableType) {
1571 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1574 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1575 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1579 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1581 e = EmptyCast.Create (e, type);
1582 return ReducedExpression.Create (e, this).Resolve (ec);
1585 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1586 if (TypeManager.IsGenericParameter (etype))
1587 expr = new BoxedCast (expr, etype);
1592 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1593 expr = new BoxedCast (expr, etype);
1597 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1598 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1603 protected override string OperatorName {
1604 get { return "as"; }
1609 // This represents a typecast in the source language.
1611 public class Cast : ShimExpression {
1612 Expression target_type;
1614 public Cast (Expression cast_type, Expression expr, Location loc)
1617 this.target_type = cast_type;
1621 public Expression TargetType {
1622 get { return target_type; }
1625 protected override Expression DoResolve (ResolveContext ec)
1627 expr = expr.Resolve (ec);
1631 type = target_type.ResolveAsType (ec);
1635 if (type.IsStatic) {
1636 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1640 eclass = ExprClass.Value;
1642 Constant c = expr as Constant;
1644 c = c.TryReduce (ec, type, loc);
1649 if (type.IsPointer && !ec.IsUnsafe) {
1650 UnsafeError (ec, loc);
1653 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1655 return EmptyCast.Create (res, type);
1660 protected override void CloneTo (CloneContext clonectx, Expression t)
1662 Cast target = (Cast) t;
1664 target.target_type = target_type.Clone (clonectx);
1665 target.expr = expr.Clone (clonectx);
1669 public class ImplicitCast : ShimExpression
1673 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1676 this.loc = expr.Location;
1678 this.arrayAccess = arrayAccess;
1681 protected override Expression DoResolve (ResolveContext ec)
1683 expr = expr.Resolve (ec);
1688 expr = ConvertExpressionToArrayIndex (ec, expr);
1690 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1697 // C# 2.0 Default value expression
1699 public class DefaultValueExpression : Expression
1703 public DefaultValueExpression (Expression expr, Location loc)
1709 public override bool IsSideEffectFree {
1715 public override bool ContainsEmitWithAwait ()
1720 public override Expression CreateExpressionTree (ResolveContext ec)
1722 Arguments args = new Arguments (2);
1723 args.Add (new Argument (this));
1724 args.Add (new Argument (new TypeOf (type, loc)));
1725 return CreateExpressionFactoryCall (ec, "Constant", args);
1728 protected override Expression DoResolve (ResolveContext ec)
1730 type = expr.ResolveAsType (ec);
1734 if (type.IsStatic) {
1735 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1739 return new NullLiteral (Location).ConvertImplicitly (type);
1741 if (TypeSpec.IsReferenceType (type))
1742 return new NullConstant (type, loc);
1744 Constant c = New.Constantify (type, expr.Location);
1748 eclass = ExprClass.Variable;
1752 public override void Emit (EmitContext ec)
1754 LocalTemporary temp_storage = new LocalTemporary(type);
1756 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1757 ec.Emit(OpCodes.Initobj, type);
1758 temp_storage.Emit(ec);
1759 temp_storage.Release (ec);
1762 #if NET_4_0 && !STATIC
1763 public override SLE.Expression MakeExpression (BuilderContext ctx)
1765 return SLE.Expression.Default (type.GetMetaInfo ());
1769 protected override void CloneTo (CloneContext clonectx, Expression t)
1771 DefaultValueExpression target = (DefaultValueExpression) t;
1773 target.expr = expr.Clone (clonectx);
1778 /// Binary operators
1780 public class Binary : Expression, IDynamicBinder
1782 public class PredefinedOperator
1784 protected readonly TypeSpec left;
1785 protected readonly TypeSpec right;
1786 public readonly Operator OperatorsMask;
1787 public TypeSpec ReturnType;
1789 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1790 : this (ltype, rtype, op_mask, ltype)
1794 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1795 : this (type, type, op_mask, return_type)
1799 public PredefinedOperator (TypeSpec type, Operator op_mask)
1800 : this (type, type, op_mask, type)
1804 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1806 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1807 throw new InternalErrorException ("Only masked values can be used");
1811 this.OperatorsMask = op_mask;
1812 this.ReturnType = return_type;
1815 public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1817 b.type = ReturnType;
1819 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1820 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1823 // A user operators does not support multiple user conversions, but decimal type
1824 // is considered to be predefined type therefore we apply predefined operators rules
1825 // and then look for decimal user-operator implementation
1827 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal)
1828 return b.ResolveUserOperator (ec, b.left, b.right);
1830 var c = b.right as Constant;
1832 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1833 return ReducedExpression.Create (b.left, b).Resolve (ec);
1834 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
1835 return ReducedExpression.Create (b.left, b).Resolve (ec);
1839 c = b.left as Constant;
1841 if (c.IsDefaultValue && (b.oper == Operator.Addition || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1842 return ReducedExpression.Create (b.right, b).Resolve (ec);
1843 if (b.oper == Operator.Multiply && c.IsOneInteger)
1844 return ReducedExpression.Create (b.right, b).Resolve (ec);
1851 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
1854 // We are dealing with primitive types only
1856 return left == ltype && ltype == rtype;
1859 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1862 if (left == lexpr.Type && right == rexpr.Type)
1865 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1866 Convert.ImplicitConversionExists (ec, rexpr, right);
1869 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1872 if (left != null && best_operator.left != null) {
1873 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left, left);
1877 // When second argument is same as the first one, the result is same
1879 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1880 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right, right);
1883 if (result == 0 || result > 2)
1886 return result == 1 ? best_operator : this;
1890 sealed class PredefinedStringOperator : PredefinedOperator
1892 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
1893 : base (type, type, op_mask, retType)
1897 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
1898 : base (ltype, rtype, op_mask, retType)
1902 public override Expression ConvertResult (ResolveContext ec, Binary b)
1905 // Use original expression for nullable arguments
1907 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1909 b.left = unwrap.Original;
1911 unwrap = b.right as Nullable.Unwrap;
1913 b.right = unwrap.Original;
1915 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1916 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1919 // Start a new concat expression using converted expression
1921 return StringConcat.Create (ec, b.left, b.right, b.loc);
1925 sealed class PredefinedShiftOperator : PredefinedOperator
1927 public PredefinedShiftOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1928 : base (ltype, rtype, op_mask)
1932 public override Expression ConvertResult (ResolveContext ec, Binary b)
1934 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1936 Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1938 int right_mask = left.BuiltinType == BuiltinTypeSpec.Type.Int || left.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
1941 // b = b.left >> b.right & (0x1f|0x3f)
1943 b.right = new Binary (Operator.BitwiseAnd,
1944 b.right, new IntConstant (ec.BuiltinTypes, right_mask, b.right.Location), b.loc).Resolve (ec);
1947 // Expression tree representation does not use & mask
1949 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1950 b.type = ReturnType;
1953 // Optimize shift by 0
1955 var c = b.right as Constant;
1956 if (c != null && c.IsDefaultValue)
1957 return ReducedExpression.Create (b.left, b).Resolve (ec);
1963 sealed class PredefinedEqualityOperator : PredefinedOperator
1965 MethodSpec equal_method, inequal_method;
1967 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
1968 : base (arg, arg, Operator.EqualityMask, retType)
1972 public override Expression ConvertResult (ResolveContext ec, Binary b)
1974 b.type = ReturnType;
1976 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1977 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1979 Arguments args = new Arguments (2);
1980 args.Add (new Argument (b.left));
1981 args.Add (new Argument (b.right));
1984 if (b.oper == Operator.Equality) {
1985 if (equal_method == null) {
1986 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
1987 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
1988 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
1989 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
1991 throw new NotImplementedException (left.GetSignatureForError ());
1994 method = equal_method;
1996 if (inequal_method == null) {
1997 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
1998 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
1999 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2000 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2002 throw new NotImplementedException (left.GetSignatureForError ());
2005 method = inequal_method;
2008 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2012 class PredefinedPointerOperator : PredefinedOperator
2014 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2015 : base (ltype, rtype, op_mask)
2019 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2020 : base (ltype, rtype, op_mask, retType)
2024 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2025 : base (type, op_mask, return_type)
2029 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2032 if (!lexpr.Type.IsPointer)
2035 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2039 if (right == null) {
2040 if (!rexpr.Type.IsPointer)
2043 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2050 public override Expression ConvertResult (ResolveContext ec, Binary b)
2053 b.left = EmptyCast.Create (b.left, left);
2054 } else if (right != null) {
2055 b.right = EmptyCast.Create (b.right, right);
2058 TypeSpec r_type = ReturnType;
2059 Expression left_arg, right_arg;
2060 if (r_type == null) {
2063 right_arg = b.right;
2064 r_type = b.left.Type;
2068 r_type = b.right.Type;
2072 right_arg = b.right;
2075 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2080 public enum Operator {
2081 Multiply = 0 | ArithmeticMask,
2082 Division = 1 | ArithmeticMask,
2083 Modulus = 2 | ArithmeticMask,
2084 Addition = 3 | ArithmeticMask | AdditionMask,
2085 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2087 LeftShift = 5 | ShiftMask,
2088 RightShift = 6 | ShiftMask,
2090 LessThan = 7 | ComparisonMask | RelationalMask,
2091 GreaterThan = 8 | ComparisonMask | RelationalMask,
2092 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2093 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2094 Equality = 11 | ComparisonMask | EqualityMask,
2095 Inequality = 12 | ComparisonMask | EqualityMask,
2097 BitwiseAnd = 13 | BitwiseMask,
2098 ExclusiveOr = 14 | BitwiseMask,
2099 BitwiseOr = 15 | BitwiseMask,
2101 LogicalAnd = 16 | LogicalMask,
2102 LogicalOr = 17 | LogicalMask,
2107 ValuesOnlyMask = ArithmeticMask - 1,
2108 ArithmeticMask = 1 << 5,
2110 ComparisonMask = 1 << 7,
2111 EqualityMask = 1 << 8,
2112 BitwiseMask = 1 << 9,
2113 LogicalMask = 1 << 10,
2114 AdditionMask = 1 << 11,
2115 SubtractionMask = 1 << 12,
2116 RelationalMask = 1 << 13
2119 protected enum State
2123 LeftNullLifted = 1 << 2,
2124 RightNullLifted = 1 << 3
2127 readonly Operator oper;
2128 protected Expression left, right;
2129 protected State state;
2130 Expression enum_conversion;
2132 public Binary (Operator oper, Expression left, Expression right, bool isCompound, Location loc)
2133 : this (oper, left, right, loc)
2136 state |= State.Compound;
2139 public Binary (Operator oper, Expression left, Expression right, Location loc)
2149 public bool IsCompound {
2151 return (state & State.Compound) != 0;
2155 public Operator Oper {
2164 /// Returns a stringified representation of the Operator
2166 string OperName (Operator oper)
2170 case Operator.Multiply:
2173 case Operator.Division:
2176 case Operator.Modulus:
2179 case Operator.Addition:
2182 case Operator.Subtraction:
2185 case Operator.LeftShift:
2188 case Operator.RightShift:
2191 case Operator.LessThan:
2194 case Operator.GreaterThan:
2197 case Operator.LessThanOrEqual:
2200 case Operator.GreaterThanOrEqual:
2203 case Operator.Equality:
2206 case Operator.Inequality:
2209 case Operator.BitwiseAnd:
2212 case Operator.BitwiseOr:
2215 case Operator.ExclusiveOr:
2218 case Operator.LogicalOr:
2221 case Operator.LogicalAnd:
2225 s = oper.ToString ();
2235 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2237 new Binary (oper, left, right, loc).Error_OperatorCannotBeApplied (ec, left, right);
2240 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2242 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
2246 l = TypeManager.CSharpName (left.Type);
2247 r = TypeManager.CSharpName (right.Type);
2249 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2253 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2255 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2259 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2261 string GetOperatorExpressionTypeName ()
2264 case Operator.Addition:
2265 return IsCompound ? "AddAssign" : "Add";
2266 case Operator.BitwiseAnd:
2267 return IsCompound ? "AndAssign" : "And";
2268 case Operator.BitwiseOr:
2269 return IsCompound ? "OrAssign" : "Or";
2270 case Operator.Division:
2271 return IsCompound ? "DivideAssign" : "Divide";
2272 case Operator.ExclusiveOr:
2273 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2274 case Operator.Equality:
2276 case Operator.GreaterThan:
2277 return "GreaterThan";
2278 case Operator.GreaterThanOrEqual:
2279 return "GreaterThanOrEqual";
2280 case Operator.Inequality:
2282 case Operator.LeftShift:
2283 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2284 case Operator.LessThan:
2286 case Operator.LessThanOrEqual:
2287 return "LessThanOrEqual";
2288 case Operator.LogicalAnd:
2290 case Operator.LogicalOr:
2292 case Operator.Modulus:
2293 return IsCompound ? "ModuloAssign" : "Modulo";
2294 case Operator.Multiply:
2295 return IsCompound ? "MultiplyAssign" : "Multiply";
2296 case Operator.RightShift:
2297 return IsCompound ? "RightShiftAssign" : "RightShift";
2298 case Operator.Subtraction:
2299 return IsCompound ? "SubtractAssign" : "Subtract";
2301 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2305 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2308 case Operator.Addition:
2309 return CSharp.Operator.OpType.Addition;
2310 case Operator.BitwiseAnd:
2311 case Operator.LogicalAnd:
2312 return CSharp.Operator.OpType.BitwiseAnd;
2313 case Operator.BitwiseOr:
2314 case Operator.LogicalOr:
2315 return CSharp.Operator.OpType.BitwiseOr;
2316 case Operator.Division:
2317 return CSharp.Operator.OpType.Division;
2318 case Operator.Equality:
2319 return CSharp.Operator.OpType.Equality;
2320 case Operator.ExclusiveOr:
2321 return CSharp.Operator.OpType.ExclusiveOr;
2322 case Operator.GreaterThan:
2323 return CSharp.Operator.OpType.GreaterThan;
2324 case Operator.GreaterThanOrEqual:
2325 return CSharp.Operator.OpType.GreaterThanOrEqual;
2326 case Operator.Inequality:
2327 return CSharp.Operator.OpType.Inequality;
2328 case Operator.LeftShift:
2329 return CSharp.Operator.OpType.LeftShift;
2330 case Operator.LessThan:
2331 return CSharp.Operator.OpType.LessThan;
2332 case Operator.LessThanOrEqual:
2333 return CSharp.Operator.OpType.LessThanOrEqual;
2334 case Operator.Modulus:
2335 return CSharp.Operator.OpType.Modulus;
2336 case Operator.Multiply:
2337 return CSharp.Operator.OpType.Multiply;
2338 case Operator.RightShift:
2339 return CSharp.Operator.OpType.RightShift;
2340 case Operator.Subtraction:
2341 return CSharp.Operator.OpType.Subtraction;
2343 throw new InternalErrorException (op.ToString ());
2347 public override bool ContainsEmitWithAwait ()
2349 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2352 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l)
2357 case Operator.Multiply:
2358 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2359 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2360 opcode = OpCodes.Mul_Ovf;
2361 else if (!IsFloat (l))
2362 opcode = OpCodes.Mul_Ovf_Un;
2364 opcode = OpCodes.Mul;
2366 opcode = OpCodes.Mul;
2370 case Operator.Division:
2372 opcode = OpCodes.Div_Un;
2374 opcode = OpCodes.Div;
2377 case Operator.Modulus:
2379 opcode = OpCodes.Rem_Un;
2381 opcode = OpCodes.Rem;
2384 case Operator.Addition:
2385 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2386 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2387 opcode = OpCodes.Add_Ovf;
2388 else if (!IsFloat (l))
2389 opcode = OpCodes.Add_Ovf_Un;
2391 opcode = OpCodes.Add;
2393 opcode = OpCodes.Add;
2396 case Operator.Subtraction:
2397 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2398 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2399 opcode = OpCodes.Sub_Ovf;
2400 else if (!IsFloat (l))
2401 opcode = OpCodes.Sub_Ovf_Un;
2403 opcode = OpCodes.Sub;
2405 opcode = OpCodes.Sub;
2408 case Operator.RightShift:
2410 opcode = OpCodes.Shr_Un;
2412 opcode = OpCodes.Shr;
2415 case Operator.LeftShift:
2416 opcode = OpCodes.Shl;
2419 case Operator.Equality:
2420 opcode = OpCodes.Ceq;
2423 case Operator.Inequality:
2424 ec.Emit (OpCodes.Ceq);
2427 opcode = OpCodes.Ceq;
2430 case Operator.LessThan:
2432 opcode = OpCodes.Clt_Un;
2434 opcode = OpCodes.Clt;
2437 case Operator.GreaterThan:
2439 opcode = OpCodes.Cgt_Un;
2441 opcode = OpCodes.Cgt;
2444 case Operator.LessThanOrEqual:
2445 if (IsUnsigned (l) || IsFloat (l))
2446 ec.Emit (OpCodes.Cgt_Un);
2448 ec.Emit (OpCodes.Cgt);
2451 opcode = OpCodes.Ceq;
2454 case Operator.GreaterThanOrEqual:
2455 if (IsUnsigned (l) || IsFloat (l))
2456 ec.Emit (OpCodes.Clt_Un);
2458 ec.Emit (OpCodes.Clt);
2462 opcode = OpCodes.Ceq;
2465 case Operator.BitwiseOr:
2466 opcode = OpCodes.Or;
2469 case Operator.BitwiseAnd:
2470 opcode = OpCodes.And;
2473 case Operator.ExclusiveOr:
2474 opcode = OpCodes.Xor;
2478 throw new InternalErrorException (oper.ToString ());
2484 static bool IsUnsigned (TypeSpec t)
2486 switch (t.BuiltinType) {
2487 case BuiltinTypeSpec.Type.Char:
2488 case BuiltinTypeSpec.Type.UInt:
2489 case BuiltinTypeSpec.Type.ULong:
2490 case BuiltinTypeSpec.Type.UShort:
2491 case BuiltinTypeSpec.Type.Byte:
2498 static bool IsFloat (TypeSpec t)
2500 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2503 Expression ResolveOperator (ResolveContext ec)
2505 TypeSpec l = left.Type;
2506 TypeSpec r = right.Type;
2508 bool primitives_only = false;
2511 // Handles predefined primitive types
2513 if (BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r)) {
2514 if ((oper & Operator.ShiftMask) == 0) {
2515 if (l.BuiltinType != BuiltinTypeSpec.Type.Bool && !DoBinaryOperatorPromotion (ec))
2518 primitives_only = true;
2522 if (l.IsPointer || r.IsPointer)
2523 return ResolveOperatorPointer (ec, l, r);
2526 bool lenum = l.IsEnum;
2527 bool renum = r.IsEnum;
2528 if (lenum || renum) {
2529 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2536 if ((oper == Operator.Addition || oper == Operator.Subtraction) && (l.IsDelegate || r.IsDelegate)) {
2538 expr = ResolveOperatorDelegate (ec, l, r);
2540 // TODO: Can this be ambiguous
2546 expr = ResolveUserOperator (ec, left, right);
2550 // Predefined reference types equality
2551 if ((oper & Operator.EqualityMask) != 0) {
2552 expr = ResolveOperatorEquality (ec, l, r);
2558 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, primitives_only, null);
2561 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2562 // if 'left' is not an enumeration constant, create one from the type of 'right'
2563 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2566 case Operator.BitwiseOr:
2567 case Operator.BitwiseAnd:
2568 case Operator.ExclusiveOr:
2569 case Operator.Equality:
2570 case Operator.Inequality:
2571 case Operator.LessThan:
2572 case Operator.LessThanOrEqual:
2573 case Operator.GreaterThan:
2574 case Operator.GreaterThanOrEqual:
2575 if (left.Type.IsEnum)
2578 if (left.IsZeroInteger)
2579 return left.TryReduce (ec, right.Type, loc);
2583 case Operator.Addition:
2584 case Operator.Subtraction:
2587 case Operator.Multiply:
2588 case Operator.Division:
2589 case Operator.Modulus:
2590 case Operator.LeftShift:
2591 case Operator.RightShift:
2592 if (right.Type.IsEnum || left.Type.IsEnum)
2601 // The `|' operator used on types which were extended is dangerous
2603 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2605 OpcodeCast lcast = left as OpcodeCast;
2606 if (lcast != null) {
2607 if (IsUnsigned (lcast.UnderlyingType))
2611 OpcodeCast rcast = right as OpcodeCast;
2612 if (rcast != null) {
2613 if (IsUnsigned (rcast.UnderlyingType))
2617 if (lcast == null && rcast == null)
2620 // FIXME: consider constants
2622 ec.Report.Warning (675, 3, loc,
2623 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2624 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2627 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
2629 return new PredefinedOperator[] {
2631 // Pointer arithmetic:
2633 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2634 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2635 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2636 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2638 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
2639 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
2640 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
2641 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
2644 // T* operator + (int y, T* x);
2645 // T* operator + (uint y, T *x);
2646 // T* operator + (long y, T *x);
2647 // T* operator + (ulong y, T *x);
2649 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
2650 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
2651 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
2652 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
2655 // long operator - (T* x, T *y)
2657 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
2661 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
2663 TypeSpec bool_type = types.Bool;
2664 return new PredefinedOperator[] {
2665 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask),
2666 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
2667 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
2668 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
2669 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
2670 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
2671 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
2673 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
2674 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
2675 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
2676 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
2677 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
2678 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
2679 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
2681 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
2682 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
2683 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
2685 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
2687 new PredefinedShiftOperator (types.Int, types.Int, Operator.ShiftMask),
2688 new PredefinedShiftOperator (types.UInt, types.Int, Operator.ShiftMask),
2689 new PredefinedShiftOperator (types.Long, types.Int, Operator.ShiftMask),
2690 new PredefinedShiftOperator (types.ULong, types.Int, Operator.ShiftMask)
2694 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
2696 TypeSpec bool_type = types.Bool;
2698 return new PredefinedOperator[] {
2699 new PredefinedEqualityOperator (types.String, bool_type),
2700 new PredefinedEqualityOperator (types.Delegate, bool_type),
2701 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type)
2706 // Rules used during binary numeric promotion
2708 static bool DoNumericPromotion (ResolveContext rc, ref Expression prim_expr, ref Expression second_expr, TypeSpec type)
2712 Constant c = prim_expr as Constant;
2714 temp = c.ConvertImplicitly (type);
2721 if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
2722 switch (prim_expr.Type.BuiltinType) {
2723 case BuiltinTypeSpec.Type.Int:
2724 case BuiltinTypeSpec.Type.Short:
2725 case BuiltinTypeSpec.Type.SByte:
2726 case BuiltinTypeSpec.Type.Long:
2727 type = rc.BuiltinTypes.Long;
2729 if (type != second_expr.Type) {
2730 c = second_expr as Constant;
2732 temp = c.ConvertImplicitly (type);
2734 temp = Convert.ImplicitNumericConversion (second_expr, type);
2741 } else if (type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
2743 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2745 switch (type.BuiltinType) {
2746 case BuiltinTypeSpec.Type.Int:
2747 case BuiltinTypeSpec.Type.Long:
2748 case BuiltinTypeSpec.Type.Short:
2749 case BuiltinTypeSpec.Type.SByte:
2754 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2763 // 7.2.6.2 Binary numeric promotions
2765 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2767 TypeSpec ltype = left.Type;
2768 TypeSpec rtype = right.Type;
2771 foreach (TypeSpec t in ec.BuiltinTypes.BinaryPromotionsTypes) {
2773 return t == rtype || DoNumericPromotion (ec, ref right, ref left, t);
2776 return t == ltype || DoNumericPromotion (ec, ref left, ref right, t);
2779 TypeSpec int32 = ec.BuiltinTypes.Int;
2780 if (ltype != int32) {
2781 Constant c = left as Constant;
2783 temp = c.ConvertImplicitly (int32);
2785 temp = Convert.ImplicitNumericConversion (left, int32);
2792 if (rtype != int32) {
2793 Constant c = right as Constant;
2795 temp = c.ConvertImplicitly (int32);
2797 temp = Convert.ImplicitNumericConversion (right, int32);
2807 protected override Expression DoResolve (ResolveContext ec)
2812 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2813 left = ((ParenthesizedExpression) left).Expr;
2814 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2818 if (left.eclass == ExprClass.Type) {
2819 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2823 left = left.Resolve (ec);
2828 Constant lc = left as Constant;
2830 if (lc != null && lc.Type.BuiltinType == BuiltinTypeSpec.Type.Bool &&
2831 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2832 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2834 // FIXME: resolve right expression as unreachable
2835 // right.Resolve (ec);
2837 ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2841 right = right.Resolve (ec);
2845 eclass = ExprClass.Value;
2846 Constant rc = right as Constant;
2848 // The conversion rules are ignored in enum context but why
2849 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
2850 lc = EnumLiftUp (ec, lc, rc, loc);
2852 rc = EnumLiftUp (ec, rc, lc, loc);
2855 if (rc != null && lc != null) {
2856 int prev_e = ec.Report.Errors;
2857 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
2858 if (e != null || ec.Report.Errors != prev_e)
2862 // Comparison warnings
2863 if ((oper & Operator.ComparisonMask) != 0) {
2864 if (left.Equals (right)) {
2865 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2867 CheckOutOfRangeComparison (ec, lc, right.Type);
2868 CheckOutOfRangeComparison (ec, rc, left.Type);
2871 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2873 var rt = right.Type;
2874 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
2875 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
2876 Error_OperatorCannotBeApplied (ec, left, right);
2883 // Special handling for logical boolean operators which require rhs not to be
2884 // evaluated based on lhs value
2886 if ((oper & Operator.LogicalMask) != 0) {
2887 Expression cond_left, cond_right, expr;
2889 args = new Arguments (2);
2891 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2892 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, ec.CurrentBlock, loc);
2894 var cond_args = new Arguments (1);
2895 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left).Resolve (ec)));
2898 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
2899 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
2901 left = temp.CreateReferenceExpression (ec, loc);
2902 if (oper == Operator.LogicalAnd) {
2903 expr = DynamicUnaryConversion.CreateIsFalse (ec, cond_args, loc);
2906 expr = DynamicUnaryConversion.CreateIsTrue (ec, cond_args, loc);
2910 args.Add (new Argument (left));
2911 args.Add (new Argument (right));
2912 cond_right = new DynamicExpressionStatement (this, args, loc);
2914 LocalVariable temp = LocalVariable.CreateCompilerGenerated (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
2916 args.Add (new Argument (temp.CreateReferenceExpression (ec, loc).Resolve (ec)));
2917 args.Add (new Argument (right));
2918 right = new DynamicExpressionStatement (this, args, loc);
2921 // bool && dynamic => (temp = left) ? temp && right : temp;
2922 // bool || dynamic => (temp = left) ? temp : temp || right;
2924 if (oper == Operator.LogicalAnd) {
2926 cond_right = temp.CreateReferenceExpression (ec, loc);
2928 cond_left = temp.CreateReferenceExpression (ec, loc);
2932 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left));
2935 return new Conditional (expr, cond_left, cond_right, loc).Resolve (ec);
2938 args = new Arguments (2);
2939 args.Add (new Argument (left));
2940 args.Add (new Argument (right));
2941 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
2944 if (ec.Module.Compiler.Settings.Version >= LanguageVersion.ISO_2 &&
2945 ((left.Type.IsNullableType && (right is NullLiteral || right.Type.IsNullableType || TypeSpec.IsValueType (right.Type))) ||
2946 (TypeSpec.IsValueType (left.Type) && right is NullLiteral) ||
2947 (right.Type.IsNullableType && (left is NullLiteral || left.Type.IsNullableType || TypeSpec.IsValueType (left.Type))) ||
2948 (TypeSpec.IsValueType (right.Type) && left is NullLiteral))) {
2949 var lifted = new Nullable.LiftedBinaryOperator (oper, left, right, loc);
2950 lifted.state = state;
2951 return lifted.Resolve (ec);
2954 return DoResolveCore (ec, left, right);
2957 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
2959 Expression expr = ResolveOperator (ec);
2961 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
2963 if (left == null || right == null)
2964 throw new InternalErrorException ("Invalid conversion");
2966 if (oper == Operator.BitwiseOr)
2967 CheckBitwiseOrOnSignExtended (ec);
2972 public override SLE.Expression MakeExpression (BuilderContext ctx)
2974 var le = left.MakeExpression (ctx);
2975 var re = right.MakeExpression (ctx);
2976 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
2979 case Operator.Addition:
2980 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
2981 case Operator.BitwiseAnd:
2982 return SLE.Expression.And (le, re);
2983 case Operator.BitwiseOr:
2984 return SLE.Expression.Or (le, re);
2985 case Operator.Division:
2986 return SLE.Expression.Divide (le, re);
2987 case Operator.Equality:
2988 return SLE.Expression.Equal (le, re);
2989 case Operator.ExclusiveOr:
2990 return SLE.Expression.ExclusiveOr (le, re);
2991 case Operator.GreaterThan:
2992 return SLE.Expression.GreaterThan (le, re);
2993 case Operator.GreaterThanOrEqual:
2994 return SLE.Expression.GreaterThanOrEqual (le, re);
2995 case Operator.Inequality:
2996 return SLE.Expression.NotEqual (le, re);
2997 case Operator.LeftShift:
2998 return SLE.Expression.LeftShift (le, re);
2999 case Operator.LessThan:
3000 return SLE.Expression.LessThan (le, re);
3001 case Operator.LessThanOrEqual:
3002 return SLE.Expression.LessThanOrEqual (le, re);
3003 case Operator.LogicalAnd:
3004 return SLE.Expression.AndAlso (le, re);
3005 case Operator.LogicalOr:
3006 return SLE.Expression.OrElse (le, re);
3007 case Operator.Modulus:
3008 return SLE.Expression.Modulo (le, re);
3009 case Operator.Multiply:
3010 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3011 case Operator.RightShift:
3012 return SLE.Expression.RightShift (le, re);
3013 case Operator.Subtraction:
3014 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3016 throw new NotImplementedException (oper.ToString ());
3021 // D operator + (D x, D y)
3022 // D operator - (D x, D y)
3024 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3026 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3028 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3029 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3034 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3035 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3045 MethodSpec method = null;
3046 Arguments args = new Arguments (2);
3047 args.Add (new Argument (left));
3048 args.Add (new Argument (right));
3050 if (oper == Operator.Addition) {
3051 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3052 } else if (oper == Operator.Subtraction) {
3053 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3057 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3059 MethodGroupExpr mg = MethodGroupExpr.CreatePredefined (method, ec.BuiltinTypes.Delegate, loc);
3060 Expression expr = new UserOperatorCall (mg.BestCandidate, args, CreateExpressionTree, loc);
3061 return new ClassCast (expr, l);
3065 // Enumeration operators
3067 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3070 // bool operator == (E x, E y);
3071 // bool operator != (E x, E y);
3072 // bool operator < (E x, E y);
3073 // bool operator > (E x, E y);
3074 // bool operator <= (E x, E y);
3075 // bool operator >= (E x, E y);
3077 // E operator & (E x, E y);
3078 // E operator | (E x, E y);
3079 // E operator ^ (E x, E y);
3081 // U operator - (E e, E f)
3082 // E operator - (E e, U x)
3083 // E operator - (U x, E e) // LAMESPEC: Not covered by the specification
3085 // E operator + (E e, U x)
3086 // E operator + (U x, E e)
3088 Expression ltemp = left;
3089 Expression rtemp = right;
3090 TypeSpec underlying_type;
3091 TypeSpec underlying_type_result;
3096 // LAMESPEC: There is never ambiguous conversion between enum operators
3097 // the one which contains more enum parameters always wins even if there
3098 // is an implicit conversion involved
3100 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3102 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3103 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
3110 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3111 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
3121 if ((oper & Operator.BitwiseMask) != 0) {
3123 underlying_type_result = underlying_type;
3126 underlying_type_result = null;
3128 } else if (oper == Operator.Subtraction) {
3130 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3131 if (ltype != rtype) {
3132 expr = Convert.ImplicitConversion (ec, left, rtype, left.Location);
3134 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3140 res_type = underlying_type;
3145 res_type = underlying_type;
3148 underlying_type_result = underlying_type;
3150 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3151 expr = Convert.ImplicitConversion (ec, right, ltype, right.Location);
3152 if (expr == null || expr is EnumConstant) {
3153 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3159 res_type = underlying_type;
3163 underlying_type_result = underlying_type;
3167 } else if (oper == Operator.Addition) {
3169 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3172 if (rtype != underlying_type && (state & (State.RightNullLifted | State.LeftNullLifted)) == 0) {
3173 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3180 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3182 if (ltype != underlying_type) {
3183 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3191 underlying_type_result = underlying_type;
3196 // Unwrap the constant correctly, so DoBinaryOperatorPromotion can do the magic
3197 // with constants and expressions
3198 if (left.Type != underlying_type) {
3199 if (left is Constant)
3200 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
3202 left = EmptyCast.Create (left, underlying_type);
3205 if (right.Type != underlying_type) {
3206 if (right is Constant)
3207 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
3209 right = EmptyCast.Create (right, underlying_type);
3213 // C# specification uses explicit cast syntax which means binary promotion
3214 // should happen, however it seems that csc does not do that
3216 if (!DoBinaryOperatorPromotion (ec)) {
3222 if (underlying_type_result != null && left.Type != underlying_type_result) {
3223 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (left.Type), underlying_type_result);
3226 expr = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, true, res_type);
3238 // If the return type of the selected operator is implicitly convertible to the type of x
3240 if (Convert.ImplicitConversionExists (ec, expr, ltype))
3244 // Otherwise, if the selected operator is a predefined operator, if the return type of the
3245 // selected operator is explicitly convertible to the type of x, and if y is implicitly
3246 // convertible to the type of x or the operator is a shift operator, then the operation
3247 // is evaluated as x = (T)(x op y), where T is the type of x
3249 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
3253 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
3260 // 7.9.6 Reference type equality operators
3262 Expression ResolveOperatorEquality (ResolveContext ec, TypeSpec l, TypeSpec r)
3265 type = ec.BuiltinTypes.Bool;
3268 // a, Both operands are reference-type values or the value null
3269 // b, One operand is a value of type T where T is a type-parameter and
3270 // the other operand is the value null. Furthermore T does not have the
3271 // value type constraint
3273 // LAMESPEC: Very confusing details in the specification, basically any
3274 // reference like type-parameter is allowed
3276 var tparam_l = l as TypeParameterSpec;
3277 var tparam_r = r as TypeParameterSpec;
3278 if (tparam_l != null) {
3279 if (right is NullLiteral && !tparam_l.HasSpecialStruct) {
3280 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3284 if (!tparam_l.IsReferenceType)
3287 l = tparam_l.GetEffectiveBase ();
3288 left = new BoxedCast (left, l);
3289 } else if (left is NullLiteral && tparam_r == null) {
3290 if (!TypeSpec.IsReferenceType (r) || r.Kind == MemberKind.InternalCompilerType)
3296 if (tparam_r != null) {
3297 if (left is NullLiteral && !tparam_r.HasSpecialStruct) {
3298 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3302 if (!tparam_r.IsReferenceType)
3305 r = tparam_r.GetEffectiveBase ();
3306 right = new BoxedCast (right, r);
3307 } else if (right is NullLiteral) {
3308 if (!TypeSpec.IsReferenceType (l) || l.Kind == MemberKind.InternalCompilerType)
3315 // LAMESPEC: method groups can be compared when they convert to other side delegate
3318 if (right.eclass == ExprClass.MethodGroup) {
3319 result = Convert.ImplicitConversion (ec, right, l, loc);
3325 } else if (r.IsDelegate && l != r) {
3328 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3329 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3338 // bool operator != (string a, string b)
3339 // bool operator == (string a, string b)
3341 // bool operator != (Delegate a, Delegate b)
3342 // bool operator == (Delegate a, Delegate b)
3344 // bool operator != (bool a, bool b)
3345 // bool operator == (bool a, bool b)
3347 // LAMESPEC: Reference equality comparison can apply to value types when
3348 // they implement an implicit conversion to any of types above.
3350 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3351 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, false, null);
3357 // bool operator != (object a, object b)
3358 // bool operator == (object a, object b)
3360 // An explicit reference conversion exists from the
3361 // type of either operand to the type of the other operand.
3364 // Optimize common path
3366 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3369 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3370 !Convert.ExplicitReferenceConversionExists (r, l))
3373 // Reject allowed explicit conversions like int->object
3374 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
3377 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3378 ec.Report.Warning (253, 2, loc,
3379 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3380 l.GetSignatureForError ());
3382 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3383 ec.Report.Warning (252, 2, loc,
3384 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3385 r.GetSignatureForError ());
3391 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3394 // bool operator == (void* x, void* y);
3395 // bool operator != (void* x, void* y);
3396 // bool operator < (void* x, void* y);
3397 // bool operator > (void* x, void* y);
3398 // bool operator <= (void* x, void* y);
3399 // bool operator >= (void* x, void* y);
3401 if ((oper & Operator.ComparisonMask) != 0) {
3404 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3411 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3417 type = ec.BuiltinTypes.Bool;
3421 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false, null);
3425 // Build-in operators method overloading
3427 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, TypeSpec enum_type)
3429 PredefinedOperator best_operator = null;
3430 TypeSpec l = left.Type;
3431 TypeSpec r = right.Type;
3432 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3434 foreach (PredefinedOperator po in operators) {
3435 if ((po.OperatorsMask & oper_mask) == 0)
3438 if (primitives_only) {
3439 if (!po.IsPrimitiveApplicable (l, r))
3442 if (!po.IsApplicable (ec, left, right))
3446 if (best_operator == null) {
3448 if (primitives_only)
3454 best_operator = po.ResolveBetterOperator (ec, best_operator);
3456 if (best_operator == null) {
3457 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3458 OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
3465 if (best_operator == null)
3468 Expression expr = best_operator.ConvertResult (ec, this);
3471 // Optimize &/&& constant expressions with 0 value
3473 if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
3474 Constant rc = right as Constant;
3475 Constant lc = left as Constant;
3476 if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
3478 // The result is a constant with side-effect
3480 Constant side_effect = rc == null ?
3481 new SideEffectConstant (lc, right, loc) :
3482 new SideEffectConstant (rc, left, loc);
3484 return ReducedExpression.Create (side_effect, expr);
3488 if (enum_type == null)
3492 // HACK: required by enum_conversion
3494 expr.Type = enum_type;
3495 return EmptyCast.Create (expr, enum_type);
3499 // Performs user-operator overloading
3501 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression left, Expression right)
3503 var op = ConvertBinaryToUserOperator (oper);
3505 if (l.IsNullableType)
3506 l = Nullable.NullableInfo.GetUnderlyingType (l);
3508 if (r.IsNullableType)
3509 r = Nullable.NullableInfo.GetUnderlyingType (r);
3511 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
3512 IList<MemberSpec> right_operators = null;
3515 right_operators = MemberCache.GetUserOperator (r, op, false);
3516 if (right_operators == null && left_operators == null)
3518 } else if (left_operators == null) {
3522 Arguments args = new Arguments (2);
3523 Argument larg = new Argument (left);
3525 Argument rarg = new Argument (right);
3529 // User-defined operator implementations always take precedence
3530 // over predefined operator implementations
3532 if (left_operators != null && right_operators != null) {
3533 left_operators = CombineUserOperators (left_operators, right_operators);
3534 } else if (right_operators != null) {
3535 left_operators = right_operators;
3538 var res = new OverloadResolver (left_operators, OverloadResolver.Restrictions.ProbingOnly |
3539 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded, loc);
3541 var oper_method = res.ResolveOperator (ec, ref args);
3542 if (oper_method == null)
3545 var llifted = (state & State.LeftNullLifted) != 0;
3546 var rlifted = (state & State.RightNullLifted) != 0;
3547 if ((Oper & Operator.EqualityMask) != 0) {
3548 var parameters = oper_method.Parameters;
3549 // LAMESPEC: No idea why this is not allowed
3550 if ((left is Nullable.Unwrap || right is Nullable.Unwrap) && parameters.Types [0] != parameters.Types [1])
3553 // Binary operation was lifted but we have found a user operator
3554 // which requires value-type argument, we downgrade ourself back to
3556 // LAMESPEC: The user operator is not called (it cannot be we are passing null to struct)
3557 // but compilation succeeds
3558 if ((llifted && !parameters.Types[0].IsStruct) || (rlifted && !parameters.Types[1].IsStruct)) {
3559 state &= ~(State.LeftNullLifted | State.RightNullLifted);
3563 Expression oper_expr;
3565 // TODO: CreateExpressionTree is allocated every time
3566 if ((oper & Operator.LogicalMask) != 0) {
3567 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
3568 oper == Operator.LogicalAnd, loc).Resolve (ec);
3570 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
3574 this.left = larg.Expr;
3577 this.right = rarg.Expr;
3583 // Merge two sets of user operators into one, they are mostly distinguish
3584 // expect when they share base type and it contains an operator
3586 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
3588 var combined = new List<MemberSpec> (left.Count + right.Count);
3589 combined.AddRange (left);
3590 foreach (var r in right) {
3592 foreach (var l in left) {
3593 if (l.DeclaringType == r.DeclaringType) {
3606 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
3608 if (c is IntegralConstant || c is CharConstant) {
3610 c.ConvertExplicitly (true, type);
3611 } catch (OverflowException) {
3612 ec.Report.Warning (652, 2, loc,
3613 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
3614 TypeManager.CSharpName (type));
3620 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3621 /// context of a conditional bool expression. This function will return
3622 /// false if it is was possible to use EmitBranchable, or true if it was.
3624 /// The expression's code is generated, and we will generate a branch to `target'
3625 /// if the resulting expression value is equal to isTrue
3627 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3630 // This is more complicated than it looks, but its just to avoid
3631 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3632 // but on top of that we want for == and != to use a special path
3633 // if we are comparing against null
3635 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
3636 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3639 // put the constant on the rhs, for simplicity
3641 if (left is Constant) {
3642 Expression swap = right;
3648 // brtrue/brfalse works with native int only
3650 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
3651 left.EmitBranchable (ec, target, my_on_true);
3654 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
3655 // right is a boolean, and it's not 'false' => it is 'true'
3656 left.EmitBranchable (ec, target, !my_on_true);
3660 } else if (oper == Operator.LogicalAnd) {
3663 Label tests_end = ec.DefineLabel ();
3665 left.EmitBranchable (ec, tests_end, false);
3666 right.EmitBranchable (ec, target, true);
3667 ec.MarkLabel (tests_end);
3670 // This optimizes code like this
3671 // if (true && i > 4)
3673 if (!(left is Constant))
3674 left.EmitBranchable (ec, target, false);
3676 if (!(right is Constant))
3677 right.EmitBranchable (ec, target, false);
3682 } else if (oper == Operator.LogicalOr){
3684 left.EmitBranchable (ec, target, true);
3685 right.EmitBranchable (ec, target, true);
3688 Label tests_end = ec.DefineLabel ();
3689 left.EmitBranchable (ec, tests_end, true);
3690 right.EmitBranchable (ec, target, false);
3691 ec.MarkLabel (tests_end);
3696 } else if ((oper & Operator.ComparisonMask) == 0) {
3697 base.EmitBranchable (ec, target, on_true);
3704 TypeSpec t = left.Type;
3705 bool is_float = IsFloat (t);
3706 bool is_unsigned = is_float || IsUnsigned (t);
3709 case Operator.Equality:
3711 ec.Emit (OpCodes.Beq, target);
3713 ec.Emit (OpCodes.Bne_Un, target);
3716 case Operator.Inequality:
3718 ec.Emit (OpCodes.Bne_Un, target);
3720 ec.Emit (OpCodes.Beq, target);
3723 case Operator.LessThan:
3725 if (is_unsigned && !is_float)
3726 ec.Emit (OpCodes.Blt_Un, target);
3728 ec.Emit (OpCodes.Blt, target);
3731 ec.Emit (OpCodes.Bge_Un, target);
3733 ec.Emit (OpCodes.Bge, target);
3736 case Operator.GreaterThan:
3738 if (is_unsigned && !is_float)
3739 ec.Emit (OpCodes.Bgt_Un, target);
3741 ec.Emit (OpCodes.Bgt, target);
3744 ec.Emit (OpCodes.Ble_Un, target);
3746 ec.Emit (OpCodes.Ble, target);
3749 case Operator.LessThanOrEqual:
3751 if (is_unsigned && !is_float)
3752 ec.Emit (OpCodes.Ble_Un, target);
3754 ec.Emit (OpCodes.Ble, target);
3757 ec.Emit (OpCodes.Bgt_Un, target);
3759 ec.Emit (OpCodes.Bgt, target);
3763 case Operator.GreaterThanOrEqual:
3765 if (is_unsigned && !is_float)
3766 ec.Emit (OpCodes.Bge_Un, target);
3768 ec.Emit (OpCodes.Bge, target);
3771 ec.Emit (OpCodes.Blt_Un, target);
3773 ec.Emit (OpCodes.Blt, target);
3776 throw new InternalErrorException (oper.ToString ());
3780 public override void Emit (EmitContext ec)
3782 EmitOperator (ec, left.Type);
3785 protected virtual void EmitOperator (EmitContext ec, TypeSpec l)
3787 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
3788 left = left.EmitToField (ec);
3790 if ((oper & Operator.LogicalMask) == 0) {
3791 right = right.EmitToField (ec);
3796 // Handle short-circuit operators differently
3799 if ((oper & Operator.LogicalMask) != 0) {
3800 Label load_result = ec.DefineLabel ();
3801 Label end = ec.DefineLabel ();
3803 bool is_or = oper == Operator.LogicalOr;
3804 left.EmitBranchable (ec, load_result, is_or);
3806 ec.Emit (OpCodes.Br_S, end);
3808 ec.MarkLabel (load_result);
3809 ec.EmitInt (is_or ? 1 : 0);
3815 // Optimize zero-based operations which cannot be optimized at expression level
3817 if (oper == Operator.Subtraction) {
3818 var lc = left as IntegralConstant;
3819 if (lc != null && lc.IsDefaultValue) {
3821 ec.Emit (OpCodes.Neg);
3828 EmitOperatorOpcode (ec, oper, l);
3831 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3832 // expression because that would wrap lifted binary operation
3834 if (enum_conversion != null)
3835 enum_conversion.Emit (ec);
3838 public override void EmitSideEffect (EmitContext ec)
3840 if ((oper & Operator.LogicalMask) != 0 ||
3841 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3842 base.EmitSideEffect (ec);
3844 left.EmitSideEffect (ec);
3845 right.EmitSideEffect (ec);
3849 protected override void CloneTo (CloneContext clonectx, Expression t)
3851 Binary target = (Binary) t;
3853 target.left = left.Clone (clonectx);
3854 target.right = right.Clone (clonectx);
3857 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3859 Arguments binder_args = new Arguments (4);
3861 MemberAccess sle = new MemberAccess (new MemberAccess (
3862 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3864 CSharpBinderFlags flags = 0;
3865 if (ec.HasSet (ResolveContext.Options.CheckedScope))
3866 flags = CSharpBinderFlags.CheckedContext;
3868 if ((oper & Operator.LogicalMask) != 0)
3869 flags |= CSharpBinderFlags.BinaryOperationLogical;
3871 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
3872 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3873 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
3874 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
3876 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
3879 public override Expression CreateExpressionTree (ResolveContext ec)
3881 return CreateExpressionTree (ec, null);
3884 Expression CreateExpressionTree (ResolveContext ec, Expression method)
3887 bool lift_arg = false;
3890 case Operator.Addition:
3891 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3892 method_name = "AddChecked";
3894 method_name = "Add";
3896 case Operator.BitwiseAnd:
3897 method_name = "And";
3899 case Operator.BitwiseOr:
3902 case Operator.Division:
3903 method_name = "Divide";
3905 case Operator.Equality:
3906 method_name = "Equal";
3909 case Operator.ExclusiveOr:
3910 method_name = "ExclusiveOr";
3912 case Operator.GreaterThan:
3913 method_name = "GreaterThan";
3916 case Operator.GreaterThanOrEqual:
3917 method_name = "GreaterThanOrEqual";
3920 case Operator.Inequality:
3921 method_name = "NotEqual";
3924 case Operator.LeftShift:
3925 method_name = "LeftShift";
3927 case Operator.LessThan:
3928 method_name = "LessThan";
3931 case Operator.LessThanOrEqual:
3932 method_name = "LessThanOrEqual";
3935 case Operator.LogicalAnd:
3936 method_name = "AndAlso";
3938 case Operator.LogicalOr:
3939 method_name = "OrElse";
3941 case Operator.Modulus:
3942 method_name = "Modulo";
3944 case Operator.Multiply:
3945 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3946 method_name = "MultiplyChecked";
3948 method_name = "Multiply";
3950 case Operator.RightShift:
3951 method_name = "RightShift";
3953 case Operator.Subtraction:
3954 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3955 method_name = "SubtractChecked";
3957 method_name = "Subtract";
3961 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3964 Arguments args = new Arguments (2);
3965 args.Add (new Argument (left.CreateExpressionTree (ec)));
3966 args.Add (new Argument (right.CreateExpressionTree (ec)));
3967 if (method != null) {
3969 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
3971 args.Add (new Argument (method));
3974 return CreateExpressionFactoryCall (ec, method_name, args);
3979 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3980 // b, c, d... may be strings or objects.
3982 public class StringConcat : Expression
3984 Arguments arguments;
3986 StringConcat (Location loc)
3989 arguments = new Arguments (2);
3992 public override bool ContainsEmitWithAwait ()
3994 return arguments.ContainsEmitWithAwait ();
3997 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
3999 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4000 throw new ArgumentException ();
4002 var s = new StringConcat (loc);
4003 s.type = rc.BuiltinTypes.String;
4004 s.eclass = ExprClass.Value;
4006 s.Append (rc, left);
4007 s.Append (rc, right);
4011 public override Expression CreateExpressionTree (ResolveContext ec)
4013 Argument arg = arguments [0];
4014 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4018 // Creates nested calls tree from an array of arguments used for IL emit
4020 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4022 Arguments concat_args = new Arguments (2);
4023 Arguments add_args = new Arguments (3);
4025 concat_args.Add (left);
4026 add_args.Add (new Argument (left_etree));
4028 concat_args.Add (arguments [pos]);
4029 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4031 var methods = GetConcatMethodCandidates ();
4032 if (methods == null)
4035 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4036 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4040 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4042 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4043 if (++pos == arguments.Count)
4046 left = new Argument (new EmptyExpression (method.ReturnType));
4047 return CreateExpressionAddCall (ec, left, expr, pos);
4050 protected override Expression DoResolve (ResolveContext ec)
4055 void Append (ResolveContext rc, Expression operand)
4060 StringConstant sc = operand as StringConstant;
4062 if (arguments.Count != 0) {
4063 Argument last_argument = arguments [arguments.Count - 1];
4064 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4065 if (last_expr_constant != null) {
4066 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4072 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4074 StringConcat concat_oper = operand as StringConcat;
4075 if (concat_oper != null) {
4076 arguments.AddRange (concat_oper.arguments);
4081 arguments.Add (new Argument (operand));
4084 IList<MemberSpec> GetConcatMethodCandidates ()
4086 return MemberCache.FindMembers (type, "Concat", true);
4089 public override void Emit (EmitContext ec)
4091 var members = GetConcatMethodCandidates ();
4092 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4093 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4094 if (method != null) {
4095 var call = new CallEmitter ();
4096 call.EmitPredefined (ec, method, arguments);
4100 public override SLE.Expression MakeExpression (BuilderContext ctx)
4102 if (arguments.Count != 2)
4103 throw new NotImplementedException ("arguments.Count != 2");
4105 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4106 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4111 // User-defined conditional logical operator
4113 public class ConditionalLogicalOperator : UserOperatorCall
4115 readonly bool is_and;
4116 Expression oper_expr;
4118 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4119 : base (oper, arguments, expr_tree, loc)
4121 this.is_and = is_and;
4122 eclass = ExprClass.Unresolved;
4125 protected override Expression DoResolve (ResolveContext ec)
4127 AParametersCollection pd = oper.Parameters;
4128 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4129 ec.Report.Error (217, loc,
4130 "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",
4131 oper.GetSignatureForError ());
4135 Expression left_dup = new EmptyExpression (type);
4136 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4137 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4138 if (op_true == null || op_false == null) {
4139 ec.Report.Error (218, loc,
4140 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4141 TypeManager.CSharpName (type), oper.GetSignatureForError ());
4145 oper_expr = is_and ? op_false : op_true;
4146 eclass = ExprClass.Value;
4150 public override void Emit (EmitContext ec)
4152 Label end_target = ec.DefineLabel ();
4155 // Emit and duplicate left argument
4157 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
4158 if (right_contains_await) {
4159 arguments[0] = arguments[0].EmitToField (ec);
4160 arguments[0].Expr.Emit (ec);
4162 arguments[0].Expr.Emit (ec);
4163 ec.Emit (OpCodes.Dup);
4164 arguments.RemoveAt (0);
4167 oper_expr.EmitBranchable (ec, end_target, true);
4171 if (right_contains_await) {
4173 // Special handling when right expression contains await and left argument
4174 // could not be left on stack before logical branch
4176 Label skip_left_load = ec.DefineLabel ();
4177 ec.Emit (OpCodes.Br_S, skip_left_load);
4178 ec.MarkLabel (end_target);
4179 arguments[0].Expr.Emit (ec);
4180 ec.MarkLabel (skip_left_load);
4182 ec.MarkLabel (end_target);
4187 public class PointerArithmetic : Expression {
4188 Expression left, right;
4192 // We assume that `l' is always a pointer
4194 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4203 public override bool ContainsEmitWithAwait ()
4205 throw new NotImplementedException ();
4208 public override Expression CreateExpressionTree (ResolveContext ec)
4210 Error_PointerInsideExpressionTree (ec);
4214 protected override Expression DoResolve (ResolveContext ec)
4216 eclass = ExprClass.Variable;
4218 var pc = left.Type as PointerContainer;
4219 if (pc != null && pc.Element.Kind == MemberKind.Void) {
4220 Error_VoidPointerOperation (ec);
4227 public override void Emit (EmitContext ec)
4229 TypeSpec op_type = left.Type;
4231 // It must be either array or fixed buffer
4233 if (TypeManager.HasElementType (op_type)) {
4234 element = TypeManager.GetElementType (op_type);
4236 FieldExpr fe = left as FieldExpr;
4238 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
4243 int size = BuiltinTypeSpec.GetSize(element);
4244 TypeSpec rtype = right.Type;
4246 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4248 // handle (pointer - pointer)
4252 ec.Emit (OpCodes.Sub);
4256 ec.Emit (OpCodes.Sizeof, element);
4259 ec.Emit (OpCodes.Div);
4261 ec.Emit (OpCodes.Conv_I8);
4264 // handle + and - on (pointer op int)
4266 Constant left_const = left as Constant;
4267 if (left_const != null) {
4269 // Optimize ((T*)null) pointer operations
4271 if (left_const.IsDefaultValue) {
4272 left = EmptyExpression.Null;
4280 var right_const = right as Constant;
4281 if (right_const != null) {
4283 // Optimize 0-based arithmetic
4285 if (right_const.IsDefaultValue)
4289 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
4291 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
4293 // TODO: Should be the checks resolve context sensitive?
4294 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
4295 right = new Binary (Binary.Operator.Multiply, right, right_const, loc).Resolve (rc);
4301 switch (rtype.BuiltinType) {
4302 case BuiltinTypeSpec.Type.SByte:
4303 case BuiltinTypeSpec.Type.Byte:
4304 case BuiltinTypeSpec.Type.Short:
4305 case BuiltinTypeSpec.Type.UShort:
4306 ec.Emit (OpCodes.Conv_I);
4308 case BuiltinTypeSpec.Type.UInt:
4309 ec.Emit (OpCodes.Conv_U);
4313 if (right_const == null && size != 1){
4315 ec.Emit (OpCodes.Sizeof, element);
4318 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4319 ec.Emit (OpCodes.Conv_I8);
4321 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4324 if (left_const == null) {
4325 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
4326 ec.Emit (OpCodes.Conv_I);
4327 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4328 ec.Emit (OpCodes.Conv_U);
4330 Binary.EmitOperatorOpcode (ec, op, op_type);
4337 // A boolean-expression is an expression that yields a result
4340 public class BooleanExpression : ShimExpression
4342 public BooleanExpression (Expression expr)
4345 this.loc = expr.Location;
4348 public override Expression CreateExpressionTree (ResolveContext ec)
4350 // TODO: We should emit IsTrue (v4) instead of direct user operator
4351 // call but that would break csc compatibility
4352 return base.CreateExpressionTree (ec);
4355 protected override Expression DoResolve (ResolveContext ec)
4357 // A boolean-expression is required to be of a type
4358 // that can be implicitly converted to bool or of
4359 // a type that implements operator true
4361 expr = expr.Resolve (ec);
4365 Assign ass = expr as Assign;
4366 if (ass != null && ass.Source is Constant) {
4367 ec.Report.Warning (665, 3, loc,
4368 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4371 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
4374 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4375 Arguments args = new Arguments (1);
4376 args.Add (new Argument (expr));
4377 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
4380 type = ec.BuiltinTypes.Bool;
4381 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4382 if (converted != null)
4386 // If no implicit conversion to bool exists, try using `operator true'
4388 converted = GetOperatorTrue (ec, expr, loc);
4389 if (converted == null) {
4390 expr.Error_ValueCannotBeConverted (ec, loc, type, false);
4398 public class BooleanExpressionFalse : Unary
4400 public BooleanExpressionFalse (Expression expr)
4401 : base (Operator.LogicalNot, expr, expr.Location)
4405 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
4407 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
4412 /// Implements the ternary conditional operator (?:)
4414 public class Conditional : Expression {
4415 Expression expr, true_expr, false_expr;
4417 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
4420 this.true_expr = true_expr;
4421 this.false_expr = false_expr;
4427 public Expression Expr {
4433 public Expression TrueExpr {
4439 public Expression FalseExpr {
4447 public override bool ContainsEmitWithAwait ()
4449 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
4452 public override Expression CreateExpressionTree (ResolveContext ec)
4454 Arguments args = new Arguments (3);
4455 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4456 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4457 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4458 return CreateExpressionFactoryCall (ec, "Condition", args);
4461 protected override Expression DoResolve (ResolveContext ec)
4463 expr = expr.Resolve (ec);
4466 // Unreachable code needs different resolve path. For instance for await
4467 // expression to not generate unreachable resumable statement
4469 Constant c = expr as Constant;
4470 if (c != null && ec.CurrentBranching != null) {
4471 bool unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
4473 if (c.IsDefaultValue) {
4474 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
4475 true_expr = true_expr.Resolve (ec);
4476 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
4478 false_expr = false_expr.Resolve (ec);
4480 true_expr = true_expr.Resolve (ec);
4482 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
4483 false_expr = false_expr.Resolve (ec);
4484 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
4487 true_expr = true_expr.Resolve (ec);
4488 false_expr = false_expr.Resolve (ec);
4491 if (true_expr == null || false_expr == null || expr == null)
4494 eclass = ExprClass.Value;
4495 TypeSpec true_type = true_expr.Type;
4496 TypeSpec false_type = false_expr.Type;
4500 // First, if an implicit conversion exists from true_expr
4501 // to false_expr, then the result type is of type false_expr.Type
4503 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
4504 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4505 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
4507 // Check if both can convert implicitly to each other's type
4511 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic && Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
4512 ec.Report.Error (172, true_expr.Location,
4513 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
4514 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
4519 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4522 ec.Report.Error (173, true_expr.Location,
4523 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4524 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4530 bool is_false = c.IsDefaultValue;
4533 // Don't issue the warning for constant expressions
4535 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
4536 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location,
4537 "Unreachable expression code detected");
4540 return ReducedExpression.Create (
4541 is_false ? false_expr : true_expr, this,
4542 false_expr is Constant && true_expr is Constant).Resolve (ec);
4548 public override void Emit (EmitContext ec)
4550 Label false_target = ec.DefineLabel ();
4551 Label end_target = ec.DefineLabel ();
4553 expr.EmitBranchable (ec, false_target, false);
4554 true_expr.Emit (ec);
4556 ec.Emit (OpCodes.Br, end_target);
4557 ec.MarkLabel (false_target);
4558 false_expr.Emit (ec);
4559 ec.MarkLabel (end_target);
4562 protected override void CloneTo (CloneContext clonectx, Expression t)
4564 Conditional target = (Conditional) t;
4566 target.expr = expr.Clone (clonectx);
4567 target.true_expr = true_expr.Clone (clonectx);
4568 target.false_expr = false_expr.Clone (clonectx);
4572 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
4574 LocalTemporary temp;
4577 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4578 public abstract void SetHasAddressTaken ();
4579 public abstract void VerifyAssigned (ResolveContext rc);
4581 public abstract bool IsLockedByStatement { get; set; }
4583 public abstract bool IsFixed { get; }
4584 public abstract bool IsRef { get; }
4585 public abstract string Name { get; }
4588 // Variable IL data, it has to be protected to encapsulate hoisted variables
4590 protected abstract ILocalVariable Variable { get; }
4593 // Variable flow-analysis data
4595 public abstract VariableInfo VariableInfo { get; }
4598 public virtual void AddressOf (EmitContext ec, AddressOp mode)
4600 HoistedVariable hv = GetHoistedVariable (ec);
4602 hv.AddressOf (ec, mode);
4606 Variable.EmitAddressOf (ec);
4609 public override bool ContainsEmitWithAwait ()
4614 public override Expression CreateExpressionTree (ResolveContext ec)
4616 HoistedVariable hv = GetHoistedVariable (ec);
4618 return hv.CreateExpressionTree ();
4620 Arguments arg = new Arguments (1);
4621 arg.Add (new Argument (this));
4622 return CreateExpressionFactoryCall (ec, "Constant", arg);
4625 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
4627 if (IsLockedByStatement) {
4628 rc.Report.Warning (728, 2, loc,
4629 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
4636 public override void Emit (EmitContext ec)
4641 public override void EmitSideEffect (EmitContext ec)
4647 // This method is used by parameters that are references, that are
4648 // being passed as references: we only want to pass the pointer (that
4649 // is already stored in the parameter, not the address of the pointer,
4650 // and not the value of the variable).
4652 public void EmitLoad (EmitContext ec)
4657 public void Emit (EmitContext ec, bool leave_copy)
4659 HoistedVariable hv = GetHoistedVariable (ec);
4661 hv.Emit (ec, leave_copy);
4669 // If we are a reference, we loaded on the stack a pointer
4670 // Now lets load the real value
4672 ec.EmitLoadFromPtr (type);
4676 ec.Emit (OpCodes.Dup);
4679 temp = new LocalTemporary (Type);
4685 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4686 bool prepare_for_load)
4688 HoistedVariable hv = GetHoistedVariable (ec);
4690 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4694 New n_source = source as New;
4695 if (n_source != null) {
4696 if (!n_source.Emit (ec, this)) {
4700 ec.EmitLoadFromPtr (type);
4712 ec.Emit (OpCodes.Dup);
4714 temp = new LocalTemporary (Type);
4720 ec.EmitStoreFromPtr (type);
4722 Variable.EmitAssign (ec);
4730 public override Expression EmitToField (EmitContext ec)
4732 HoistedVariable hv = GetHoistedVariable (ec);
4734 return hv.EmitToField (ec);
4737 return base.EmitToField (ec);
4740 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4742 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4745 public HoistedVariable GetHoistedVariable (EmitContext ec)
4747 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4750 public override string GetSignatureForError ()
4755 public bool IsHoisted {
4756 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4761 // Resolved reference to a local variable
4763 public class LocalVariableReference : VariableReference
4765 public LocalVariable local_info;
4767 public LocalVariableReference (LocalVariable li, Location l)
4769 this.local_info = li;
4773 public override VariableInfo VariableInfo {
4774 get { return local_info.VariableInfo; }
4777 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4779 return local_info.HoistedVariant;
4785 // A local variable is always fixed
4787 public override bool IsFixed {
4793 public override bool IsLockedByStatement {
4795 return local_info.IsLocked;
4798 local_info.IsLocked = value;
4802 public override bool IsRef {
4803 get { return false; }
4806 public override string Name {
4807 get { return local_info.Name; }
4812 public override void VerifyAssigned (ResolveContext rc)
4814 VariableInfo variable_info = local_info.VariableInfo;
4815 if (variable_info == null)
4818 if (variable_info.IsAssigned (rc))
4821 rc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
4822 variable_info.SetAssigned (rc);
4825 public override void SetHasAddressTaken ()
4827 local_info.SetHasAddressTaken ();
4830 void DoResolveBase (ResolveContext ec)
4833 // If we are referencing a variable from the external block
4834 // flag it for capturing
4836 if (ec.MustCaptureVariable (local_info)) {
4837 if (local_info.AddressTaken) {
4838 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4839 } else if (local_info.IsFixed) {
4840 ec.Report.Error (1764, loc,
4841 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
4842 GetSignatureForError ());
4845 if (ec.IsVariableCapturingRequired) {
4846 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4847 storey.CaptureLocalVariable (ec, local_info);
4851 eclass = ExprClass.Variable;
4852 type = local_info.Type;
4855 protected override Expression DoResolve (ResolveContext ec)
4857 local_info.SetIsUsed ();
4859 VerifyAssigned (ec);
4865 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4868 if (right_side == EmptyExpression.OutAccess)
4869 local_info.SetIsUsed ();
4871 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
4874 if (right_side == EmptyExpression.OutAccess) {
4875 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4876 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4877 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4878 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4879 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4880 } else if (right_side == EmptyExpression.UnaryAddress) {
4881 code = 459; msg = "Cannot take the address of {1} `{0}'";
4883 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4885 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4886 } else if (VariableInfo != null) {
4887 VariableInfo.SetAssigned (ec);
4890 if (eclass == ExprClass.Unresolved)
4893 return base.DoResolveLValue (ec, right_side);
4896 public override int GetHashCode ()
4898 return local_info.GetHashCode ();
4901 public override bool Equals (object obj)
4903 LocalVariableReference lvr = obj as LocalVariableReference;
4907 return local_info == lvr.local_info;
4910 protected override ILocalVariable Variable {
4911 get { return local_info; }
4914 public override string ToString ()
4916 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4919 protected override void CloneTo (CloneContext clonectx, Expression t)
4926 /// This represents a reference to a parameter in the intermediate
4929 public class ParameterReference : VariableReference
4931 protected ParametersBlock.ParameterInfo pi;
4933 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
4941 public override bool IsLockedByStatement {
4946 pi.IsLocked = value;
4950 public override bool IsRef {
4951 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4954 bool HasOutModifier {
4955 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4958 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4960 return pi.Parameter.HoistedVariant;
4964 // A ref or out parameter is classified as a moveable variable, even
4965 // if the argument given for the parameter is a fixed variable
4967 public override bool IsFixed {
4968 get { return !IsRef; }
4971 public override string Name {
4972 get { return Parameter.Name; }
4975 public Parameter Parameter {
4976 get { return pi.Parameter; }
4979 public override VariableInfo VariableInfo {
4980 get { return pi.VariableInfo; }
4983 protected override ILocalVariable Variable {
4984 get { return Parameter; }
4989 public override void AddressOf (EmitContext ec, AddressOp mode)
4992 // ParameterReferences might already be a reference
4999 base.AddressOf (ec, mode);
5002 public override void SetHasAddressTaken ()
5004 Parameter.HasAddressTaken = true;
5007 void SetAssigned (ResolveContext ec)
5009 if (HasOutModifier && ec.DoFlowAnalysis)
5010 ec.CurrentBranching.SetAssigned (VariableInfo);
5013 bool DoResolveBase (ResolveContext ec)
5015 if (eclass != ExprClass.Unresolved)
5018 type = pi.ParameterType;
5019 eclass = ExprClass.Variable;
5022 // If we are referencing a parameter from the external block
5023 // flag it for capturing
5025 if (ec.MustCaptureVariable (pi)) {
5026 if (Parameter.HasAddressTaken)
5027 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5030 ec.Report.Error (1628, loc,
5031 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5032 Name, ec.CurrentAnonymousMethod.ContainerType);
5035 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5036 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5037 storey.CaptureParameter (ec, this);
5044 public override int GetHashCode ()
5046 return Name.GetHashCode ();
5049 public override bool Equals (object obj)
5051 ParameterReference pr = obj as ParameterReference;
5055 return Name == pr.Name;
5058 protected override void CloneTo (CloneContext clonectx, Expression target)
5064 public override Expression CreateExpressionTree (ResolveContext ec)
5066 HoistedVariable hv = GetHoistedVariable (ec);
5068 return hv.CreateExpressionTree ();
5070 return Parameter.ExpressionTreeVariableReference ();
5074 // Notice that for ref/out parameters, the type exposed is not the
5075 // same type exposed externally.
5078 // externally we expose "int&"
5079 // here we expose "int".
5081 // We record this in "is_ref". This means that the type system can treat
5082 // the type as it is expected, but when we generate the code, we generate
5083 // the alternate kind of code.
5085 protected override Expression DoResolve (ResolveContext ec)
5087 if (!DoResolveBase (ec))
5090 VerifyAssigned (ec);
5094 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5096 if (!DoResolveBase (ec))
5100 return base.DoResolveLValue (ec, right_side);
5103 public override void VerifyAssigned (ResolveContext rc)
5105 // HACK: Variables are not captured in probing mode
5106 if (rc.IsInProbingMode)
5109 if (HasOutModifier && !VariableInfo.IsAssigned (rc)) {
5110 rc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
5116 /// Invocation of methods or delegates.
5118 public class Invocation : ExpressionStatement
5120 protected Arguments arguments;
5121 protected Expression expr;
5122 protected MethodGroupExpr mg;
5124 public Invocation (Expression expr, Arguments arguments)
5127 this.arguments = arguments;
5129 loc = expr.Location;
5133 public Arguments Arguments {
5139 public Expression Expression {
5146 protected override void CloneTo (CloneContext clonectx, Expression t)
5148 Invocation target = (Invocation) t;
5150 if (arguments != null)
5151 target.arguments = arguments.Clone (clonectx);
5153 target.expr = expr.Clone (clonectx);
5156 public override bool ContainsEmitWithAwait ()
5158 if (arguments != null && arguments.ContainsEmitWithAwait ())
5161 return mg.ContainsEmitWithAwait ();
5164 public override Expression CreateExpressionTree (ResolveContext ec)
5166 Expression instance = mg.IsInstance ?
5167 mg.InstanceExpression.CreateExpressionTree (ec) :
5168 new NullLiteral (loc);
5170 var args = Arguments.CreateForExpressionTree (ec, arguments,
5172 mg.CreateExpressionTree (ec));
5174 return CreateExpressionFactoryCall (ec, "Call", args);
5177 protected override Expression DoResolve (ResolveContext ec)
5179 Expression member_expr;
5180 var atn = expr as ATypeNameExpression;
5182 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
5183 if (member_expr != null)
5184 member_expr = member_expr.Resolve (ec);
5186 member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5189 if (member_expr == null)
5193 // Next, evaluate all the expressions in the argument list
5195 bool dynamic_arg = false;
5196 if (arguments != null)
5197 arguments.Resolve (ec, out dynamic_arg);
5199 TypeSpec expr_type = member_expr.Type;
5200 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5201 return DoResolveDynamic (ec, member_expr);
5203 mg = member_expr as MethodGroupExpr;
5204 Expression invoke = null;
5207 if (expr_type != null && expr_type.IsDelegate) {
5208 invoke = new DelegateInvocation (member_expr, arguments, loc);
5209 invoke = invoke.Resolve (ec);
5210 if (invoke == null || !dynamic_arg)
5213 if (member_expr is RuntimeValueExpression) {
5214 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
5215 member_expr.Type.GetSignatureForError ()); ;
5219 MemberExpr me = member_expr as MemberExpr;
5221 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5225 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
5226 member_expr.GetSignatureForError ());
5231 if (invoke == null) {
5232 mg = DoResolveOverload (ec);
5238 return DoResolveDynamic (ec, member_expr);
5240 var method = mg.BestCandidate;
5241 type = mg.BestCandidateReturnType;
5243 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
5245 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5247 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5251 IsSpecialMethodInvocation (ec, method, loc);
5253 eclass = ExprClass.Value;
5257 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
5260 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
5262 args = dmb.Arguments;
5263 if (arguments != null)
5264 args.AddRange (arguments);
5265 } else if (mg == null) {
5266 if (arguments == null)
5267 args = new Arguments (1);
5271 args.Insert (0, new Argument (memberExpr));
5275 ec.Report.Error (1971, loc,
5276 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
5281 if (arguments == null)
5282 args = new Arguments (1);
5286 MemberAccess ma = expr as MemberAccess;
5288 var left_type = ma.LeftExpression as TypeExpr;
5289 if (left_type != null) {
5290 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5293 // Any value type has to be pass as by-ref to get back the same
5294 // instance on which the member was called
5296 var mod = TypeSpec.IsValueType (ma.LeftExpression.Type) ? Argument.AType.Ref : Argument.AType.None;
5297 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
5299 } else { // is SimpleName
5301 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5303 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5308 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5311 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5313 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
5316 static MetaType[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
5318 AParametersCollection pd = mb.Parameters;
5320 Argument a = arguments[pd.Count - 1];
5321 Arglist list = (Arglist) a.Expr;
5323 return list.ArgumentTypes;
5326 public override string GetSignatureForError ()
5328 return mg.GetSignatureForError ();
5332 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
5333 // or the type dynamic, then the member is invocable
5335 public static bool IsMemberInvocable (MemberSpec member)
5337 switch (member.Kind) {
5338 case MemberKind.Event:
5340 case MemberKind.Field:
5341 case MemberKind.Property:
5342 var m = member as IInterfaceMemberSpec;
5343 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
5349 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
5351 if (!method.IsReservedMethod)
5354 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
5357 ec.Report.SymbolRelatedToPreviousError (method);
5358 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5359 method.GetSignatureForError ());
5364 public override void Emit (EmitContext ec)
5366 mg.EmitCall (ec, arguments);
5369 public override void EmitStatement (EmitContext ec)
5374 // Pop the return value if there is one
5376 if (type.Kind != MemberKind.Void)
5377 ec.Emit (OpCodes.Pop);
5380 public override SLE.Expression MakeExpression (BuilderContext ctx)
5382 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
5385 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
5388 throw new NotSupportedException ();
5390 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5391 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
5397 // Implements simple new expression
5399 public class New : ExpressionStatement, IMemoryLocation
5401 protected Arguments arguments;
5404 // During bootstrap, it contains the RequestedType,
5405 // but if `type' is not null, it *might* contain a NewDelegate
5406 // (because of field multi-initialization)
5408 protected Expression RequestedType;
5410 protected MethodSpec method;
5412 public New (Expression requested_type, Arguments arguments, Location l)
5414 RequestedType = requested_type;
5415 this.arguments = arguments;
5420 public Arguments Arguments {
5427 // Returns true for resolved `new S()'
5429 public bool IsDefaultStruct {
5431 return arguments == null && type.IsStruct && GetType () == typeof (New);
5438 /// Converts complex core type syntax like 'new int ()' to simple constant
5440 public static Constant Constantify (TypeSpec t, Location loc)
5442 switch (t.BuiltinType) {
5443 case BuiltinTypeSpec.Type.Int:
5444 return new IntConstant (t, 0, loc);
5445 case BuiltinTypeSpec.Type.UInt:
5446 return new UIntConstant (t, 0, loc);
5447 case BuiltinTypeSpec.Type.Long:
5448 return new LongConstant (t, 0, loc);
5449 case BuiltinTypeSpec.Type.ULong:
5450 return new ULongConstant (t, 0, loc);
5451 case BuiltinTypeSpec.Type.Float:
5452 return new FloatConstant (t, 0, loc);
5453 case BuiltinTypeSpec.Type.Double:
5454 return new DoubleConstant (t, 0, loc);
5455 case BuiltinTypeSpec.Type.Short:
5456 return new ShortConstant (t, 0, loc);
5457 case BuiltinTypeSpec.Type.UShort:
5458 return new UShortConstant (t, 0, loc);
5459 case BuiltinTypeSpec.Type.SByte:
5460 return new SByteConstant (t, 0, loc);
5461 case BuiltinTypeSpec.Type.Byte:
5462 return new ByteConstant (t, 0, loc);
5463 case BuiltinTypeSpec.Type.Char:
5464 return new CharConstant (t, '\0', loc);
5465 case BuiltinTypeSpec.Type.Bool:
5466 return new BoolConstant (t, false, loc);
5467 case BuiltinTypeSpec.Type.Decimal:
5468 return new DecimalConstant (t, 0, loc);
5472 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
5474 if (t.IsNullableType)
5475 return Nullable.LiftedNull.Create (t, loc);
5480 public override bool ContainsEmitWithAwait ()
5482 return arguments != null && arguments.ContainsEmitWithAwait ();
5486 // Checks whether the type is an interface that has the
5487 // [ComImport, CoClass] attributes and must be treated
5490 public Expression CheckComImport (ResolveContext ec)
5492 if (!type.IsInterface)
5496 // Turn the call into:
5497 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5499 var real_class = type.MemberDefinition.GetAttributeCoClass ();
5500 if (real_class == null)
5503 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
5504 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5505 return cast.Resolve (ec);
5508 public override Expression CreateExpressionTree (ResolveContext ec)
5511 if (method == null) {
5512 args = new Arguments (1);
5513 args.Add (new Argument (new TypeOf (type, loc)));
5515 args = Arguments.CreateForExpressionTree (ec,
5516 arguments, new TypeOfMethod (method, loc));
5519 return CreateExpressionFactoryCall (ec, "New", args);
5522 protected override Expression DoResolve (ResolveContext ec)
5524 type = RequestedType.ResolveAsType (ec);
5528 eclass = ExprClass.Value;
5530 if (type.IsPointer) {
5531 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5532 TypeManager.CSharpName (type));
5536 if (arguments == null) {
5537 Constant c = Constantify (type, RequestedType.Location);
5539 return ReducedExpression.Create (c, this);
5542 if (type.IsDelegate) {
5543 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
5546 var tparam = type as TypeParameterSpec;
5547 if (tparam != null) {
5549 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
5550 // where type parameter constraint is inflated to struct
5552 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
5553 ec.Report.Error (304, loc,
5554 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
5555 TypeManager.CSharpName (type));
5558 if ((arguments != null) && (arguments.Count != 0)) {
5559 ec.Report.Error (417, loc,
5560 "`{0}': cannot provide arguments when creating an instance of a variable type",
5561 TypeManager.CSharpName (type));
5567 if (type.IsStatic) {
5568 ec.Report.SymbolRelatedToPreviousError (type);
5569 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5573 if (type.IsInterface || type.IsAbstract){
5574 if (!TypeManager.IsGenericType (type)) {
5575 RequestedType = CheckComImport (ec);
5576 if (RequestedType != null)
5577 return RequestedType;
5580 ec.Report.SymbolRelatedToPreviousError (type);
5581 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5586 // Any struct always defines parameterless constructor
5588 if (type.IsStruct && arguments == null)
5592 if (arguments != null) {
5593 arguments.Resolve (ec, out dynamic);
5598 method = ConstructorLookup (ec, type, ref arguments, loc);
5601 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5602 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
5608 bool DoEmitTypeParameter (EmitContext ec)
5610 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
5614 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
5615 var tparam = (TypeParameterSpec) type;
5617 if (tparam.IsReferenceType) {
5618 ec.Emit (OpCodes.Call, ctor_factory);
5622 // Allow DoEmit() to be called multiple times.
5623 // We need to create a new LocalTemporary each time since
5624 // you can't share LocalBuilders among ILGeneators.
5625 LocalTemporary temp = new LocalTemporary (type);
5627 Label label_activator = ec.DefineLabel ();
5628 Label label_end = ec.DefineLabel ();
5630 temp.AddressOf (ec, AddressOp.Store);
5631 ec.Emit (OpCodes.Initobj, type);
5634 ec.Emit (OpCodes.Box, type);
5635 ec.Emit (OpCodes.Brfalse, label_activator);
5637 temp.AddressOf (ec, AddressOp.Store);
5638 ec.Emit (OpCodes.Initobj, type);
5641 ec.Emit (OpCodes.Br_S, label_end);
5643 ec.MarkLabel (label_activator);
5645 ec.Emit (OpCodes.Call, ctor_factory);
5646 ec.MarkLabel (label_end);
5651 // This Emit can be invoked in two contexts:
5652 // * As a mechanism that will leave a value on the stack (new object)
5653 // * As one that wont (init struct)
5655 // If we are dealing with a ValueType, we have a few
5656 // situations to deal with:
5658 // * The target is a ValueType, and we have been provided
5659 // the instance (this is easy, we are being assigned).
5661 // * The target of New is being passed as an argument,
5662 // to a boxing operation or a function that takes a
5665 // In this case, we need to create a temporary variable
5666 // that is the argument of New.
5668 // Returns whether a value is left on the stack
5670 // *** Implementation note ***
5672 // To benefit from this optimization, each assignable expression
5673 // has to manually cast to New and call this Emit.
5675 // TODO: It's worth to implement it for arrays and fields
5677 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5679 bool is_value_type = TypeSpec.IsValueType (type);
5680 VariableReference vr = target as VariableReference;
5682 if (target != null && is_value_type && (vr != null || method == null)) {
5683 target.AddressOf (ec, AddressOp.Store);
5684 } else if (vr != null && vr.IsRef) {
5688 if (arguments != null) {
5689 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
5690 arguments = arguments.Emit (ec, false, true);
5692 arguments.Emit (ec);
5695 if (is_value_type) {
5696 if (method == null) {
5697 ec.Emit (OpCodes.Initobj, type);
5702 ec.Emit (OpCodes.Call, method);
5707 if (type is TypeParameterSpec)
5708 return DoEmitTypeParameter (ec);
5710 ec.Emit (OpCodes.Newobj, method);
5714 public override void Emit (EmitContext ec)
5716 LocalTemporary v = null;
5717 if (method == null && TypeSpec.IsValueType (type)) {
5718 // TODO: Use temporary variable from pool
5719 v = new LocalTemporary (type);
5726 public override void EmitStatement (EmitContext ec)
5728 LocalTemporary v = null;
5729 if (method == null && TypeSpec.IsValueType (type)) {
5730 // TODO: Use temporary variable from pool
5731 v = new LocalTemporary (type);
5735 ec.Emit (OpCodes.Pop);
5738 public void AddressOf (EmitContext ec, AddressOp mode)
5740 EmitAddressOf (ec, mode);
5743 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5745 LocalTemporary value_target = new LocalTemporary (type);
5747 if (type is TypeParameterSpec) {
5748 DoEmitTypeParameter (ec);
5749 value_target.Store (ec);
5750 value_target.AddressOf (ec, mode);
5751 return value_target;
5754 value_target.AddressOf (ec, AddressOp.Store);
5756 if (method == null) {
5757 ec.Emit (OpCodes.Initobj, type);
5759 if (arguments != null)
5760 arguments.Emit (ec);
5762 ec.Emit (OpCodes.Call, method);
5765 value_target.AddressOf (ec, mode);
5766 return value_target;
5769 protected override void CloneTo (CloneContext clonectx, Expression t)
5771 New target = (New) t;
5773 target.RequestedType = RequestedType.Clone (clonectx);
5774 if (arguments != null){
5775 target.arguments = arguments.Clone (clonectx);
5779 public override SLE.Expression MakeExpression (BuilderContext ctx)
5782 return base.MakeExpression (ctx);
5784 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
5790 // Array initializer expression, the expression is allowed in
5791 // variable or field initialization only which makes it tricky as
5792 // the type has to be infered based on the context either from field
5793 // type or variable type (think of multiple declarators)
5795 public class ArrayInitializer : Expression
5797 List<Expression> elements;
5798 BlockVariableDeclaration variable;
5800 public ArrayInitializer (List<Expression> init, Location loc)
5806 public ArrayInitializer (int count, Location loc)
5807 : this (new List<Expression> (count), loc)
5811 public ArrayInitializer (Location loc)
5819 get { return elements.Count; }
5822 public Expression this [int index] {
5824 return elements [index];
5828 public BlockVariableDeclaration VariableDeclaration {
5839 public void Add (Expression expr)
5841 elements.Add (expr);
5844 public override bool ContainsEmitWithAwait ()
5846 throw new NotSupportedException ();
5849 public override Expression CreateExpressionTree (ResolveContext ec)
5851 throw new NotSupportedException ("ET");
5854 protected override void CloneTo (CloneContext clonectx, Expression t)
5856 var target = (ArrayInitializer) t;
5858 target.elements = new List<Expression> (elements.Count);
5859 foreach (var element in elements)
5860 target.elements.Add (element.Clone (clonectx));
5863 protected override Expression DoResolve (ResolveContext rc)
5865 var current_field = rc.CurrentMemberDefinition as FieldBase;
5866 TypeExpression type;
5867 if (current_field != null && rc.CurrentAnonymousMethod == null) {
5868 type = new TypeExpression (current_field.MemberType, current_field.Location);
5869 } else if (variable != null) {
5870 if (variable.TypeExpression is VarExpr) {
5871 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5872 return EmptyExpression.Null;
5875 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
5877 throw new NotImplementedException ("Unexpected array initializer context");
5880 return new ArrayCreation (type, this).Resolve (rc);
5883 public override void Emit (EmitContext ec)
5885 throw new InternalErrorException ("Missing Resolve call");
5890 /// 14.5.10.2: Represents an array creation expression.
5894 /// There are two possible scenarios here: one is an array creation
5895 /// expression that specifies the dimensions and optionally the
5896 /// initialization data and the other which does not need dimensions
5897 /// specified but where initialization data is mandatory.
5899 public class ArrayCreation : Expression
5901 FullNamedExpression requested_base_type;
5902 ArrayInitializer initializers;
5905 // The list of Argument types.
5906 // This is used to construct the `newarray' or constructor signature
5908 protected List<Expression> arguments;
5910 protected TypeSpec array_element_type;
5911 int num_arguments = 0;
5912 protected int dimensions;
5913 protected readonly ComposedTypeSpecifier rank;
5914 Expression first_emit;
5915 LocalTemporary first_emit_temp;
5917 protected List<Expression> array_data;
5919 Dictionary<int, int> bounds;
5921 // The number of constants in array initializers
5922 int const_initializers_count;
5923 bool only_constant_initializers;
5925 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
5926 : this (requested_base_type, rank, initializers, l)
5928 arguments = new List<Expression> (exprs);
5929 num_arguments = arguments.Count;
5933 // For expressions like int[] foo = new int[] { 1, 2, 3 };
5935 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
5937 this.requested_base_type = requested_base_type;
5939 this.initializers = initializers;
5943 num_arguments = rank.Dimension;
5947 // For compiler generated single dimensional arrays only
5949 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
5950 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
5955 // For expressions like int[] foo = { 1, 2, 3 };
5957 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
5958 : this (requested_base_type, null, initializers, initializers.Location)
5962 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
5964 if (initializers != null && bounds == null) {
5966 // We use this to store all the date values in the order in which we
5967 // will need to store them in the byte blob later
5969 array_data = new List<Expression> ();
5970 bounds = new Dictionary<int, int> ();
5973 if (specified_dims) {
5974 Expression a = arguments [idx];
5979 a = ConvertExpressionToArrayIndex (ec, a);
5985 if (initializers != null) {
5986 Constant c = a as Constant;
5987 if (c == null && a is ArrayIndexCast)
5988 c = ((ArrayIndexCast) a).Child as Constant;
5991 ec.Report.Error (150, a.Location, "A constant value is expected");
5997 value = System.Convert.ToInt32 (c.GetValue ());
5999 ec.Report.Error (150, a.Location, "A constant value is expected");
6003 // TODO: probe.Count does not fit ulong in
6004 if (value != probe.Count) {
6005 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6009 bounds[idx] = value;
6013 if (initializers == null)
6016 for (int i = 0; i < probe.Count; ++i) {
6018 if (o is ArrayInitializer) {
6019 var sub_probe = o as ArrayInitializer;
6020 if (idx + 1 >= dimensions){
6021 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6025 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6028 } else if (child_bounds > 1) {
6029 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6031 Expression element = ResolveArrayElement (ec, o);
6032 if (element == null)
6035 // Initializers with the default values can be ignored
6036 Constant c = element as Constant;
6038 if (!c.IsDefaultInitializer (array_element_type)) {
6039 ++const_initializers_count;
6042 only_constant_initializers = false;
6045 array_data.Add (element);
6052 public override bool ContainsEmitWithAwait ()
6054 foreach (var arg in arguments) {
6055 if (arg.ContainsEmitWithAwait ())
6059 return InitializersContainAwait ();
6062 public override Expression CreateExpressionTree (ResolveContext ec)
6066 if (array_data == null) {
6067 args = new Arguments (arguments.Count + 1);
6068 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6069 foreach (Expression a in arguments)
6070 args.Add (new Argument (a.CreateExpressionTree (ec)));
6072 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6075 if (dimensions > 1) {
6076 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6080 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6081 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6082 if (array_data != null) {
6083 for (int i = 0; i < array_data.Count; ++i) {
6084 Expression e = array_data [i];
6085 args.Add (new Argument (e.CreateExpressionTree (ec)));
6089 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6092 void UpdateIndices (ResolveContext rc)
6095 for (var probe = initializers; probe != null;) {
6096 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
6098 bounds[i++] = probe.Count;
6100 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
6101 probe = (ArrayInitializer) probe[0];
6102 } else if (dimensions > i) {
6110 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
6112 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
6115 bool InitializersContainAwait ()
6117 if (array_data == null)
6120 foreach (var expr in array_data) {
6121 if (expr.ContainsEmitWithAwait ())
6128 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
6130 element = element.Resolve (ec);
6131 if (element == null)
6134 if (element is CompoundAssign.TargetExpression) {
6135 if (first_emit != null)
6136 throw new InternalErrorException ("Can only handle one mutator at a time");
6137 first_emit = element;
6138 element = first_emit_temp = new LocalTemporary (element.Type);
6141 return Convert.ImplicitConversionRequired (
6142 ec, element, array_element_type, loc);
6145 protected bool ResolveInitializers (ResolveContext ec)
6147 only_constant_initializers = true;
6149 if (arguments != null) {
6151 for (int i = 0; i < arguments.Count; ++i) {
6152 res &= CheckIndices (ec, initializers, i, true, dimensions);
6153 if (initializers != null)
6160 arguments = new List<Expression> ();
6162 if (!CheckIndices (ec, initializers, 0, false, dimensions))
6171 // Resolved the type of the array
6173 bool ResolveArrayType (ResolveContext ec)
6178 FullNamedExpression array_type_expr;
6179 if (num_arguments > 0) {
6180 array_type_expr = new ComposedCast (requested_base_type, rank);
6182 array_type_expr = requested_base_type;
6185 type = array_type_expr.ResolveAsType (ec);
6186 if (array_type_expr == null)
6189 var ac = type as ArrayContainer;
6191 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6195 array_element_type = ac.Element;
6196 dimensions = ac.Rank;
6201 protected override Expression DoResolve (ResolveContext ec)
6206 if (!ResolveArrayType (ec))
6210 // validate the initializers and fill in any missing bits
6212 if (!ResolveInitializers (ec))
6215 eclass = ExprClass.Value;
6219 byte [] MakeByteBlob ()
6224 int count = array_data.Count;
6226 TypeSpec element_type = array_element_type;
6227 if (element_type.IsEnum)
6228 element_type = EnumSpec.GetUnderlyingType (element_type);
6230 factor = BuiltinTypeSpec.GetSize (element_type);
6232 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6234 data = new byte [(count * factor + 3) & ~3];
6237 for (int i = 0; i < count; ++i) {
6238 var c = array_data[i] as Constant;
6244 object v = c.GetValue ();
6246 switch (element_type.BuiltinType) {
6247 case BuiltinTypeSpec.Type.Long:
6248 long lval = (long) v;
6250 for (int j = 0; j < factor; ++j) {
6251 data[idx + j] = (byte) (lval & 0xFF);
6255 case BuiltinTypeSpec.Type.ULong:
6256 ulong ulval = (ulong) v;
6258 for (int j = 0; j < factor; ++j) {
6259 data[idx + j] = (byte) (ulval & 0xFF);
6260 ulval = (ulval >> 8);
6263 case BuiltinTypeSpec.Type.Float:
6264 element = BitConverter.GetBytes ((float) v);
6266 for (int j = 0; j < factor; ++j)
6267 data[idx + j] = element[j];
6268 if (!BitConverter.IsLittleEndian)
6269 System.Array.Reverse (data, idx, 4);
6271 case BuiltinTypeSpec.Type.Double:
6272 element = BitConverter.GetBytes ((double) v);
6274 for (int j = 0; j < factor; ++j)
6275 data[idx + j] = element[j];
6277 // FIXME: Handle the ARM float format.
6278 if (!BitConverter.IsLittleEndian)
6279 System.Array.Reverse (data, idx, 8);
6281 case BuiltinTypeSpec.Type.Char:
6282 int chval = (int) ((char) v);
6284 data[idx] = (byte) (chval & 0xff);
6285 data[idx + 1] = (byte) (chval >> 8);
6287 case BuiltinTypeSpec.Type.Short:
6288 int sval = (int) ((short) v);
6290 data[idx] = (byte) (sval & 0xff);
6291 data[idx + 1] = (byte) (sval >> 8);
6293 case BuiltinTypeSpec.Type.UShort:
6294 int usval = (int) ((ushort) v);
6296 data[idx] = (byte) (usval & 0xff);
6297 data[idx + 1] = (byte) (usval >> 8);
6299 case BuiltinTypeSpec.Type.Int:
6302 data[idx] = (byte) (val & 0xff);
6303 data[idx + 1] = (byte) ((val >> 8) & 0xff);
6304 data[idx + 2] = (byte) ((val >> 16) & 0xff);
6305 data[idx + 3] = (byte) (val >> 24);
6307 case BuiltinTypeSpec.Type.UInt:
6308 uint uval = (uint) v;
6310 data[idx] = (byte) (uval & 0xff);
6311 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
6312 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
6313 data[idx + 3] = (byte) (uval >> 24);
6315 case BuiltinTypeSpec.Type.SByte:
6316 data[idx] = (byte) (sbyte) v;
6318 case BuiltinTypeSpec.Type.Byte:
6319 data[idx] = (byte) v;
6321 case BuiltinTypeSpec.Type.Bool:
6322 data[idx] = (byte) ((bool) v ? 1 : 0);
6324 case BuiltinTypeSpec.Type.Decimal:
6325 int[] bits = Decimal.GetBits ((decimal) v);
6328 // FIXME: For some reason, this doesn't work on the MS runtime.
6329 int[] nbits = new int[4];
6335 for (int j = 0; j < 4; j++) {
6336 data[p++] = (byte) (nbits[j] & 0xff);
6337 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
6338 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
6339 data[p++] = (byte) (nbits[j] >> 24);
6343 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6353 public override SLE.Expression MakeExpression (BuilderContext ctx)
6356 return base.MakeExpression (ctx);
6358 var initializers = new SLE.Expression [array_data.Count];
6359 for (var i = 0; i < initializers.Length; i++) {
6360 if (array_data [i] == null)
6361 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
6363 initializers [i] = array_data [i].MakeExpression (ctx);
6366 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
6372 // Emits the initializers for the array
6374 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
6376 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
6381 // First, the static data
6383 byte [] data = MakeByteBlob ();
6384 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
6386 if (stackArray == null) {
6387 ec.Emit (OpCodes.Dup);
6389 stackArray.Emit (ec);
6392 ec.Emit (OpCodes.Ldtoken, fb);
6393 ec.Emit (OpCodes.Call, m);
6398 // Emits pieces of the array that can not be computed at compile
6399 // time (variables and string locations).
6401 // This always expect the top value on the stack to be the array
6403 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
6405 int dims = bounds.Count;
6406 var current_pos = new int [dims];
6408 for (int i = 0; i < array_data.Count; i++){
6410 Expression e = array_data [i];
6411 var c = e as Constant;
6413 // Constant can be initialized via StaticInitializer
6414 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
6418 if (stackArray != null) {
6419 if (e.ContainsEmitWithAwait ()) {
6420 e = e.EmitToField (ec);
6423 stackArray.Emit (ec);
6425 ec.Emit (OpCodes.Dup);
6428 for (int idx = 0; idx < dims; idx++)
6429 ec.EmitInt (current_pos [idx]);
6432 // If we are dealing with a struct, get the
6433 // address of it, so we can store it.
6435 if (dims == 1 && etype.IsStruct) {
6436 switch (etype.BuiltinType) {
6437 case BuiltinTypeSpec.Type.Byte:
6438 case BuiltinTypeSpec.Type.SByte:
6439 case BuiltinTypeSpec.Type.Bool:
6440 case BuiltinTypeSpec.Type.Short:
6441 case BuiltinTypeSpec.Type.UShort:
6442 case BuiltinTypeSpec.Type.Char:
6443 case BuiltinTypeSpec.Type.Int:
6444 case BuiltinTypeSpec.Type.UInt:
6445 case BuiltinTypeSpec.Type.Long:
6446 case BuiltinTypeSpec.Type.ULong:
6447 case BuiltinTypeSpec.Type.Float:
6448 case BuiltinTypeSpec.Type.Double:
6451 ec.Emit (OpCodes.Ldelema, etype);
6458 ec.EmitArrayStore ((ArrayContainer) type);
6464 for (int j = dims - 1; j >= 0; j--){
6466 if (current_pos [j] < bounds [j])
6468 current_pos [j] = 0;
6473 public override void Emit (EmitContext ec)
6475 if (first_emit != null) {
6476 first_emit.Emit (ec);
6477 first_emit_temp.Store (ec);
6480 FieldExpr await_stack_field;
6481 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
6482 await_stack_field = ec.GetTemporaryField (type);
6485 await_stack_field = null;
6488 EmitExpressionsList (ec, arguments);
6490 ec.EmitArrayNew ((ArrayContainer) type);
6492 if (initializers == null)
6495 if (await_stack_field != null)
6496 await_stack_field.EmitAssignFromStack (ec);
6500 // Emit static initializer for arrays which contain more than 2 items and
6501 // the static initializer will initialize at least 25% of array values or there
6502 // is more than 10 items to be initialized
6504 // NOTE: const_initializers_count does not contain default constant values.
6506 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
6507 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
6508 EmitStaticInitializers (ec, await_stack_field);
6510 if (!only_constant_initializers)
6511 EmitDynamicInitializers (ec, false, await_stack_field);
6515 EmitDynamicInitializers (ec, true, await_stack_field);
6518 if (await_stack_field != null)
6519 await_stack_field.Emit (ec);
6521 if (first_emit_temp != null)
6522 first_emit_temp.Release (ec);
6525 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
6527 // no multi dimensional or jagged arrays
6528 if (arguments.Count != 1 || array_element_type.IsArray) {
6529 base.EncodeAttributeValue (rc, enc, targetType);
6533 // No array covariance, except for array -> object
6534 if (type != targetType) {
6535 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
6536 base.EncodeAttributeValue (rc, enc, targetType);
6540 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
6541 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
6546 // Single dimensional array of 0 size
6547 if (array_data == null) {
6548 IntConstant ic = arguments[0] as IntConstant;
6549 if (ic == null || !ic.IsDefaultValue) {
6550 base.EncodeAttributeValue (rc, enc, targetType);
6558 enc.Encode (array_data.Count);
6559 foreach (var element in array_data) {
6560 element.EncodeAttributeValue (rc, enc, array_element_type);
6564 protected override void CloneTo (CloneContext clonectx, Expression t)
6566 ArrayCreation target = (ArrayCreation) t;
6568 if (requested_base_type != null)
6569 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6571 if (arguments != null){
6572 target.arguments = new List<Expression> (arguments.Count);
6573 foreach (Expression e in arguments)
6574 target.arguments.Add (e.Clone (clonectx));
6577 if (initializers != null)
6578 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
6583 // Represents an implicitly typed array epxression
6585 class ImplicitlyTypedArrayCreation : ArrayCreation
6587 sealed class InferenceContext : TypeInferenceContext
6589 class ExpressionBoundInfo : BoundInfo
6591 readonly Expression expr;
6593 public ExpressionBoundInfo (Expression expr)
6594 : base (expr.Type, BoundKind.Lower)
6599 public override bool Equals (BoundInfo other)
6601 // We are using expression not type for conversion check
6602 // no optimization based on types is possible
6606 public override Expression GetTypeExpression ()
6612 public void AddExpression (Expression expr)
6614 AddToBounds (new ExpressionBoundInfo (expr), 0);
6618 InferenceContext best_type_inference;
6620 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6621 : base (null, rank, initializers, loc)
6625 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
6626 : base (null, initializers, loc)
6630 protected override Expression DoResolve (ResolveContext ec)
6635 dimensions = rank.Dimension;
6637 best_type_inference = new InferenceContext ();
6639 if (!ResolveInitializers (ec))
6642 best_type_inference.FixAllTypes (ec);
6643 array_element_type = best_type_inference.InferredTypeArguments[0];
6644 best_type_inference = null;
6646 if (array_element_type == null || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
6647 arguments.Count != rank.Dimension) {
6648 ec.Report.Error (826, loc,
6649 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6654 // At this point we found common base type for all initializer elements
6655 // but we have to be sure that all static initializer elements are of
6658 UnifyInitializerElement (ec);
6660 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
6661 eclass = ExprClass.Value;
6666 // Converts static initializer only
6668 void UnifyInitializerElement (ResolveContext ec)
6670 for (int i = 0; i < array_data.Count; ++i) {
6671 Expression e = array_data[i];
6673 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6677 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6679 element = element.Resolve (ec);
6680 if (element != null)
6681 best_type_inference.AddExpression (element);
6687 sealed class CompilerGeneratedThis : This
6689 public CompilerGeneratedThis (TypeSpec type, Location loc)
6693 eclass = ExprClass.Variable;
6696 protected override Expression DoResolve (ResolveContext ec)
6701 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6708 /// Represents the `this' construct
6711 public class This : VariableReference
6713 sealed class ThisVariable : ILocalVariable
6715 public static readonly ILocalVariable Instance = new ThisVariable ();
6717 public void Emit (EmitContext ec)
6722 public void EmitAssign (EmitContext ec)
6724 throw new InvalidOperationException ();
6727 public void EmitAddressOf (EmitContext ec)
6733 VariableInfo variable_info;
6735 public This (Location loc)
6742 public override string Name {
6743 get { return "this"; }
6746 public override bool IsLockedByStatement {
6754 public override bool IsRef {
6755 get { return type.IsStruct; }
6758 public override bool IsSideEffectFree {
6764 protected override ILocalVariable Variable {
6765 get { return ThisVariable.Instance; }
6768 public override VariableInfo VariableInfo {
6769 get { return variable_info; }
6772 public override bool IsFixed {
6773 get { return false; }
6778 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
6781 // It's null for all cases when we don't need to check `this'
6782 // definitive assignment
6784 if (variable_info == null)
6787 if (rc.HasSet (ResolveContext.Options.OmitStructFlowAnalysis))
6790 if (!variable_info.IsAssigned (rc)) {
6791 rc.Report.Error (188, loc,
6792 "The `this' object cannot be used before all of its fields are assigned to");
6796 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
6798 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6799 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6800 } else if (ec.CurrentAnonymousMethod != null) {
6801 ec.Report.Error (1673, loc,
6802 "Anonymous methods inside structs cannot access instance members of `this'. " +
6803 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6805 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6809 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6814 AnonymousMethodStorey storey = ae.Storey;
6815 while (storey != null) {
6816 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6818 return storey.HoistedThis;
6826 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
6828 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
6831 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
6834 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
6840 public virtual void ResolveBase (ResolveContext ec)
6842 eclass = ExprClass.Variable;
6843 type = ec.CurrentType;
6845 if (!IsThisAvailable (ec, false)) {
6846 Error_ThisNotAvailable (ec);
6850 var block = ec.CurrentBlock;
6851 if (block != null) {
6852 if (block.ParametersBlock.TopBlock.ThisVariable != null)
6853 variable_info = block.ParametersBlock.TopBlock.ThisVariable.VariableInfo;
6855 AnonymousExpression am = ec.CurrentAnonymousMethod;
6856 if (am != null && ec.IsVariableCapturingRequired) {
6857 am.SetHasThisAccess ();
6862 protected override Expression DoResolve (ResolveContext ec)
6866 CheckStructThisDefiniteAssignment (ec);
6871 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6873 if (eclass == ExprClass.Unresolved)
6876 if (variable_info != null)
6877 variable_info.SetAssigned (ec);
6880 if (right_side == EmptyExpression.UnaryAddress)
6881 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6882 else if (right_side == EmptyExpression.OutAccess)
6883 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6885 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6891 public override int GetHashCode()
6893 throw new NotImplementedException ();
6896 public override bool Equals (object obj)
6898 This t = obj as This;
6905 protected override void CloneTo (CloneContext clonectx, Expression t)
6910 public override void SetHasAddressTaken ()
6915 public override void VerifyAssigned (ResolveContext rc)
6921 /// Represents the `__arglist' construct
6923 public class ArglistAccess : Expression
6925 public ArglistAccess (Location loc)
6930 protected override void CloneTo (CloneContext clonectx, Expression target)
6935 public override bool ContainsEmitWithAwait ()
6940 public override Expression CreateExpressionTree (ResolveContext ec)
6942 throw new NotSupportedException ("ET");
6945 protected override Expression DoResolve (ResolveContext ec)
6947 eclass = ExprClass.Variable;
6948 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
6950 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
6951 ec.Report.Error (190, loc,
6952 "The __arglist construct is valid only within a variable argument method");
6958 public override void Emit (EmitContext ec)
6960 ec.Emit (OpCodes.Arglist);
6965 /// Represents the `__arglist (....)' construct
6967 public class Arglist : Expression
6969 Arguments Arguments;
6971 public Arglist (Location loc)
6976 public Arglist (Arguments args, Location l)
6982 public MetaType[] ArgumentTypes {
6984 if (Arguments == null)
6985 return MetaType.EmptyTypes;
6987 var retval = new MetaType[Arguments.Count];
6988 for (int i = 0; i < retval.Length; i++)
6989 retval[i] = Arguments[i].Expr.Type.GetMetaInfo ();
6995 public override bool ContainsEmitWithAwait ()
6997 throw new NotImplementedException ();
7000 public override Expression CreateExpressionTree (ResolveContext ec)
7002 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7006 protected override Expression DoResolve (ResolveContext ec)
7008 eclass = ExprClass.Variable;
7009 type = InternalType.Arglist;
7010 if (Arguments != null) {
7011 bool dynamic; // Can be ignored as there is always only 1 overload
7012 Arguments.Resolve (ec, out dynamic);
7018 public override void Emit (EmitContext ec)
7020 if (Arguments != null)
7021 Arguments.Emit (ec);
7024 protected override void CloneTo (CloneContext clonectx, Expression t)
7026 Arglist target = (Arglist) t;
7028 if (Arguments != null)
7029 target.Arguments = Arguments.Clone (clonectx);
7033 class RefValueExpr : ShimExpression
7035 FullNamedExpression texpr;
7037 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7044 public override bool ContainsEmitWithAwait ()
7049 protected override Expression DoResolve (ResolveContext rc)
7051 expr = expr.Resolve (rc);
7052 type = texpr.ResolveAsType (rc);
7053 if (expr == null || type == null)
7056 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7057 eclass = ExprClass.Value;
7061 public override void Emit (EmitContext ec)
7064 ec.Emit (OpCodes.Refanyval, type);
7065 ec.EmitLoadFromPtr (type);
7069 class RefTypeExpr : ShimExpression
7071 public RefTypeExpr (Expression expr, Location loc)
7077 protected override Expression DoResolve (ResolveContext rc)
7079 expr = expr.Resolve (rc);
7083 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7087 type = rc.BuiltinTypes.Type;
7088 eclass = ExprClass.Value;
7092 public override void Emit (EmitContext ec)
7095 ec.Emit (OpCodes.Refanytype);
7096 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7098 ec.Emit (OpCodes.Call, m);
7102 class MakeRefExpr : ShimExpression
7104 public MakeRefExpr (Expression expr, Location loc)
7110 public override bool ContainsEmitWithAwait ()
7112 throw new NotImplementedException ();
7115 protected override Expression DoResolve (ResolveContext rc)
7117 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
7118 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
7119 eclass = ExprClass.Value;
7123 public override void Emit (EmitContext ec)
7125 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
7126 ec.Emit (OpCodes.Mkrefany, expr.Type);
7131 /// Implements the typeof operator
7133 public class TypeOf : Expression {
7134 FullNamedExpression QueriedType;
7137 public TypeOf (FullNamedExpression queried_type, Location l)
7139 QueriedType = queried_type;
7144 // Use this constructor for any compiler generated typeof expression
7146 public TypeOf (TypeSpec type, Location loc)
7148 this.typearg = type;
7154 public override bool IsSideEffectFree {
7160 public TypeSpec TypeArgument {
7166 public FullNamedExpression TypeExpression {
7175 protected override void CloneTo (CloneContext clonectx, Expression t)
7177 TypeOf target = (TypeOf) t;
7178 if (QueriedType != null)
7179 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
7182 public override bool ContainsEmitWithAwait ()
7187 public override Expression CreateExpressionTree (ResolveContext ec)
7189 Arguments args = new Arguments (2);
7190 args.Add (new Argument (this));
7191 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7192 return CreateExpressionFactoryCall (ec, "Constant", args);
7195 protected override Expression DoResolve (ResolveContext ec)
7197 if (eclass != ExprClass.Unresolved)
7200 if (typearg == null) {
7202 // Pointer types are allowed without explicit unsafe, they are just tokens
7204 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
7205 typearg = QueriedType.ResolveAsType (ec);
7208 if (typearg == null)
7211 if (typearg.Kind == MemberKind.Void && !(QueriedType is TypeExpression)) {
7212 ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
7213 } else if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7214 ec.Report.Error (1962, QueriedType.Location,
7215 "The typeof operator cannot be used on the dynamic type");
7219 type = ec.BuiltinTypes.Type;
7221 // Even though what is returned is a type object, it's treated as a value by the compiler.
7222 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7223 eclass = ExprClass.Value;
7227 static bool ContainsDynamicType (TypeSpec type)
7229 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7232 var element_container = type as ElementTypeSpec;
7233 if (element_container != null)
7234 return ContainsDynamicType (element_container.Element);
7236 foreach (var t in type.TypeArguments) {
7237 if (ContainsDynamicType (t)) {
7245 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7247 // Target type is not System.Type therefore must be object
7248 // and we need to use different encoding sequence
7249 if (targetType != type)
7252 if (typearg is InflatedTypeSpec) {
7255 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
7256 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7257 typearg.GetSignatureForError ());
7261 gt = gt.DeclaringType;
7262 } while (gt != null);
7265 if (ContainsDynamicType (typearg)) {
7266 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7270 enc.EncodeTypeName (typearg);
7273 public override void Emit (EmitContext ec)
7275 ec.Emit (OpCodes.Ldtoken, typearg);
7276 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7278 ec.Emit (OpCodes.Call, m);
7282 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
7284 public TypeOfMethod (MethodSpec method, Location loc)
7285 : base (method, loc)
7289 protected override Expression DoResolve (ResolveContext ec)
7291 if (member.IsConstructor) {
7292 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
7294 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
7300 return base.DoResolve (ec);
7303 public override void Emit (EmitContext ec)
7305 ec.Emit (OpCodes.Ldtoken, member);
7308 ec.Emit (OpCodes.Castclass, type);
7311 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7313 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
7316 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7318 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
7322 abstract class TypeOfMember<T> : Expression where T : MemberSpec
7324 protected readonly T member;
7326 protected TypeOfMember (T member, Location loc)
7328 this.member = member;
7332 public override bool IsSideEffectFree {
7338 public override bool ContainsEmitWithAwait ()
7343 public override Expression CreateExpressionTree (ResolveContext ec)
7345 Arguments args = new Arguments (2);
7346 args.Add (new Argument (this));
7347 args.Add (new Argument (new TypeOf (type, loc)));
7348 return CreateExpressionFactoryCall (ec, "Constant", args);
7351 protected override Expression DoResolve (ResolveContext ec)
7353 eclass = ExprClass.Value;
7357 public override void Emit (EmitContext ec)
7359 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
7360 PredefinedMember<MethodSpec> p;
7362 p = GetTypeFromHandleGeneric (ec);
7363 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
7365 p = GetTypeFromHandle (ec);
7368 var mi = p.Resolve (loc);
7370 ec.Emit (OpCodes.Call, mi);
7373 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
7374 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
7377 sealed class TypeOfField : TypeOfMember<FieldSpec>
7379 public TypeOfField (FieldSpec field, Location loc)
7384 protected override Expression DoResolve (ResolveContext ec)
7386 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
7390 return base.DoResolve (ec);
7393 public override void Emit (EmitContext ec)
7395 ec.Emit (OpCodes.Ldtoken, member);
7399 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7401 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
7404 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7406 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
7411 /// Implements the sizeof expression
7413 public class SizeOf : Expression {
7414 readonly Expression QueriedType;
7415 TypeSpec type_queried;
7417 public SizeOf (Expression queried_type, Location l)
7419 this.QueriedType = queried_type;
7423 public override bool IsSideEffectFree {
7429 public override bool ContainsEmitWithAwait ()
7434 public override Expression CreateExpressionTree (ResolveContext ec)
7436 Error_PointerInsideExpressionTree (ec);
7440 protected override Expression DoResolve (ResolveContext ec)
7442 type_queried = QueriedType.ResolveAsType (ec);
7443 if (type_queried == null)
7446 if (type_queried.IsEnum)
7447 type_queried = EnumSpec.GetUnderlyingType (type_queried);
7449 int size_of = BuiltinTypeSpec.GetSize (type_queried);
7451 return new IntConstant (ec.BuiltinTypes, size_of, loc);
7454 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
7459 ec.Report.Error (233, loc,
7460 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7461 TypeManager.CSharpName (type_queried));
7464 type = ec.BuiltinTypes.Int;
7465 eclass = ExprClass.Value;
7469 public override void Emit (EmitContext ec)
7471 ec.Emit (OpCodes.Sizeof, type_queried);
7474 protected override void CloneTo (CloneContext clonectx, Expression t)
7480 /// Implements the qualified-alias-member (::) expression.
7482 public class QualifiedAliasMember : MemberAccess
7484 readonly string alias;
7485 public static readonly string GlobalAlias = "global";
7487 public QualifiedAliasMember (string alias, string identifier, Location l)
7488 : base (null, identifier, l)
7493 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7494 : base (null, identifier, targs, l)
7499 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
7500 : base (null, identifier, arity, l)
7505 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
7507 if (alias == GlobalAlias) {
7508 expr = ec.Module.GlobalRootNamespace;
7509 return base.ResolveAsTypeOrNamespace (ec);
7512 int errors = ec.Module.Compiler.Report.Errors;
7513 expr = ec.LookupNamespaceAlias (alias);
7515 if (errors == ec.Module.Compiler.Report.Errors)
7516 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7520 FullNamedExpression fne = base.ResolveAsTypeOrNamespace (ec);
7524 if (expr.eclass == ExprClass.Type) {
7525 ec.Module.Compiler.Report.Error (431, loc,
7526 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7534 protected override Expression DoResolve (ResolveContext ec)
7536 return ResolveAsTypeOrNamespace (ec);
7539 protected override void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7541 rc.Module.Compiler.Report.Error (687, loc,
7542 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7543 GetSignatureForError ());
7546 public override string GetSignatureForError ()
7549 if (targs != null) {
7550 name = Name + "<" + targs.GetSignatureForError () + ">";
7553 return alias + "::" + name;
7556 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7558 return DoResolve (rc);
7561 protected override void CloneTo (CloneContext clonectx, Expression t)
7568 /// Implements the member access expression
7570 public class MemberAccess : ATypeNameExpression
7572 protected Expression expr;
7574 public MemberAccess (Expression expr, string id)
7575 : base (id, expr.Location)
7580 public MemberAccess (Expression expr, string identifier, Location loc)
7581 : base (identifier, loc)
7586 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7587 : base (identifier, args, loc)
7592 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
7593 : base (identifier, arity, loc)
7598 public Expression LeftExpression {
7604 protected override Expression DoResolve (ResolveContext rc)
7606 var e = DoResolveName (rc, null);
7608 if (!rc.OmitStructFlowAnalysis) {
7609 var fe = e as FieldExpr;
7611 fe.VerifyAssignedStructField (rc, null);
7618 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
7620 var e = DoResolveName (rc, rhs);
7622 if (!rc.OmitStructFlowAnalysis) {
7623 var fe = e as FieldExpr;
7624 if (fe != null && fe.InstanceExpression is FieldExpr) {
7625 fe = (FieldExpr) fe.InstanceExpression;
7626 fe.VerifyAssignedStructField (rc, rhs);
7633 Expression DoResolveName (ResolveContext rc, Expression right_side)
7635 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
7639 if (right_side != null) {
7640 if (e is TypeExpr) {
7641 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
7645 e = e.ResolveLValue (rc, right_side);
7647 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
7653 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
7655 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
7656 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
7658 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
7661 public static bool IsValidDotExpression (TypeSpec type)
7663 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
7664 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
7666 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7669 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7671 var sn = expr as SimpleName;
7672 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
7675 // Resolve the expression with flow analysis turned off, we'll do the definite
7676 // assignment checks later. This is because we don't know yet what the expression
7677 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7678 // definite assignment check on the actual field and not on the whole struct.
7680 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
7682 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
7685 // Resolve expression which does have type set as we need expression type
7686 // with disable flow analysis as we don't know whether left side expression
7687 // is used as variable or type
7689 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
7690 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
7691 expr = expr.Resolve (rc);
7693 } else if (expr is TypeParameterExpr) {
7694 expr.Error_UnexpectedKind (rc, flags, sn.Location);
7698 expr = expr.Resolve (rc, flags);
7705 Namespace ns = expr as Namespace;
7707 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
7709 if (retval == null) {
7710 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
7714 if (HasTypeArguments)
7715 return new GenericTypeExpr (retval.Type, targs, loc);
7721 TypeSpec expr_type = expr.Type;
7722 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7723 me = expr as MemberExpr;
7725 me.ResolveInstanceExpression (rc, null);
7728 // Run defined assigned checks on expressions resolved with
7729 // disabled flow-analysis
7732 var vr = expr as VariableReference;
7734 vr.VerifyAssigned (rc);
7737 Arguments args = new Arguments (1);
7738 args.Add (new Argument (expr));
7739 return new DynamicMemberBinder (Name, args, loc);
7742 if (!IsValidDotExpression (expr_type)) {
7743 Error_OperatorCannotBeApplied (rc, expr_type);
7747 var lookup_arity = Arity;
7748 bool errorMode = false;
7749 Expression member_lookup;
7751 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
7752 if (member_lookup == null) {
7754 // Try to look for extension method when member lookup failed
7756 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
7757 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
7758 if (methods != null) {
7759 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
7760 if (HasTypeArguments) {
7761 if (!targs.Resolve (rc))
7764 emg.SetTypeArguments (rc, targs);
7768 // Run defined assigned checks on expressions resolved with
7769 // disabled flow-analysis
7771 if (sn != null && !errorMode) {
7772 var vr = expr as VariableReference;
7774 vr.VerifyAssigned (rc);
7777 // TODO: it should really skip the checks bellow
7778 return emg.Resolve (rc);
7784 if (member_lookup == null) {
7785 var dep = expr_type.GetMissingDependencies ();
7787 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
7788 } else if (expr is TypeExpr) {
7789 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
7791 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
7797 if (member_lookup is MethodGroupExpr) {
7798 // Leave it to overload resolution to report correct error
7799 } else if (!(member_lookup is TypeExpr)) {
7800 // TODO: rc.SymbolRelatedToPreviousError
7801 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
7806 if (member_lookup != null)
7810 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
7814 TypeExpr texpr = member_lookup as TypeExpr;
7815 if (texpr != null) {
7816 if (!(expr is TypeExpr)) {
7817 me = expr as MemberExpr;
7818 if (me == null || me.ProbeIdenticalTypeName (rc, expr, sn) == expr) {
7819 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7820 Name, member_lookup.GetSignatureForError ());
7825 if (!texpr.Type.IsAccessible (rc)) {
7826 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
7827 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
7831 if (HasTypeArguments) {
7832 return new GenericTypeExpr (member_lookup.Type, targs, loc);
7835 return member_lookup;
7838 me = member_lookup as MemberExpr;
7840 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
7844 me = me.ResolveMemberAccess (rc, expr, sn);
7847 if (!targs.Resolve (rc))
7850 me.SetTypeArguments (rc, targs);
7854 // Run defined assigned checks on expressions resolved with
7855 // disabled flow-analysis
7857 if (sn != null && !(me is FieldExpr && TypeSpec.IsValueType (expr_type))) {
7858 var vr = expr as VariableReference;
7860 vr.VerifyAssigned (rc);
7866 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
7868 FullNamedExpression fexpr = expr as FullNamedExpression;
7869 if (fexpr == null) {
7870 expr.ResolveAsType (rc);
7874 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
7876 if (expr_resolved == null)
7879 Namespace ns = expr_resolved as Namespace;
7881 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
7883 if (retval == null) {
7884 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
7885 } else if (HasTypeArguments) {
7886 retval = new GenericTypeExpr (retval.Type, targs, loc);
7887 if (retval.ResolveAsType (rc) == null)
7894 var tnew_expr = expr_resolved.ResolveAsType (rc);
7895 if (tnew_expr == null)
7898 TypeSpec expr_type = tnew_expr;
7899 if (TypeManager.IsGenericParameter (expr_type)) {
7900 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7901 tnew_expr.GetSignatureForError ());
7905 TypeSpec nested = null;
7906 while (expr_type != null) {
7907 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7908 if (nested == null) {
7909 if (expr_type == tnew_expr) {
7910 Error_IdentifierNotFound (rc, expr_type, Name);
7914 expr_type = tnew_expr;
7915 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7916 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
7920 if (nested.IsAccessible (rc))
7924 // Keep looking after inaccessible candidate but only if
7925 // we are not in same context as the definition itself
7927 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
7930 expr_type = expr_type.BaseType;
7935 if (HasTypeArguments) {
7936 texpr = new GenericTypeExpr (nested, targs, loc);
7938 texpr = new GenericOpenTypeExpr (nested, loc);
7941 texpr = new TypeExpression (nested, loc);
7944 if (texpr.ResolveAsType (rc) == null)
7950 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7952 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
7954 if (nested != null) {
7955 Error_TypeArgumentsCannotBeUsed (rc, nested, Arity, expr.Location);
7959 var any_other_member = MemberLookup (rc, true, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
7960 if (any_other_member != null) {
7961 any_other_member.Error_UnexpectedKind (rc.Module.Compiler.Report, null, "type", loc);
7965 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7966 Name, expr_type.GetSignatureForError ());
7969 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
7971 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
7972 ec.Report.SymbolRelatedToPreviousError (type);
7973 ec.Report.Error (1061, loc,
7974 "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?)",
7975 type.GetSignatureForError (), name);
7979 base.Error_TypeDoesNotContainDefinition (ec, type, name);
7982 public override string GetSignatureForError ()
7984 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7987 protected override void CloneTo (CloneContext clonectx, Expression t)
7989 MemberAccess target = (MemberAccess) t;
7991 target.expr = expr.Clone (clonectx);
7996 /// Implements checked expressions
7998 public class CheckedExpr : Expression {
8000 public Expression Expr;
8002 public CheckedExpr (Expression e, Location l)
8008 public override bool ContainsEmitWithAwait ()
8010 return Expr.ContainsEmitWithAwait ();
8013 public override Expression CreateExpressionTree (ResolveContext ec)
8015 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
8016 return Expr.CreateExpressionTree (ec);
8019 protected override Expression DoResolve (ResolveContext ec)
8021 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
8022 Expr = Expr.Resolve (ec);
8027 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8030 eclass = Expr.eclass;
8035 public override void Emit (EmitContext ec)
8037 using (ec.With (EmitContext.Options.CheckedScope, true))
8041 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8043 using (ec.With (EmitContext.Options.CheckedScope, true))
8044 Expr.EmitBranchable (ec, target, on_true);
8047 public override SLE.Expression MakeExpression (BuilderContext ctx)
8049 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
8050 return Expr.MakeExpression (ctx);
8054 protected override void CloneTo (CloneContext clonectx, Expression t)
8056 CheckedExpr target = (CheckedExpr) t;
8058 target.Expr = Expr.Clone (clonectx);
8063 /// Implements the unchecked expression
8065 public class UnCheckedExpr : Expression {
8067 public Expression Expr;
8069 public UnCheckedExpr (Expression e, Location l)
8075 public override bool ContainsEmitWithAwait ()
8077 return Expr.ContainsEmitWithAwait ();
8080 public override Expression CreateExpressionTree (ResolveContext ec)
8082 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8083 return Expr.CreateExpressionTree (ec);
8086 protected override Expression DoResolve (ResolveContext ec)
8088 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8089 Expr = Expr.Resolve (ec);
8094 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8097 eclass = Expr.eclass;
8102 public override void Emit (EmitContext ec)
8104 using (ec.With (EmitContext.Options.CheckedScope, false))
8108 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8110 using (ec.With (EmitContext.Options.CheckedScope, false))
8111 Expr.EmitBranchable (ec, target, on_true);
8114 protected override void CloneTo (CloneContext clonectx, Expression t)
8116 UnCheckedExpr target = (UnCheckedExpr) t;
8118 target.Expr = Expr.Clone (clonectx);
8123 /// An Element Access expression.
8125 /// During semantic analysis these are transformed into
8126 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
8128 public class ElementAccess : Expression
8130 public Arguments Arguments;
8131 public Expression Expr;
8133 public ElementAccess (Expression e, Arguments args, Location loc)
8137 this.Arguments = args;
8140 public override bool ContainsEmitWithAwait ()
8142 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
8146 // We perform some simple tests, and then to "split" the emit and store
8147 // code we create an instance of a different class, and return that.
8149 Expression CreateAccessExpression (ResolveContext ec)
8152 return (new ArrayAccess (this, loc));
8155 return MakePointerAccess (ec, type);
8157 FieldExpr fe = Expr as FieldExpr;
8159 var ff = fe.Spec as FixedFieldSpec;
8161 return MakePointerAccess (ec, ff.ElementType);
8165 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
8166 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8167 return new IndexerExpr (indexers, type, this);
8170 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8171 type.GetSignatureForError ());
8175 public override Expression CreateExpressionTree (ResolveContext ec)
8177 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
8178 Expr.CreateExpressionTree (ec));
8180 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
8183 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
8185 if (Arguments.Count != 1){
8186 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
8190 if (Arguments [0] is NamedArgument)
8191 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
8193 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
8194 return new Indirection (p, loc);
8197 protected override Expression DoResolve (ResolveContext ec)
8199 Expr = Expr.Resolve (ec);
8205 // TODO: Create 1 result for Resolve and ResolveLValue ?
8206 var res = CreateAccessExpression (ec);
8210 return res.Resolve (ec);
8213 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
8215 Expr = Expr.Resolve (ec);
8221 var res = CreateAccessExpression (ec);
8225 bool lvalue_instance = rhs != null && type.IsStruct && (Expr is Invocation || Expr is PropertyExpr);
8226 if (lvalue_instance) {
8227 Expr.Error_ValueAssignment (ec, EmptyExpression.LValueMemberAccess);
8230 return res.ResolveLValue (ec, rhs);
8233 public override void Emit (EmitContext ec)
8235 throw new Exception ("Should never be reached");
8238 public static void Error_NamedArgument (NamedArgument na, Report Report)
8240 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
8243 public override string GetSignatureForError ()
8245 return Expr.GetSignatureForError ();
8248 protected override void CloneTo (CloneContext clonectx, Expression t)
8250 ElementAccess target = (ElementAccess) t;
8252 target.Expr = Expr.Clone (clonectx);
8253 if (Arguments != null)
8254 target.Arguments = Arguments.Clone (clonectx);
8259 /// Implements array access
8261 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
8263 // Points to our "data" repository
8267 LocalTemporary temp;
8269 bool? has_await_args;
8271 public ArrayAccess (ElementAccess ea_data, Location l)
8277 public void AddressOf (EmitContext ec, AddressOp mode)
8279 var ac = (ArrayContainer) ea.Expr.Type;
8281 LoadInstanceAndArguments (ec, false, false);
8283 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
8284 ec.Emit (OpCodes.Readonly);
8286 ec.EmitArrayAddress (ac);
8289 public override Expression CreateExpressionTree (ResolveContext ec)
8291 return ea.CreateExpressionTree (ec);
8294 public override bool ContainsEmitWithAwait ()
8296 return ea.ContainsEmitWithAwait ();
8299 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8301 return DoResolve (ec);
8304 protected override Expression DoResolve (ResolveContext ec)
8306 // dynamic is used per argument in ConvertExpressionToArrayIndex case
8308 ea.Arguments.Resolve (ec, out dynamic);
8310 var ac = ea.Expr.Type as ArrayContainer;
8311 int rank = ea.Arguments.Count;
8312 if (ac.Rank != rank) {
8313 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8314 rank.ToString (), ac.Rank.ToString ());
8319 if (type.IsPointer && !ec.IsUnsafe) {
8320 UnsafeError (ec, ea.Location);
8323 foreach (Argument a in ea.Arguments) {
8324 if (a is NamedArgument)
8325 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
8327 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
8330 eclass = ExprClass.Variable;
8335 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8337 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8341 // Load the array arguments into the stack.
8343 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
8346 ea.Expr = ea.Expr.EmitToField (ec);
8347 } else if (duplicateArguments) {
8349 ec.Emit (OpCodes.Dup);
8351 var copy = new LocalTemporary (ea.Expr.Type);
8358 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
8359 if (dup_args != null)
8360 ea.Arguments = dup_args;
8363 public void Emit (EmitContext ec, bool leave_copy)
8365 var ac = ea.Expr.Type as ArrayContainer;
8368 ec.EmitLoadFromPtr (type);
8370 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
8371 LoadInstanceAndArguments (ec, false, true);
8374 LoadInstanceAndArguments (ec, false, false);
8375 ec.EmitArrayLoad (ac);
8379 ec.Emit (OpCodes.Dup);
8380 temp = new LocalTemporary (this.type);
8385 public override void Emit (EmitContext ec)
8390 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8392 var ac = (ArrayContainer) ea.Expr.Type;
8393 TypeSpec t = source.Type;
8395 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
8398 // When we are dealing with a struct, get the address of it to avoid value copy
8399 // Same cannot be done for reference type because array covariance and the
8400 // check in ldelema requires to specify the type of array element stored at the index
8402 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
8403 LoadInstanceAndArguments (ec, false, has_await_args.Value);
8405 if (has_await_args.Value) {
8406 if (source.ContainsEmitWithAwait ()) {
8407 source = source.EmitToField (ec);
8412 LoadInstanceAndArguments (ec, isCompound, false);
8417 ec.EmitArrayAddress (ac);
8420 ec.Emit (OpCodes.Dup);
8424 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
8426 if (has_await_args.Value) {
8427 if (source.ContainsEmitWithAwait ())
8428 source = source.EmitToField (ec);
8430 LoadInstanceAndArguments (ec, false, false);
8437 var lt = ea.Expr as LocalTemporary;
8443 ec.Emit (OpCodes.Dup);
8444 temp = new LocalTemporary (this.type);
8449 ec.EmitStoreFromPtr (t);
8451 ec.EmitArrayStore (ac);
8460 public override Expression EmitToField (EmitContext ec)
8463 // Have to be specialized for arrays to get access to
8464 // underlying element. Instead of another result copy we
8465 // need direct access to element
8469 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
8471 ea.Expr = ea.Expr.EmitToField (ec);
8475 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8478 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8480 throw new NotImplementedException ();
8484 public override SLE.Expression MakeExpression (BuilderContext ctx)
8486 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8489 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
8491 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
8492 return Arguments.MakeExpression (ea.Arguments, ctx);
8498 // Indexer access expression
8500 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
8502 IList<MemberSpec> indexers;
8503 Arguments arguments;
8504 TypeSpec queried_type;
8506 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
8507 : base (ea.Location)
8509 this.indexers = indexers;
8510 this.queried_type = queriedType;
8511 this.InstanceExpression = ea.Expr;
8512 this.arguments = ea.Arguments;
8517 protected override Arguments Arguments {
8526 protected override TypeSpec DeclaringType {
8528 return best_candidate.DeclaringType;
8532 public override bool IsInstance {
8538 public override bool IsStatic {
8544 public override string Name {
8552 public override bool ContainsEmitWithAwait ()
8554 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
8557 public override Expression CreateExpressionTree (ResolveContext ec)
8559 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8560 InstanceExpression.CreateExpressionTree (ec),
8561 new TypeOfMethod (Getter, loc));
8563 return CreateExpressionFactoryCall (ec, "Call", args);
8566 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8568 LocalTemporary await_source_arg = null;
8571 emitting_compound_assignment = true;
8572 if (source is DynamicExpressionStatement) {
8577 emitting_compound_assignment = false;
8579 if (has_await_arguments) {
8580 await_source_arg = new LocalTemporary (Type);
8581 await_source_arg.Store (ec);
8583 arguments.Add (new Argument (await_source_arg));
8586 temp = await_source_arg;
8589 has_await_arguments = false;
8594 ec.Emit (OpCodes.Dup);
8595 temp = new LocalTemporary (Type);
8601 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
8602 source = source.EmitToField (ec);
8604 temp = new LocalTemporary (Type);
8611 arguments.Add (new Argument (source));
8614 var call = new CallEmitter ();
8615 call.InstanceExpression = InstanceExpression;
8616 if (arguments == null)
8617 call.InstanceExpressionOnStack = true;
8619 call.Emit (ec, Setter, arguments, loc);
8624 } else if (leave_copy) {
8628 if (await_source_arg != null) {
8629 await_source_arg.Release (ec);
8633 public override string GetSignatureForError ()
8635 return best_candidate.GetSignatureForError ();
8638 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8641 throw new NotSupportedException ();
8643 var value = new[] { source.MakeExpression (ctx) };
8644 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
8646 return SLE.Expression.Block (
8647 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
8650 return args.First ();
8655 public override SLE.Expression MakeExpression (BuilderContext ctx)
8658 return base.MakeExpression (ctx);
8660 var args = Arguments.MakeExpression (arguments, ctx);
8661 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
8665 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
8667 if (best_candidate != null)
8670 eclass = ExprClass.IndexerAccess;
8673 arguments.Resolve (rc, out dynamic);
8675 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8678 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
8679 res.BaseMembersProvider = this;
8681 // TODO: Do I need 2 argument sets?
8682 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
8683 if (best_candidate != null)
8684 type = res.BestCandidateReturnType;
8685 else if (!res.BestCandidateIsDynamic)
8690 // It has dynamic arguments
8693 Arguments args = new Arguments (arguments.Count + 1);
8695 rc.Report.Error (1972, loc,
8696 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8698 args.Add (new Argument (InstanceExpression));
8700 args.AddRange (arguments);
8702 best_candidate = null;
8703 return new DynamicIndexBinder (args, loc);
8707 // Try to avoid resolving left expression again
8709 if (right_side != null)
8710 ResolveInstanceExpression (rc, right_side);
8712 CheckProtectedMemberAccess (rc, best_candidate);
8716 protected override void CloneTo (CloneContext clonectx, Expression t)
8718 IndexerExpr target = (IndexerExpr) t;
8720 if (arguments != null)
8721 target.arguments = arguments.Clone (clonectx);
8724 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
8726 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
8729 #region IBaseMembersProvider Members
8731 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
8733 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
8736 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
8738 if (queried_type == member.DeclaringType)
8741 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
8742 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
8745 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
8754 // A base access expression
8756 public class BaseThis : This
8758 public BaseThis (Location loc)
8763 public BaseThis (TypeSpec type, Location loc)
8767 eclass = ExprClass.Variable;
8772 public override string Name {
8780 public override Expression CreateExpressionTree (ResolveContext ec)
8782 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
8783 return base.CreateExpressionTree (ec);
8786 public override void Emit (EmitContext ec)
8790 var context_type = ec.CurrentType;
8791 if (context_type.IsStruct) {
8792 ec.Emit (OpCodes.Ldobj, context_type);
8793 ec.Emit (OpCodes.Box, context_type);
8797 protected override void Error_ThisNotAvailable (ResolveContext ec)
8800 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
8802 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
8806 public override void ResolveBase (ResolveContext ec)
8808 base.ResolveBase (ec);
8809 type = ec.CurrentType.BaseType;
8814 /// This class exists solely to pass the Type around and to be a dummy
8815 /// that can be passed to the conversion functions (this is used by
8816 /// foreach implementation to typecast the object return value from
8817 /// get_Current into the proper type. All code has been generated and
8818 /// we only care about the side effect conversions to be performed
8820 /// This is also now used as a placeholder where a no-action expression
8821 /// is needed (the `New' class).
8823 class EmptyExpression : Expression
8825 sealed class OutAccessExpression : EmptyExpression
8827 public OutAccessExpression (TypeSpec t)
8832 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8834 rc.Report.Error (206, right_side.Location,
8835 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
8841 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
8842 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
8843 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
8844 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
8845 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
8846 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
8847 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
8848 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
8850 public EmptyExpression (TypeSpec t)
8853 eclass = ExprClass.Value;
8854 loc = Location.Null;
8857 public override bool ContainsEmitWithAwait ()
8862 public override Expression CreateExpressionTree (ResolveContext ec)
8864 throw new NotSupportedException ("ET");
8867 protected override Expression DoResolve (ResolveContext ec)
8872 public override void Emit (EmitContext ec)
8874 // nothing, as we only exist to not do anything.
8877 public override void EmitSideEffect (EmitContext ec)
8882 sealed class EmptyAwaitExpression : EmptyExpression
8884 public EmptyAwaitExpression (TypeSpec type)
8889 public override bool ContainsEmitWithAwait ()
8896 // Empty statement expression
8898 public sealed class EmptyExpressionStatement : ExpressionStatement
8900 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8902 private EmptyExpressionStatement ()
8904 loc = Location.Null;
8907 public override bool ContainsEmitWithAwait ()
8912 public override Expression CreateExpressionTree (ResolveContext ec)
8917 public override void EmitStatement (EmitContext ec)
8922 protected override Expression DoResolve (ResolveContext ec)
8924 eclass = ExprClass.Value;
8925 type = ec.BuiltinTypes.Object;
8929 public override void Emit (EmitContext ec)
8935 class ErrorExpression : EmptyExpression
8937 public static readonly ErrorExpression Instance = new ErrorExpression ();
8939 private ErrorExpression ()
8940 : base (InternalType.ErrorType)
8944 public override Expression CreateExpressionTree (ResolveContext ec)
8949 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8954 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
8958 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
8962 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
8967 public class UserCast : Expression {
8971 public UserCast (MethodSpec method, Expression source, Location l)
8973 this.method = method;
8974 this.source = source;
8975 type = method.ReturnType;
8979 public Expression Source {
8985 public override bool ContainsEmitWithAwait ()
8987 return source.ContainsEmitWithAwait ();
8990 public override Expression CreateExpressionTree (ResolveContext ec)
8992 Arguments args = new Arguments (3);
8993 args.Add (new Argument (source.CreateExpressionTree (ec)));
8994 args.Add (new Argument (new TypeOf (type, loc)));
8995 args.Add (new Argument (new TypeOfMethod (method, loc)));
8996 return CreateExpressionFactoryCall (ec, "Convert", args);
8999 protected override Expression DoResolve (ResolveContext ec)
9001 ObsoleteAttribute oa = method.GetAttributeObsolete ();
9003 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
9005 eclass = ExprClass.Value;
9009 public override void Emit (EmitContext ec)
9012 ec.Emit (OpCodes.Call, method);
9015 public override string GetSignatureForError ()
9017 return TypeManager.CSharpSignature (method);
9020 public override SLE.Expression MakeExpression (BuilderContext ctx)
9023 return base.MakeExpression (ctx);
9025 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
9031 // Holds additional type specifiers like ?, *, []
9033 public class ComposedTypeSpecifier
9035 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
9037 public readonly int Dimension;
9038 public readonly Location Location;
9040 public ComposedTypeSpecifier (int specifier, Location loc)
9042 this.Dimension = specifier;
9043 this.Location = loc;
9047 public bool IsNullable {
9049 return Dimension == -1;
9053 public bool IsPointer {
9055 return Dimension == -2;
9059 public ComposedTypeSpecifier Next { get; set; }
9063 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
9065 return new ComposedTypeSpecifier (dimension, loc);
9068 public static ComposedTypeSpecifier CreateNullable (Location loc)
9070 return new ComposedTypeSpecifier (-1, loc);
9073 public static ComposedTypeSpecifier CreatePointer (Location loc)
9075 return new ComposedTypeSpecifier (-2, loc);
9078 public string GetSignatureForError ()
9083 ArrayContainer.GetPostfixSignature (Dimension);
9085 return Next != null ? s + Next.GetSignatureForError () : s;
9090 // This class is used to "construct" the type during a typecast
9091 // operation. Since the Type.GetType class in .NET can parse
9092 // the type specification, we just use this to construct the type
9093 // one bit at a time.
9095 public class ComposedCast : TypeExpr {
9096 FullNamedExpression left;
9097 ComposedTypeSpecifier spec;
9099 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
9102 throw new ArgumentNullException ("spec");
9106 this.loc = spec.Location;
9109 public override TypeSpec ResolveAsType (IMemberContext ec)
9111 type = left.ResolveAsType (ec);
9115 eclass = ExprClass.Type;
9117 var single_spec = spec;
9119 if (single_spec.IsNullable) {
9120 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
9124 single_spec = single_spec.Next;
9125 } else if (single_spec.IsPointer) {
9126 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
9130 UnsafeError (ec.Module.Compiler.Report, loc);
9134 type = PointerContainer.MakeType (ec.Module, type);
9135 single_spec = single_spec.Next;
9136 } while (single_spec != null && single_spec.IsPointer);
9139 if (single_spec != null && single_spec.Dimension > 0) {
9140 if (type.IsSpecialRuntimeType) {
9141 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
9142 } else if (type.IsStatic) {
9143 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
9144 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9145 type.GetSignatureForError ());
9147 MakeArray (ec.Module, single_spec);
9154 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
9156 if (spec.Next != null)
9157 MakeArray (module, spec.Next);
9159 type = ArrayContainer.MakeType (module, type, spec.Dimension);
9162 public override string GetSignatureForError ()
9164 return left.GetSignatureForError () + spec.GetSignatureForError ();
9168 class FixedBufferPtr : Expression
9170 readonly Expression array;
9172 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
9174 this.type = array_type;
9179 public override bool ContainsEmitWithAwait ()
9181 throw new NotImplementedException ();
9184 public override Expression CreateExpressionTree (ResolveContext ec)
9186 Error_PointerInsideExpressionTree (ec);
9190 public override void Emit(EmitContext ec)
9195 protected override Expression DoResolve (ResolveContext ec)
9197 type = PointerContainer.MakeType (ec.Module, type);
9198 eclass = ExprClass.Value;
9205 // This class is used to represent the address of an array, used
9206 // only by the Fixed statement, this generates "&a [0]" construct
9207 // for fixed (char *pa = a)
9209 class ArrayPtr : FixedBufferPtr
9211 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
9212 base (array, array_type, l)
9216 public override void Emit (EmitContext ec)
9221 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
9226 // Encapsulates a conversion rules required for array indexes
9228 public class ArrayIndexCast : TypeCast
9230 public ArrayIndexCast (Expression expr, TypeSpec returnType)
9231 : base (expr, returnType)
9233 if (expr.Type == returnType) // int -> int
9234 throw new ArgumentException ("unnecessary array index conversion");
9237 public override Expression CreateExpressionTree (ResolveContext ec)
9239 using (ec.Set (ResolveContext.Options.CheckedScope)) {
9240 return base.CreateExpressionTree (ec);
9244 public override void Emit (EmitContext ec)
9248 switch (child.Type.BuiltinType) {
9249 case BuiltinTypeSpec.Type.UInt:
9250 ec.Emit (OpCodes.Conv_U);
9252 case BuiltinTypeSpec.Type.Long:
9253 ec.Emit (OpCodes.Conv_Ovf_I);
9255 case BuiltinTypeSpec.Type.ULong:
9256 ec.Emit (OpCodes.Conv_Ovf_I_Un);
9259 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9265 // Implements the `stackalloc' keyword
9267 public class StackAlloc : Expression {
9272 public StackAlloc (Expression type, Expression count, Location l)
9279 public override bool ContainsEmitWithAwait ()
9284 public override Expression CreateExpressionTree (ResolveContext ec)
9286 throw new NotSupportedException ("ET");
9289 protected override Expression DoResolve (ResolveContext ec)
9291 count = count.Resolve (ec);
9295 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
9296 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
9301 Constant c = count as Constant;
9302 if (c != null && c.IsNegative) {
9303 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9306 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9307 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9310 otype = t.ResolveAsType (ec);
9314 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
9317 type = PointerContainer.MakeType (ec.Module, otype);
9318 eclass = ExprClass.Value;
9323 public override void Emit (EmitContext ec)
9325 int size = BuiltinTypeSpec.GetSize (otype);
9330 ec.Emit (OpCodes.Sizeof, otype);
9334 ec.Emit (OpCodes.Mul_Ovf_Un);
9335 ec.Emit (OpCodes.Localloc);
9338 protected override void CloneTo (CloneContext clonectx, Expression t)
9340 StackAlloc target = (StackAlloc) t;
9341 target.count = count.Clone (clonectx);
9342 target.t = t.Clone (clonectx);
9347 // An object initializer expression
9349 public class ElementInitializer : Assign
9351 public readonly string Name;
9353 public ElementInitializer (string name, Expression initializer, Location loc)
9354 : base (null, initializer, loc)
9359 protected override void CloneTo (CloneContext clonectx, Expression t)
9361 ElementInitializer target = (ElementInitializer) t;
9362 target.source = source.Clone (clonectx);
9365 public override Expression CreateExpressionTree (ResolveContext ec)
9367 Arguments args = new Arguments (2);
9368 FieldExpr fe = target as FieldExpr;
9370 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9372 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9374 args.Add (new Argument (source.CreateExpressionTree (ec)));
9375 return CreateExpressionFactoryCall (ec,
9376 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9380 protected override Expression DoResolve (ResolveContext ec)
9383 return EmptyExpressionStatement.Instance;
9385 var t = ec.CurrentInitializerVariable.Type;
9386 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9387 Arguments args = new Arguments (1);
9388 args.Add (new Argument (ec.CurrentInitializerVariable));
9389 target = new DynamicMemberBinder (Name, args, loc);
9392 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9393 if (member == null) {
9394 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9396 if (member != null) {
9397 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
9398 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
9403 if (member == null) {
9404 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
9408 if (!(member is PropertyExpr || member is FieldExpr)) {
9409 ec.Report.Error (1913, loc,
9410 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
9411 member.GetSignatureForError ());
9416 var me = member as MemberExpr;
9418 ec.Report.Error (1914, loc,
9419 "Static field or property `{0}' cannot be assigned in an object initializer",
9420 me.GetSignatureForError ());
9424 me.InstanceExpression = ec.CurrentInitializerVariable;
9427 if (source is CollectionOrObjectInitializers) {
9428 Expression previous = ec.CurrentInitializerVariable;
9429 ec.CurrentInitializerVariable = target;
9430 source = source.Resolve (ec);
9431 ec.CurrentInitializerVariable = previous;
9435 eclass = source.eclass;
9440 return base.DoResolve (ec);
9443 public override void EmitStatement (EmitContext ec)
9445 if (source is CollectionOrObjectInitializers)
9448 base.EmitStatement (ec);
9453 // A collection initializer expression
9455 class CollectionElementInitializer : Invocation
9457 public class ElementInitializerArgument : Argument
9459 public ElementInitializerArgument (Expression e)
9465 sealed class AddMemberAccess : MemberAccess
9467 public AddMemberAccess (Expression expr, Location loc)
9468 : base (expr, "Add", loc)
9472 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9474 if (TypeManager.HasElementType (type))
9477 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9481 public CollectionElementInitializer (Expression argument)
9482 : base (null, new Arguments (1))
9484 base.arguments.Add (new ElementInitializerArgument (argument));
9485 this.loc = argument.Location;
9488 public CollectionElementInitializer (List<Expression> arguments, Location loc)
9489 : base (null, new Arguments (arguments.Count))
9491 foreach (Expression e in arguments)
9492 base.arguments.Add (new ElementInitializerArgument (e));
9497 public override Expression CreateExpressionTree (ResolveContext ec)
9499 Arguments args = new Arguments (2);
9500 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9502 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
9503 foreach (Argument a in arguments)
9504 expr_initializers.Add (a.CreateExpressionTree (ec));
9506 args.Add (new Argument (new ArrayCreation (
9507 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
9508 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9511 protected override void CloneTo (CloneContext clonectx, Expression t)
9513 CollectionElementInitializer target = (CollectionElementInitializer) t;
9514 if (arguments != null)
9515 target.arguments = arguments.Clone (clonectx);
9518 protected override Expression DoResolve (ResolveContext ec)
9520 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9522 return base.DoResolve (ec);
9527 // A block of object or collection initializers
9529 public class CollectionOrObjectInitializers : ExpressionStatement
9531 IList<Expression> initializers;
9532 bool is_collection_initialization;
9534 public static readonly CollectionOrObjectInitializers Empty =
9535 new CollectionOrObjectInitializers (Array.AsReadOnly (new Expression [0]), Location.Null);
9537 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
9539 this.initializers = initializers;
9543 public bool IsEmpty {
9545 return initializers.Count == 0;
9549 public bool IsCollectionInitializer {
9551 return is_collection_initialization;
9555 protected override void CloneTo (CloneContext clonectx, Expression target)
9557 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9559 t.initializers = new List<Expression> (initializers.Count);
9560 foreach (var e in initializers)
9561 t.initializers.Add (e.Clone (clonectx));
9564 public override bool ContainsEmitWithAwait ()
9566 foreach (var e in initializers) {
9567 if (e.ContainsEmitWithAwait ())
9574 public override Expression CreateExpressionTree (ResolveContext ec)
9576 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
9577 foreach (Expression e in initializers) {
9578 Expression expr = e.CreateExpressionTree (ec);
9580 expr_initializers.Add (expr);
9583 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
9586 protected override Expression DoResolve (ResolveContext ec)
9588 List<string> element_names = null;
9589 for (int i = 0; i < initializers.Count; ++i) {
9590 Expression initializer = initializers [i];
9591 ElementInitializer element_initializer = initializer as ElementInitializer;
9594 if (element_initializer != null) {
9595 element_names = new List<string> (initializers.Count);
9596 element_names.Add (element_initializer.Name);
9597 } else if (initializer is CompletingExpression){
9598 initializer.Resolve (ec);
9599 throw new InternalErrorException ("This line should never be reached");
9601 var t = ec.CurrentInitializerVariable.Type;
9602 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
9603 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
9604 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9605 "object initializer because type `{1}' does not implement `{2}' interface",
9606 ec.CurrentInitializerVariable.GetSignatureForError (),
9607 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9608 TypeManager.CSharpName (ec.BuiltinTypes.IEnumerable));
9611 is_collection_initialization = true;
9614 if (is_collection_initialization != (element_initializer == null)) {
9615 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9616 is_collection_initialization ? "collection initializer" : "object initializer");
9620 if (!is_collection_initialization) {
9621 if (element_names.Contains (element_initializer.Name)) {
9622 ec.Report.Error (1912, element_initializer.Location,
9623 "An object initializer includes more than one member `{0}' initialization",
9624 element_initializer.Name);
9626 element_names.Add (element_initializer.Name);
9631 Expression e = initializer.Resolve (ec);
9632 if (e == EmptyExpressionStatement.Instance)
9633 initializers.RemoveAt (i--);
9635 initializers [i] = e;
9638 type = ec.CurrentInitializerVariable.Type;
9639 if (is_collection_initialization) {
9640 if (TypeManager.HasElementType (type)) {
9641 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9642 TypeManager.CSharpName (type));
9646 eclass = ExprClass.Variable;
9650 public override void Emit (EmitContext ec)
9655 public override void EmitStatement (EmitContext ec)
9657 foreach (ExpressionStatement e in initializers)
9658 e.EmitStatement (ec);
9663 // New expression with element/object initializers
9665 public class NewInitialize : New
9668 // This class serves as a proxy for variable initializer target instances.
9669 // A real variable is assigned later when we resolve left side of an
9672 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9674 NewInitialize new_instance;
9676 public InitializerTargetExpression (NewInitialize newInstance)
9678 this.type = newInstance.type;
9679 this.loc = newInstance.loc;
9680 this.eclass = newInstance.eclass;
9681 this.new_instance = newInstance;
9684 public override bool ContainsEmitWithAwait ()
9689 public override Expression CreateExpressionTree (ResolveContext ec)
9691 // Should not be reached
9692 throw new NotSupportedException ("ET");
9695 protected override Expression DoResolve (ResolveContext ec)
9700 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9705 public override void Emit (EmitContext ec)
9707 Expression e = (Expression) new_instance.instance;
9711 public override Expression EmitToField (EmitContext ec)
9713 return (Expression) new_instance.instance;
9716 #region IMemoryLocation Members
9718 public void AddressOf (EmitContext ec, AddressOp mode)
9720 new_instance.instance.AddressOf (ec, mode);
9726 CollectionOrObjectInitializers initializers;
9727 IMemoryLocation instance;
9729 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9730 : base (requested_type, arguments, l)
9732 this.initializers = initializers;
9735 protected override void CloneTo (CloneContext clonectx, Expression t)
9737 base.CloneTo (clonectx, t);
9739 NewInitialize target = (NewInitialize) t;
9740 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9743 public override bool ContainsEmitWithAwait ()
9745 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
9748 public override Expression CreateExpressionTree (ResolveContext ec)
9750 Arguments args = new Arguments (2);
9751 args.Add (new Argument (base.CreateExpressionTree (ec)));
9752 if (!initializers.IsEmpty)
9753 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9755 return CreateExpressionFactoryCall (ec,
9756 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9760 protected override Expression DoResolve (ResolveContext ec)
9762 Expression e = base.DoResolve (ec);
9766 Expression previous = ec.CurrentInitializerVariable;
9767 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9768 initializers.Resolve (ec);
9769 ec.CurrentInitializerVariable = previous;
9773 public override bool Emit (EmitContext ec, IMemoryLocation target)
9775 bool left_on_stack = base.Emit (ec, target);
9777 if (initializers.IsEmpty)
9778 return left_on_stack;
9780 LocalTemporary temp = null;
9782 instance = target as LocalTemporary;
9784 if (instance == null) {
9785 if (!left_on_stack) {
9786 VariableReference vr = target as VariableReference;
9788 // FIXME: This still does not work correctly for pre-set variables
9789 if (vr != null && vr.IsRef)
9790 target.AddressOf (ec, AddressOp.Load);
9792 ((Expression) target).Emit (ec);
9793 left_on_stack = true;
9796 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
9797 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
9799 temp = new LocalTemporary (type);
9804 if (left_on_stack && temp != null)
9807 initializers.Emit (ec);
9809 if (left_on_stack) {
9814 ((Expression) instance).Emit (ec);
9818 return left_on_stack;
9821 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9823 instance = base.EmitAddressOf (ec, Mode);
9825 if (!initializers.IsEmpty)
9826 initializers.Emit (ec);
9832 public class NewAnonymousType : New
9834 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
9836 List<AnonymousTypeParameter> parameters;
9837 readonly TypeContainer parent;
9838 AnonymousTypeClass anonymous_type;
9840 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
9841 : base (null, null, loc)
9843 this.parameters = parameters;
9844 this.parent = parent;
9847 protected override void CloneTo (CloneContext clonectx, Expression target)
9849 if (parameters == null)
9852 NewAnonymousType t = (NewAnonymousType) target;
9853 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
9854 foreach (AnonymousTypeParameter atp in parameters)
9855 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
9858 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
9860 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
9864 type = AnonymousTypeClass.Create (parent, parameters, loc);
9870 type.ResolveTypeParameters ();
9873 if (ec.Report.Errors == 0)
9876 parent.Module.AddAnonymousType (type);
9880 public override Expression CreateExpressionTree (ResolveContext ec)
9882 if (parameters == null)
9883 return base.CreateExpressionTree (ec);
9885 var init = new ArrayInitializer (parameters.Count, loc);
9886 foreach (Property p in anonymous_type.Properties)
9887 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
9889 var ctor_args = new ArrayInitializer (arguments.Count, loc);
9890 foreach (Argument a in arguments)
9891 ctor_args.Add (a.CreateExpressionTree (ec));
9893 Arguments args = new Arguments (3);
9894 args.Add (new Argument (new TypeOfMethod (method, loc)));
9895 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
9896 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
9898 return CreateExpressionFactoryCall (ec, "New", args);
9901 protected override Expression DoResolve (ResolveContext ec)
9903 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
9904 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9908 if (parameters == null) {
9909 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
9910 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
9911 return base.DoResolve (ec);
9915 arguments = new Arguments (parameters.Count);
9916 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9917 for (int i = 0; i < parameters.Count; ++i) {
9918 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9924 arguments.Add (new Argument (e));
9925 t_args [i] = new TypeExpression (e.Type, e.Location);
9931 anonymous_type = CreateAnonymousType (ec, parameters);
9932 if (anonymous_type == null)
9935 RequestedType = new GenericTypeExpr (anonymous_type.Definition, new TypeArguments (t_args), loc);
9936 return base.DoResolve (ec);
9940 public class AnonymousTypeParameter : ShimExpression
9942 public readonly string Name;
9944 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9945 : base (initializer)
9951 public AnonymousTypeParameter (Parameter parameter)
9952 : base (new SimpleName (parameter.Name, parameter.Location))
9954 this.Name = parameter.Name;
9955 this.loc = parameter.Location;
9958 public override bool Equals (object o)
9960 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9961 return other != null && Name == other.Name;
9964 public override int GetHashCode ()
9966 return Name.GetHashCode ();
9969 protected override Expression DoResolve (ResolveContext ec)
9971 Expression e = expr.Resolve (ec);
9975 if (e.eclass == ExprClass.MethodGroup) {
9976 Error_InvalidInitializer (ec, e.ExprClassName);
9981 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
9982 Error_InvalidInitializer (ec, type.GetSignatureForError ());
9989 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
9991 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",