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;
20 using MetaType = IKVM.Reflection.Type;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using MetaType = System.Type;
25 using System.Reflection;
26 using System.Reflection.Emit;
32 // This is an user operator expression, automatically created during
35 public class UserOperatorCall : Expression {
36 protected readonly Arguments arguments;
37 protected readonly MethodSpec oper;
38 readonly Func<ResolveContext, Expression, Expression> expr_tree;
40 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
43 this.arguments = args;
44 this.expr_tree = expr_tree;
46 type = oper.ReturnType;
47 eclass = ExprClass.Value;
51 public override bool ContainsEmitWithAwait ()
53 return arguments.ContainsEmitWithAwait ();
56 public override Expression CreateExpressionTree (ResolveContext ec)
58 if (expr_tree != null)
59 return expr_tree (ec, new TypeOfMethod (oper, loc));
61 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
62 new NullLiteral (loc),
63 new TypeOfMethod (oper, loc));
65 return CreateExpressionFactoryCall (ec, "Call", args);
68 protected override void CloneTo (CloneContext context, Expression target)
73 protected override Expression DoResolve (ResolveContext ec)
76 // We are born fully resolved
81 public override void Emit (EmitContext ec)
83 var call = new CallEmitter ();
84 call.Emit (ec, oper, arguments, loc);
87 public override void FlowAnalysis (FlowAnalysisContext fc)
89 arguments.FlowAnalysis (fc);
92 public override SLE.Expression MakeExpression (BuilderContext ctx)
95 return base.MakeExpression (ctx);
97 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
102 public class ParenthesizedExpression : ShimExpression
104 bool conditional_access_receiver;
106 public ParenthesizedExpression (Expression expr, Location loc)
112 void ResolveConditionalAccessReceiver (ResolveContext rc)
114 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
115 conditional_access_receiver = true;
119 protected override Expression DoResolve (ResolveContext rc)
121 Expression res = null;
123 ResolveConditionalAccessReceiver (rc);
124 if (conditional_access_receiver) {
125 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
126 res = expr.Resolve (rc);
129 res = expr.Resolve (rc);
132 var constant = res as Constant;
133 if (constant != null && constant.IsLiteral)
134 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
136 if (conditional_access_receiver) {
138 type = LiftMemberType (rc, res.Type);
139 eclass = expr.eclass;
146 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
148 return expr.DoResolveLValue (ec, right_side);
151 public override object Accept (StructuralVisitor visitor)
153 return visitor.Visit (this);
156 public override void Emit (EmitContext ec)
158 if (!conditional_access_receiver)
161 var prev = ec.ConditionalAccess;
162 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
164 ec.CloseConditionalAccess (type.IsNullableType ? type : null);
165 ec.ConditionalAccess = prev;
168 public override bool HasConditionalAccess ()
175 // Unary implements unary expressions.
177 public class Unary : Expression
179 public enum Operator : byte {
180 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
184 public readonly Operator Oper;
185 public Expression Expr;
186 ConvCast.Mode enum_conversion;
188 public Unary (Operator op, Expression expr, Location loc)
196 // This routine will attempt to simplify the unary expression when the
197 // argument is a constant.
199 Constant TryReduceConstant (ResolveContext ec, Constant constant)
203 while (e is EmptyConstantCast)
204 e = ((EmptyConstantCast) e).child;
206 if (e is SideEffectConstant) {
207 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
208 return r == null ? null : new SideEffectConstant (r, e, r.Location);
211 TypeSpec expr_type = e.Type;
214 case Operator.UnaryPlus:
215 // Unary numeric promotions
216 switch (expr_type.BuiltinType) {
217 case BuiltinTypeSpec.Type.Byte:
218 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
219 case BuiltinTypeSpec.Type.SByte:
220 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
221 case BuiltinTypeSpec.Type.Short:
222 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
223 case BuiltinTypeSpec.Type.UShort:
224 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
225 case BuiltinTypeSpec.Type.Char:
226 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
228 // Predefined operators
229 case BuiltinTypeSpec.Type.Int:
230 case BuiltinTypeSpec.Type.UInt:
231 case BuiltinTypeSpec.Type.Long:
232 case BuiltinTypeSpec.Type.ULong:
233 case BuiltinTypeSpec.Type.Float:
234 case BuiltinTypeSpec.Type.Double:
235 case BuiltinTypeSpec.Type.Decimal:
241 case Operator.UnaryNegation:
242 // Unary numeric promotions
243 switch (expr_type.BuiltinType) {
244 case BuiltinTypeSpec.Type.Byte:
245 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
246 case BuiltinTypeSpec.Type.SByte:
247 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
248 case BuiltinTypeSpec.Type.Short:
249 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
250 case BuiltinTypeSpec.Type.UShort:
251 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
252 case BuiltinTypeSpec.Type.Char:
253 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
255 // Predefined operators
256 case BuiltinTypeSpec.Type.Int:
257 int ivalue = ((IntConstant) e).Value;
258 if (ivalue == int.MinValue) {
259 if (ec.ConstantCheckState) {
260 ConstantFold.Error_CompileTimeOverflow (ec, loc);
265 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
267 case BuiltinTypeSpec.Type.Long:
268 long lvalue = ((LongConstant) e).Value;
269 if (lvalue == long.MinValue) {
270 if (ec.ConstantCheckState) {
271 ConstantFold.Error_CompileTimeOverflow (ec, loc);
276 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
278 case BuiltinTypeSpec.Type.UInt:
279 UIntLiteral uil = constant as UIntLiteral;
281 if (uil.Value == int.MaxValue + (uint) 1)
282 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
283 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
285 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
288 case BuiltinTypeSpec.Type.ULong:
289 ULongLiteral ull = constant as ULongLiteral;
290 if (ull != null && ull.Value == 9223372036854775808)
291 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
294 case BuiltinTypeSpec.Type.Float:
295 FloatLiteral fl = constant as FloatLiteral;
296 // For better error reporting
298 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
300 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
302 case BuiltinTypeSpec.Type.Double:
303 DoubleLiteral dl = constant as DoubleLiteral;
304 // For better error reporting
306 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
308 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
310 case BuiltinTypeSpec.Type.Decimal:
311 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
316 case Operator.LogicalNot:
317 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
320 bool b = (bool)e.GetValue ();
321 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
323 case Operator.OnesComplement:
324 // Unary numeric promotions
325 switch (expr_type.BuiltinType) {
326 case BuiltinTypeSpec.Type.Byte:
327 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
328 case BuiltinTypeSpec.Type.SByte:
329 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
330 case BuiltinTypeSpec.Type.Short:
331 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
332 case BuiltinTypeSpec.Type.UShort:
333 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
334 case BuiltinTypeSpec.Type.Char:
335 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
337 // Predefined operators
338 case BuiltinTypeSpec.Type.Int:
339 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
340 case BuiltinTypeSpec.Type.UInt:
341 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
342 case BuiltinTypeSpec.Type.Long:
343 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
344 case BuiltinTypeSpec.Type.ULong:
345 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
347 if (e is EnumConstant) {
348 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
351 // Numeric promotion upgraded types to int but for enum constant
352 // original underlying constant type is needed
354 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
355 int v = ((IntConstant) res).Value;
356 switch (((EnumConstant) e).Child.Type.BuiltinType) {
357 case BuiltinTypeSpec.Type.UShort:
358 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
360 case BuiltinTypeSpec.Type.Short:
361 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
363 case BuiltinTypeSpec.Type.Byte:
364 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
366 case BuiltinTypeSpec.Type.SByte:
367 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
372 res = new EnumConstant (res, expr_type);
378 throw new Exception ("Can not constant fold: " + Oper.ToString());
381 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
383 eclass = ExprClass.Value;
385 TypeSpec expr_type = expr.Type;
386 Expression best_expr;
388 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
391 // Primitive types first
393 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
394 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
395 if (best_expr == null)
398 type = best_expr.Type;
404 // E operator ~(E x);
406 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
407 return ResolveEnumOperator (ec, expr, predefined);
409 return ResolveUserType (ec, expr, predefined);
412 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
414 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
415 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
416 if (best_expr == null)
420 enum_conversion = Binary.GetEnumResultCast (underlying_type);
422 return EmptyCast.Create (this, type);
425 public override bool ContainsEmitWithAwait ()
427 return Expr.ContainsEmitWithAwait ();
430 public override Expression CreateExpressionTree (ResolveContext ec)
432 return CreateExpressionTree (ec, null);
435 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
439 case Operator.AddressOf:
440 Error_PointerInsideExpressionTree (ec);
442 case Operator.UnaryNegation:
443 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
444 method_name = "NegateChecked";
446 method_name = "Negate";
448 case Operator.OnesComplement:
449 case Operator.LogicalNot:
452 case Operator.UnaryPlus:
453 method_name = "UnaryPlus";
456 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
459 Arguments args = new Arguments (2);
460 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
462 args.Add (new Argument (user_op));
464 return CreateExpressionFactoryCall (ec, method_name, args);
467 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
469 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
472 // 7.6.1 Unary plus operator
474 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
475 types.Int, types.UInt,
476 types.Long, types.ULong,
477 types.Float, types.Double,
482 // 7.6.2 Unary minus operator
484 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
485 types.Int, types.Long,
486 types.Float, types.Double,
491 // 7.6.3 Logical negation operator
493 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
498 // 7.6.4 Bitwise complement operator
500 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
501 types.Int, types.UInt,
502 types.Long, types.ULong
505 return predefined_operators;
509 // Unary numeric promotions
511 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
513 TypeSpec expr_type = expr.Type;
514 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
515 switch (expr_type.BuiltinType) {
516 case BuiltinTypeSpec.Type.Byte:
517 case BuiltinTypeSpec.Type.SByte:
518 case BuiltinTypeSpec.Type.Short:
519 case BuiltinTypeSpec.Type.UShort:
520 case BuiltinTypeSpec.Type.Char:
521 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
525 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
526 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
531 protected override Expression DoResolve (ResolveContext ec)
533 if (Oper == Operator.AddressOf) {
534 return ResolveAddressOf (ec);
537 Expr = Expr.Resolve (ec);
541 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
542 Arguments args = new Arguments (1);
543 args.Add (new Argument (Expr));
544 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
547 if (Expr.Type.IsNullableType)
548 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
551 // Attempt to use a constant folding operation.
553 Constant cexpr = Expr as Constant;
555 cexpr = TryReduceConstant (ec, cexpr);
560 Expression expr = ResolveOperator (ec, Expr);
562 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
565 // Reduce unary operator on predefined types
567 if (expr == this && Oper == Operator.UnaryPlus)
573 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
578 public override void Emit (EmitContext ec)
580 EmitOperator (ec, type);
583 protected void EmitOperator (EmitContext ec, TypeSpec type)
586 case Operator.UnaryPlus:
590 case Operator.UnaryNegation:
591 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
592 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
593 Expr = Expr.EmitToField (ec);
596 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
597 ec.Emit (OpCodes.Conv_U8);
599 ec.Emit (OpCodes.Sub_Ovf);
602 ec.Emit (OpCodes.Neg);
607 case Operator.LogicalNot:
610 ec.Emit (OpCodes.Ceq);
613 case Operator.OnesComplement:
615 ec.Emit (OpCodes.Not);
618 case Operator.AddressOf:
619 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
623 throw new Exception ("This should not happen: Operator = "
628 // Same trick as in Binary expression
630 if (enum_conversion != 0) {
631 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
632 ConvCast.Emit (ec, enum_conversion);
637 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
639 if (Oper == Operator.LogicalNot)
640 Expr.EmitBranchable (ec, target, !on_true);
642 base.EmitBranchable (ec, target, on_true);
645 public override void EmitSideEffect (EmitContext ec)
647 Expr.EmitSideEffect (ec);
650 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
652 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
653 oper, type.GetSignatureForError ());
656 public override void FlowAnalysis (FlowAnalysisContext fc)
658 FlowAnalysis (fc, false);
661 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
663 FlowAnalysis (fc, true);
666 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
668 if (Oper == Operator.AddressOf) {
669 var vr = Expr as VariableReference;
670 if (vr != null && vr.VariableInfo != null)
671 fc.SetVariableAssigned (vr.VariableInfo);
676 if (Oper == Operator.LogicalNot && conditional) {
677 Expr.FlowAnalysisConditional (fc);
679 var temp = fc.DefiniteAssignmentOnTrue;
680 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
681 fc.DefiniteAssignmentOnFalse = temp;
683 Expr.FlowAnalysis (fc);
688 // Converts operator to System.Linq.Expressions.ExpressionType enum name
690 string GetOperatorExpressionTypeName ()
693 case Operator.OnesComplement:
694 return "OnesComplement";
695 case Operator.LogicalNot:
697 case Operator.UnaryNegation:
699 case Operator.UnaryPlus:
702 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
706 static bool IsFloat (TypeSpec t)
708 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
712 // Returns a stringified representation of the Operator
714 public static string OperName (Operator oper)
717 case Operator.UnaryPlus:
719 case Operator.UnaryNegation:
721 case Operator.LogicalNot:
723 case Operator.OnesComplement:
725 case Operator.AddressOf:
729 throw new NotImplementedException (oper.ToString ());
732 public override SLE.Expression MakeExpression (BuilderContext ctx)
734 var expr = Expr.MakeExpression (ctx);
735 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
738 case Operator.UnaryNegation:
739 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
740 case Operator.LogicalNot:
741 return SLE.Expression.Not (expr);
742 case Operator.OnesComplement:
743 return SLE.Expression.OnesComplement (expr);
745 throw new NotImplementedException (Oper.ToString ());
749 Expression ResolveAddressOf (ResolveContext ec)
752 UnsafeError (ec, loc);
754 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
755 if (Expr == null || Expr.eclass != ExprClass.Variable) {
756 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
760 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
764 IVariableReference vr = Expr as IVariableReference;
767 is_fixed = vr.IsFixed;
768 vr.SetHasAddressTaken ();
771 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
774 IFixedExpression fe = Expr as IFixedExpression;
775 is_fixed = fe != null && fe.IsFixed;
778 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
779 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
782 type = PointerContainer.MakeType (ec.Module, Expr.Type);
783 eclass = ExprClass.Value;
787 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
789 expr = DoNumericPromotion (rc, Oper, expr);
790 TypeSpec expr_type = expr.Type;
791 foreach (TypeSpec t in predefined) {
799 // Perform user-operator overload resolution
801 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
803 CSharp.Operator.OpType op_type;
805 case Operator.LogicalNot:
806 op_type = CSharp.Operator.OpType.LogicalNot; break;
807 case Operator.OnesComplement:
808 op_type = CSharp.Operator.OpType.OnesComplement; break;
809 case Operator.UnaryNegation:
810 op_type = CSharp.Operator.OpType.UnaryNegation; break;
811 case Operator.UnaryPlus:
812 op_type = CSharp.Operator.OpType.UnaryPlus; break;
814 throw new InternalErrorException (Oper.ToString ());
817 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
821 Arguments args = new Arguments (1);
822 args.Add (new Argument (expr));
824 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
825 var oper = res.ResolveOperator (ec, ref args);
830 Expr = args [0].Expr;
831 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
835 // Unary user type overload resolution
837 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
839 Expression best_expr = ResolveUserOperator (ec, expr);
840 if (best_expr != null)
843 foreach (TypeSpec t in predefined) {
844 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
845 if (oper_expr == null)
848 if (oper_expr == ErrorExpression.Instance)
852 // decimal type is predefined but has user-operators
854 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
855 oper_expr = ResolveUserType (ec, oper_expr, predefined);
857 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
859 if (oper_expr == null)
862 if (best_expr == null) {
863 best_expr = oper_expr;
867 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
869 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
870 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
872 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
879 best_expr = oper_expr;
882 if (best_expr == null)
886 // HACK: Decimal user-operator is included in standard operators
888 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
892 type = best_expr.Type;
896 protected override void CloneTo (CloneContext clonectx, Expression t)
898 Unary target = (Unary) t;
900 target.Expr = Expr.Clone (clonectx);
903 public override object Accept (StructuralVisitor visitor)
905 return visitor.Visit (this);
911 // Unary operators are turned into Indirection expressions
912 // after semantic analysis (this is so we can take the address
913 // of an indirection).
915 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
917 LocalTemporary temporary;
920 public Indirection (Expression expr, Location l)
926 public Expression Expr {
932 public bool IsFixed {
936 public override Location StartLocation {
938 return expr.StartLocation;
942 protected override void CloneTo (CloneContext clonectx, Expression t)
944 Indirection target = (Indirection) t;
945 target.expr = expr.Clone (clonectx);
948 public override bool ContainsEmitWithAwait ()
950 throw new NotImplementedException ();
953 public override Expression CreateExpressionTree (ResolveContext ec)
955 Error_PointerInsideExpressionTree (ec);
959 public override void Emit (EmitContext ec)
964 ec.EmitLoadFromPtr (Type);
967 public void Emit (EmitContext ec, bool leave_copy)
971 ec.Emit (OpCodes.Dup);
972 temporary = new LocalTemporary (expr.Type);
973 temporary.Store (ec);
977 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
979 prepared = isCompound;
984 ec.Emit (OpCodes.Dup);
988 ec.Emit (OpCodes.Dup);
989 temporary = new LocalTemporary (source.Type);
990 temporary.Store (ec);
993 ec.EmitStoreFromPtr (type);
995 if (temporary != null) {
997 temporary.Release (ec);
1001 public void AddressOf (EmitContext ec, AddressOp Mode)
1006 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1008 return DoResolve (ec);
1011 protected override Expression DoResolve (ResolveContext ec)
1013 expr = expr.Resolve (ec);
1018 UnsafeError (ec, loc);
1020 var pc = expr.Type as PointerContainer;
1023 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
1029 if (type.Kind == MemberKind.Void) {
1030 Error_VoidPointerOperation (ec);
1034 eclass = ExprClass.Variable;
1038 public override object Accept (StructuralVisitor visitor)
1040 return visitor.Visit (this);
1045 /// Unary Mutator expressions (pre and post ++ and --)
1049 /// UnaryMutator implements ++ and -- expressions. It derives from
1050 /// ExpressionStatement becuase the pre/post increment/decrement
1051 /// operators can be used in a statement context.
1053 /// FIXME: Idea, we could split this up in two classes, one simpler
1054 /// for the common case, and one with the extra fields for more complex
1055 /// classes (indexers require temporary access; overloaded require method)
1058 public class UnaryMutator : ExpressionStatement
1060 class DynamicPostMutator : Expression, IAssignMethod
1062 LocalTemporary temp;
1065 public DynamicPostMutator (Expression expr)
1068 this.type = expr.Type;
1069 this.loc = expr.Location;
1072 public override Expression CreateExpressionTree (ResolveContext ec)
1074 throw new NotImplementedException ("ET");
1077 protected override Expression DoResolve (ResolveContext rc)
1079 eclass = expr.eclass;
1083 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1085 expr.DoResolveLValue (ec, right_side);
1086 return DoResolve (ec);
1089 public override void Emit (EmitContext ec)
1094 public void Emit (EmitContext ec, bool leave_copy)
1096 throw new NotImplementedException ();
1100 // Emits target assignment using unmodified source value
1102 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1105 // Allocate temporary variable to keep original value before it's modified
1107 temp = new LocalTemporary (type);
1111 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1122 public enum Mode : byte {
1129 PreDecrement = IsDecrement,
1130 PostIncrement = IsPost,
1131 PostDecrement = IsPost | IsDecrement
1135 bool is_expr, recurse;
1137 protected Expression expr;
1139 // Holds the real operation
1140 Expression operation;
1142 public UnaryMutator (Mode m, Expression e, Location loc)
1149 public Mode UnaryMutatorMode {
1155 public Expression Expr {
1161 public override Location StartLocation {
1163 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1167 public override bool ContainsEmitWithAwait ()
1169 return expr.ContainsEmitWithAwait ();
1172 public override Expression CreateExpressionTree (ResolveContext ec)
1174 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1177 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1180 // Predefined ++ and -- operators exist for the following types:
1181 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1183 return new TypeSpec[] {
1199 protected override Expression DoResolve (ResolveContext ec)
1201 expr = expr.Resolve (ec);
1203 if (expr == null || expr.Type == InternalType.ErrorType)
1206 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1208 // Handle postfix unary operators using local
1209 // temporary variable
1211 if ((mode & Mode.IsPost) != 0)
1212 expr = new DynamicPostMutator (expr);
1214 Arguments args = new Arguments (1);
1215 args.Add (new Argument (expr));
1216 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1219 if (expr.Type.IsNullableType)
1220 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1222 return DoResolveOperation (ec);
1225 protected Expression DoResolveOperation (ResolveContext ec)
1227 eclass = ExprClass.Value;
1230 if (expr is RuntimeValueExpression) {
1233 // Use itself at the top of the stack
1234 operation = new EmptyExpression (type);
1238 // The operand of the prefix/postfix increment decrement operators
1239 // should be an expression that is classified as a variable,
1240 // a property access or an indexer access
1242 // TODO: Move to parser, expr is ATypeNameExpression
1243 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1244 expr = expr.ResolveLValue (ec, expr);
1246 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1250 // Step 1: Try to find a user operator, it has priority over predefined ones
1252 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1253 var methods = MemberCache.GetUserOperator (type, user_op, false);
1255 if (methods != null) {
1256 Arguments args = new Arguments (1);
1257 args.Add (new Argument (expr));
1259 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1260 var method = res.ResolveOperator (ec, ref args);
1264 args[0].Expr = operation;
1265 operation = new UserOperatorCall (method, args, null, loc);
1266 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1271 // Step 2: Try predefined types
1274 Expression source = null;
1275 bool primitive_type;
1278 // Predefined without user conversion first for speed-up
1280 // Predefined ++ and -- operators exist for the following types:
1281 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1283 switch (type.BuiltinType) {
1284 case BuiltinTypeSpec.Type.Byte:
1285 case BuiltinTypeSpec.Type.SByte:
1286 case BuiltinTypeSpec.Type.Short:
1287 case BuiltinTypeSpec.Type.UShort:
1288 case BuiltinTypeSpec.Type.Int:
1289 case BuiltinTypeSpec.Type.UInt:
1290 case BuiltinTypeSpec.Type.Long:
1291 case BuiltinTypeSpec.Type.ULong:
1292 case BuiltinTypeSpec.Type.Char:
1293 case BuiltinTypeSpec.Type.Float:
1294 case BuiltinTypeSpec.Type.Double:
1295 case BuiltinTypeSpec.Type.Decimal:
1297 primitive_type = true;
1300 primitive_type = false;
1302 // ++/-- on pointer variables of all types except void*
1303 if (type.IsPointer) {
1304 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1305 Error_VoidPointerOperation (ec);
1311 Expression best_source = null;
1312 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1313 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1315 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1319 if (best_source == null) {
1320 best_source = source;
1324 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1329 best_source = source;
1333 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1337 source = best_source;
1340 // ++/-- on enum types
1341 if (source == null && type.IsEnum)
1344 if (source == null) {
1345 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1352 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1353 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1354 operation = new Binary (op, source, one);
1355 operation = operation.Resolve (ec);
1356 if (operation == null)
1357 throw new NotImplementedException ("should not be reached");
1359 if (operation.Type != type) {
1361 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1363 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1369 void EmitCode (EmitContext ec, bool is_expr)
1372 this.is_expr = is_expr;
1373 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1376 public override void Emit (EmitContext ec)
1379 // We use recurse to allow ourselfs to be the source
1380 // of an assignment. This little hack prevents us from
1381 // having to allocate another expression
1384 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1392 EmitCode (ec, true);
1395 protected virtual void EmitOperation (EmitContext ec)
1397 operation.Emit (ec);
1400 public override void EmitStatement (EmitContext ec)
1402 EmitCode (ec, false);
1405 public override void FlowAnalysis (FlowAnalysisContext fc)
1407 expr.FlowAnalysis (fc);
1411 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1413 string GetOperatorExpressionTypeName ()
1415 return IsDecrement ? "Decrement" : "Increment";
1419 get { return (mode & Mode.IsDecrement) != 0; }
1423 public override SLE.Expression MakeExpression (BuilderContext ctx)
1425 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1426 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1427 return SLE.Expression.Assign (target, source);
1430 public static string OperName (Mode oper)
1432 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1435 protected override void CloneTo (CloneContext clonectx, Expression t)
1437 UnaryMutator target = (UnaryMutator) t;
1439 target.expr = expr.Clone (clonectx);
1442 public override object Accept (StructuralVisitor visitor)
1444 return visitor.Visit (this);
1450 // Base class for the `is' and `as' operators
1452 public abstract class Probe : Expression
1454 public Expression ProbeType;
1455 protected Expression expr;
1456 protected TypeSpec probe_type_expr;
1458 protected Probe (Expression expr, Expression probe_type, Location l)
1460 ProbeType = probe_type;
1465 public Expression Expr {
1471 public override bool ContainsEmitWithAwait ()
1473 return expr.ContainsEmitWithAwait ();
1476 protected Expression ResolveCommon (ResolveContext rc)
1478 expr = expr.Resolve (rc);
1482 ResolveProbeType (rc);
1483 if (probe_type_expr == null)
1486 if (probe_type_expr.IsStatic) {
1487 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1488 probe_type_expr.GetSignatureForError ());
1492 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1493 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1498 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1499 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1507 protected virtual void ResolveProbeType (ResolveContext rc)
1509 probe_type_expr = ProbeType.ResolveAsType (rc);
1512 public override void EmitSideEffect (EmitContext ec)
1514 expr.EmitSideEffect (ec);
1517 public override void FlowAnalysis (FlowAnalysisContext fc)
1519 expr.FlowAnalysis (fc);
1522 public override bool HasConditionalAccess ()
1524 return expr.HasConditionalAccess ();
1527 protected abstract string OperatorName { get; }
1529 protected override void CloneTo (CloneContext clonectx, Expression t)
1531 Probe target = (Probe) t;
1533 target.expr = expr.Clone (clonectx);
1534 target.ProbeType = ProbeType.Clone (clonectx);
1540 /// Implementation of the `is' operator.
1542 public class Is : Probe
1544 Nullable.Unwrap expr_unwrap;
1545 MethodSpec number_mg;
1546 Arguments number_args;
1548 public Is (Expression expr, Expression probe_type, Location l)
1549 : base (expr, probe_type, l)
1553 protected override string OperatorName {
1554 get { return "is"; }
1557 public LocalVariable Variable { get; set; }
1559 public override Expression CreateExpressionTree (ResolveContext ec)
1561 if (Variable != null)
1562 throw new NotSupportedException ();
1564 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1565 expr.CreateExpressionTree (ec),
1566 new TypeOf (probe_type_expr, loc));
1568 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1571 Expression CreateConstantResult (ResolveContext rc, bool result)
1574 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1575 probe_type_expr.GetSignatureForError ());
1577 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1578 probe_type_expr.GetSignatureForError ());
1580 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1581 return expr.IsSideEffectFree ?
1582 ReducedExpression.Create (c, this) :
1583 new SideEffectConstant (c, this, loc);
1586 public override void Emit (EmitContext ec)
1588 if (probe_type_expr == null) {
1589 if (ProbeType is WildcardPattern) {
1590 expr.EmitSideEffect (ec);
1591 ProbeType.Emit (ec);
1593 EmitPatternMatch (ec);
1600 if (expr_unwrap == null) {
1602 ec.Emit (OpCodes.Cgt_Un);
1606 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1608 if (probe_type_expr == null) {
1609 EmitPatternMatch (ec);
1614 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1617 void EmitPatternMatch (EmitContext ec)
1619 var no_match = ec.DefineLabel ();
1620 var end = ec.DefineLabel ();
1622 if (expr_unwrap != null) {
1623 expr_unwrap.EmitCheck (ec);
1625 if (ProbeType.IsNull) {
1627 ec.Emit (OpCodes.Ceq);
1631 ec.Emit (OpCodes.Brfalse_S, no_match);
1632 expr_unwrap.Emit (ec);
1633 ProbeType.Emit (ec);
1634 ec.Emit (OpCodes.Ceq);
1635 ec.Emit (OpCodes.Br_S, end);
1636 ec.MarkLabel (no_match);
1642 if (number_args != null && number_args.Count == 3) {
1643 var ce = new CallEmitter ();
1644 ce.Emit (ec, number_mg, number_args, loc);
1648 var probe_type = ProbeType.Type;
1651 ec.Emit (OpCodes.Isinst, probe_type);
1652 ec.Emit (OpCodes.Dup);
1653 ec.Emit (OpCodes.Brfalse, no_match);
1655 bool complex_pattern = ProbeType is ComplexPatternExpression;
1656 Label prev = ec.RecursivePatternLabel;
1657 if (complex_pattern)
1658 ec.RecursivePatternLabel = ec.DefineLabel ();
1660 if (number_mg != null) {
1661 var ce = new CallEmitter ();
1662 ce.Emit (ec, number_mg, number_args, loc);
1664 if (TypeSpec.IsValueType (probe_type))
1665 ec.Emit (OpCodes.Unbox_Any, probe_type);
1667 ProbeType.Emit (ec);
1668 if (complex_pattern) {
1671 ec.Emit (OpCodes.Ceq);
1674 ec.Emit (OpCodes.Br_S, end);
1675 ec.MarkLabel (no_match);
1677 ec.Emit (OpCodes.Pop);
1679 if (complex_pattern)
1680 ec.MarkLabel (ec.RecursivePatternLabel);
1682 ec.RecursivePatternLabel = prev;
1688 void EmitLoad (EmitContext ec)
1690 Label no_value_label = new Label ();
1692 if (expr_unwrap != null) {
1693 expr_unwrap.EmitCheck (ec);
1695 if (Variable == null)
1698 ec.Emit (OpCodes.Dup);
1699 no_value_label = ec.DefineLabel ();
1700 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1701 expr_unwrap.Emit (ec);
1705 // Only to make verifier happy
1706 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1707 ec.Emit (OpCodes.Box, expr.Type);
1709 ec.Emit (OpCodes.Isinst, probe_type_expr);
1712 if (Variable != null) {
1713 bool value_on_stack;
1714 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1715 ec.Emit (OpCodes.Dup);
1716 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1717 value_on_stack = true;
1719 value_on_stack = false;
1722 Variable.CreateBuilder (ec);
1723 Variable.EmitAssign (ec);
1725 if (expr_unwrap != null) {
1726 ec.MarkLabel (no_value_label);
1727 } else if (!value_on_stack) {
1733 protected override Expression DoResolve (ResolveContext rc)
1735 if (ResolveCommon (rc) == null)
1738 type = rc.BuiltinTypes.Bool;
1739 eclass = ExprClass.Value;
1741 if (probe_type_expr == null)
1742 return ResolveMatchingExpression (rc);
1744 var res = ResolveResultExpression (rc);
1745 if (Variable != null) {
1746 if (res is Constant)
1747 throw new NotImplementedException ("constant in type pattern matching");
1749 Variable.Type = probe_type_expr;
1750 var bc = rc as BlockContext;
1752 Variable.PrepareAssignmentAnalysis (bc);
1758 public override void FlowAnalysis (FlowAnalysisContext fc)
1760 base.FlowAnalysis (fc);
1762 if (Variable != null)
1763 fc.SetVariableAssigned (Variable.VariableInfo, true);
1766 protected override void ResolveProbeType (ResolveContext rc)
1768 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1769 if (ProbeType is PatternExpression) {
1770 ProbeType.Resolve (rc);
1775 // Have to use session recording because we don't have reliable type probing
1776 // mechanism (similar issue as in attributes resolving)
1778 // TODO: This is still wrong because ResolveAsType can be destructive
1780 var type_printer = new SessionReportPrinter ();
1781 var prev_recorder = rc.Report.SetPrinter (type_printer);
1783 probe_type_expr = ProbeType.ResolveAsType (rc);
1784 type_printer.EndSession ();
1786 if (probe_type_expr != null) {
1787 type_printer.Merge (rc.Report.Printer);
1788 rc.Report.SetPrinter (prev_recorder);
1792 var vexpr = ProbeType as VarExpr;
1793 if (vexpr != null && vexpr.InferType (rc, expr)) {
1794 probe_type_expr = vexpr.Type;
1795 rc.Report.SetPrinter (prev_recorder);
1799 var expr_printer = new SessionReportPrinter ();
1800 rc.Report.SetPrinter (expr_printer);
1801 ProbeType = ProbeType.Resolve (rc);
1802 expr_printer.EndSession ();
1804 if (ProbeType != null) {
1805 expr_printer.Merge (rc.Report.Printer);
1807 type_printer.Merge (rc.Report.Printer);
1810 rc.Report.SetPrinter (prev_recorder);
1814 base.ResolveProbeType (rc);
1817 Expression ResolveMatchingExpression (ResolveContext rc)
1819 var mc = ProbeType as Constant;
1821 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1822 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1827 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1829 var c = Expr as Constant;
1831 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1836 if (Expr.Type.IsNullableType) {
1837 expr_unwrap = new Nullable.Unwrap (Expr);
1838 expr_unwrap.Resolve (rc);
1839 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1840 } else if (ProbeType.Type == Expr.Type) {
1841 // TODO: Better error handling
1842 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1843 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1844 var helper = rc.Module.CreatePatterMatchingHelper ();
1845 number_mg = helper.NumberMatcher.Spec;
1848 // There are actually 3 arguments but the first one is already on the stack
1850 number_args = new Arguments (3);
1851 if (!ProbeType.Type.IsEnum)
1852 number_args.Add (new Argument (Expr));
1854 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1855 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1861 if (ProbeType is PatternExpression) {
1862 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1863 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1869 // TODO: Better error message
1870 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1874 Expression ResolveResultExpression (ResolveContext ec)
1876 TypeSpec d = expr.Type;
1877 bool d_is_nullable = false;
1880 // If E is a method group or the null literal, or if the type of E is a reference
1881 // type or a nullable type and the value of E is null, the result is false
1883 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1884 return CreateConstantResult (ec, false);
1886 if (d.IsNullableType) {
1887 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1888 if (!ut.IsGenericParameter) {
1890 d_is_nullable = true;
1894 TypeSpec t = probe_type_expr;
1895 bool t_is_nullable = false;
1896 if (t.IsNullableType) {
1897 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1898 if (!ut.IsGenericParameter) {
1900 t_is_nullable = true;
1907 // D and T are the same value types but D can be null
1909 if (d_is_nullable && !t_is_nullable) {
1910 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1915 // The result is true if D and T are the same value types
1917 return CreateConstantResult (ec, true);
1920 var tp = d as TypeParameterSpec;
1922 return ResolveGenericParameter (ec, t, tp);
1925 // An unboxing conversion exists
1927 if (Convert.ExplicitReferenceConversionExists (d, t))
1931 // open generic type
1933 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1936 var tps = t as TypeParameterSpec;
1938 return ResolveGenericParameter (ec, d, tps);
1940 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1941 ec.Report.Warning (1981, 3, loc,
1942 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1943 OperatorName, t.GetSignatureForError ());
1946 if (TypeManager.IsGenericParameter (d))
1947 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1949 if (TypeSpec.IsValueType (d)) {
1950 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1951 if (d_is_nullable && !t_is_nullable) {
1952 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1956 return CreateConstantResult (ec, true);
1959 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1960 var c = expr as Constant;
1962 return CreateConstantResult (ec, !c.IsNull);
1965 // Do not optimize for imported type or dynamic type
1967 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1968 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1972 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1976 // Turn is check into simple null check for implicitly convertible reference types
1978 return ReducedExpression.Create (
1979 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
1983 if (Convert.ExplicitReferenceConversionExists (d, t))
1987 // open generic type
1989 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1994 return CreateConstantResult (ec, false);
1997 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1999 if (t.IsReferenceType) {
2001 return CreateConstantResult (ec, false);
2004 if (expr.Type.IsGenericParameter) {
2005 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
2006 return CreateConstantResult (ec, true);
2008 expr = new BoxedCast (expr, d);
2014 public override object Accept (StructuralVisitor visitor)
2016 return visitor.Visit (this);
2020 class WildcardPattern : PatternExpression
2022 public WildcardPattern (Location loc)
2027 protected override Expression DoResolve (ResolveContext rc)
2029 eclass = ExprClass.Value;
2030 type = rc.BuiltinTypes.Object;
2034 public override void Emit (EmitContext ec)
2040 class RecursivePattern : ComplexPatternExpression
2042 MethodGroupExpr operator_mg;
2043 Arguments operator_args;
2045 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2046 : base (typeExpresion, loc)
2048 Arguments = arguments;
2051 public Arguments Arguments { get; private set; }
2053 protected override Expression DoResolve (ResolveContext rc)
2055 type = TypeExpression.ResolveAsType (rc);
2059 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2060 if (operators == null) {
2061 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2065 var ops = FindMatchingOverloads (operators);
2067 // TODO: better error message
2068 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2073 Arguments.Resolve (rc, out dynamic_args);
2075 throw new NotImplementedException ("dynamic argument");
2077 var op = FindBestOverload (rc, ops);
2079 // TODO: better error message
2080 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2084 var op_types = op.Parameters.Types;
2085 operator_args = new Arguments (op_types.Length);
2086 operator_args.Add (new Argument (new EmptyExpression (type)));
2088 for (int i = 0; i < Arguments.Count; ++i) {
2089 // TODO: Needs releasing optimization
2090 var lt = new LocalTemporary (op_types [i + 1]);
2091 operator_args.Add (new Argument (lt, Argument.AType.Out));
2093 if (comparisons == null)
2094 comparisons = new Expression[Arguments.Count];
2099 var arg = Arguments [i];
2100 var named = arg as NamedArgument;
2101 if (named != null) {
2102 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2103 expr = Arguments [arg_comp_index].Expr;
2109 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2112 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2114 eclass = ExprClass.Value;
2118 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2120 int arg_count = Arguments.Count + 1;
2121 List<MethodSpec> best = null;
2122 foreach (MethodSpec method in members) {
2123 var pm = method.Parameters;
2124 if (pm.Count != arg_count)
2127 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2129 for (int ii = 1; ii < pm.Count; ++ii) {
2130 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2140 best = new List<MethodSpec> ();
2148 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2150 for (int ii = 0; ii < Arguments.Count; ++ii) {
2151 var arg = Arguments [ii];
2152 var expr = arg.Expr;
2153 if (expr is WildcardPattern)
2156 var na = arg as NamedArgument;
2157 for (int i = 0; i < methods.Count; ++i) {
2158 var pd = methods [i].Parameters;
2162 index = pd.GetParameterIndexByName (na.Name);
2164 methods.RemoveAt (i--);
2171 var m = pd.Types [index];
2172 if (!Convert.ImplicitConversionExists (rc, expr, m))
2173 methods.RemoveAt (i--);
2177 if (methods.Count != 1)
2183 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2185 operator_mg.EmitCall (ec, operator_args, false);
2186 ec.Emit (OpCodes.Brfalse, target);
2188 base.EmitBranchable (ec, target, on_true);
2191 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2193 if (expr is WildcardPattern)
2194 return new EmptyExpression (expr.Type);
2196 var recursive = expr as RecursivePattern;
2197 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2201 if (recursive != null) {
2202 recursive.SetParentInstance (lt);
2206 // TODO: Better error handling
2207 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2210 public void SetParentInstance (Expression instance)
2212 operator_args [0] = new Argument (instance);
2216 class PropertyPattern : ComplexPatternExpression
2218 LocalTemporary instance;
2220 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2221 : base (typeExpresion, loc)
2226 public List<PropertyPatternMember> Members { get; private set; }
2228 protected override Expression DoResolve (ResolveContext rc)
2230 type = TypeExpression.ResolveAsType (rc);
2234 comparisons = new Expression[Members.Count];
2236 // TODO: optimize when source is VariableReference, it'd save dup+pop
2237 instance = new LocalTemporary (type);
2239 for (int i = 0; i < Members.Count; i++) {
2240 var lookup = Members [i];
2242 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2243 if (member == null) {
2244 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2245 if (member != null) {
2246 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2251 if (member == null) {
2252 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2256 var pe = member as PropertyExpr;
2257 if (pe == null || member is FieldExpr) {
2258 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2262 // TODO: Obsolete checks
2263 // TODO: check accessibility
2264 if (pe != null && !pe.PropertyInfo.HasGet) {
2265 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2269 var expr = lookup.Expr.Resolve (rc);
2273 var me = (MemberExpr)member;
2274 me.InstanceExpression = instance;
2276 comparisons [i] = ResolveComparison (rc, expr, me);
2279 eclass = ExprClass.Value;
2283 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2285 if (expr is WildcardPattern)
2286 return new EmptyExpression (expr.Type);
2288 return new Is (instance, expr, expr.Location).Resolve (rc);
2291 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2293 instance.Store (ec);
2295 base.EmitBranchable (ec, target, on_true);
2299 class PropertyPatternMember
2301 public PropertyPatternMember (string name, Expression expr, Location loc)
2308 public string Name { get; private set; }
2309 public Expression Expr { get; private set; }
2310 public Location Location { get; private set; }
2313 abstract class PatternExpression : Expression
2315 protected PatternExpression (Location loc)
2320 public override Expression CreateExpressionTree (ResolveContext ec)
2322 throw new NotImplementedException ();
2326 abstract class ComplexPatternExpression : PatternExpression
2328 protected Expression[] comparisons;
2330 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2333 TypeExpression = typeExpresion;
2336 public ATypeNameExpression TypeExpression { get; private set; }
2338 public override void Emit (EmitContext ec)
2340 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2343 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2345 if (comparisons != null) {
2346 foreach (var comp in comparisons) {
2347 comp.EmitBranchable (ec, target, false);
2354 /// Implementation of the `as' operator.
2356 public class As : Probe {
2358 public As (Expression expr, Expression probe_type, Location l)
2359 : base (expr, probe_type, l)
2363 protected override string OperatorName {
2364 get { return "as"; }
2367 public override Expression CreateExpressionTree (ResolveContext ec)
2369 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2370 expr.CreateExpressionTree (ec),
2371 new TypeOf (probe_type_expr, loc));
2373 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2376 public override void Emit (EmitContext ec)
2380 ec.Emit (OpCodes.Isinst, type);
2382 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2383 ec.Emit (OpCodes.Unbox_Any, type);
2386 protected override Expression DoResolve (ResolveContext ec)
2388 if (ResolveCommon (ec) == null)
2391 type = probe_type_expr;
2392 eclass = ExprClass.Value;
2393 TypeSpec etype = expr.Type;
2395 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2396 if (TypeManager.IsGenericParameter (type)) {
2397 ec.Report.Error (413, loc,
2398 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2399 probe_type_expr.GetSignatureForError ());
2401 ec.Report.Error (77, loc,
2402 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2403 type.GetSignatureForError ());
2408 if (expr.IsNull && type.IsNullableType) {
2409 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2412 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2413 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2417 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2419 e = EmptyCast.Create (e, type);
2420 return ReducedExpression.Create (e, this).Resolve (ec);
2423 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2424 if (TypeManager.IsGenericParameter (etype))
2425 expr = new BoxedCast (expr, etype);
2430 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2431 expr = new BoxedCast (expr, etype);
2435 if (etype != InternalType.ErrorType) {
2436 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2437 etype.GetSignatureForError (), type.GetSignatureForError ());
2443 public override object Accept (StructuralVisitor visitor)
2445 return visitor.Visit (this);
2450 // This represents a typecast in the source language.
2452 public class Cast : ShimExpression {
2453 Expression target_type;
2455 public Cast (Expression cast_type, Expression expr, Location loc)
2458 this.target_type = cast_type;
2462 public Expression TargetType {
2463 get { return target_type; }
2466 protected override Expression DoResolve (ResolveContext ec)
2468 expr = expr.Resolve (ec);
2472 type = target_type.ResolveAsType (ec);
2476 if (type.IsStatic) {
2477 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2481 if (type.IsPointer && !ec.IsUnsafe) {
2482 UnsafeError (ec, loc);
2485 eclass = ExprClass.Value;
2487 Constant c = expr as Constant;
2489 c = c.Reduce (ec, type);
2494 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2496 return EmptyCast.Create (res, type);
2501 protected override void CloneTo (CloneContext clonectx, Expression t)
2503 Cast target = (Cast) t;
2505 target.target_type = target_type.Clone (clonectx);
2506 target.expr = expr.Clone (clonectx);
2509 public override object Accept (StructuralVisitor visitor)
2511 return visitor.Visit (this);
2515 public class ImplicitCast : ShimExpression
2519 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2522 this.loc = expr.Location;
2524 this.arrayAccess = arrayAccess;
2527 protected override Expression DoResolve (ResolveContext ec)
2529 expr = expr.Resolve (ec);
2534 expr = ConvertExpressionToArrayIndex (ec, expr);
2536 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2542 public class DeclarationExpression : Expression, IMemoryLocation
2544 LocalVariableReference lvr;
2546 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2548 VariableType = variableType;
2549 Variable = variable;
2550 this.loc = variable.Location;
2553 public LocalVariable Variable { get; set; }
2554 public Expression Initializer { get; set; }
2555 public FullNamedExpression VariableType { get; set; }
2557 public void AddressOf (EmitContext ec, AddressOp mode)
2559 Variable.CreateBuilder (ec);
2561 if (Initializer != null) {
2562 lvr.EmitAssign (ec, Initializer, false, false);
2565 lvr.AddressOf (ec, mode);
2568 protected override void CloneTo (CloneContext clonectx, Expression t)
2570 var target = (DeclarationExpression) t;
2572 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2574 if (Initializer != null)
2575 target.Initializer = Initializer.Clone (clonectx);
2578 public override Expression CreateExpressionTree (ResolveContext rc)
2580 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2584 bool DoResolveCommon (ResolveContext rc)
2586 var var_expr = VariableType as VarExpr;
2587 if (var_expr != null) {
2588 type = InternalType.VarOutType;
2590 type = VariableType.ResolveAsType (rc);
2595 if (Initializer != null) {
2596 Initializer = Initializer.Resolve (rc);
2598 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2599 type = var_expr.Type;
2603 Variable.Type = type;
2604 lvr = new LocalVariableReference (Variable, loc);
2606 eclass = ExprClass.Variable;
2610 protected override Expression DoResolve (ResolveContext rc)
2612 if (DoResolveCommon (rc))
2618 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2620 if (lvr == null && DoResolveCommon (rc))
2621 lvr.ResolveLValue (rc, right_side);
2626 public override void Emit (EmitContext ec)
2628 throw new NotImplementedException ();
2633 // C# 2.0 Default value expression
2635 public class DefaultValueExpression : Expression
2639 public DefaultValueExpression (Expression expr, Location loc)
2645 public Expression Expr {
2651 public override bool IsSideEffectFree {
2657 public override bool ContainsEmitWithAwait ()
2662 public override Expression CreateExpressionTree (ResolveContext ec)
2664 Arguments args = new Arguments (2);
2665 args.Add (new Argument (this));
2666 args.Add (new Argument (new TypeOf (type, loc)));
2667 return CreateExpressionFactoryCall (ec, "Constant", args);
2670 protected override Expression DoResolve (ResolveContext ec)
2672 type = expr.ResolveAsType (ec);
2676 if (type.IsStatic) {
2677 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2681 return new NullLiteral (Location).ConvertImplicitly (type);
2683 if (TypeSpec.IsReferenceType (type))
2684 return new NullConstant (type, loc);
2686 Constant c = New.Constantify (type, expr.Location);
2690 eclass = ExprClass.Variable;
2694 public override void Emit (EmitContext ec)
2696 LocalTemporary temp_storage = new LocalTemporary(type);
2698 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2699 ec.Emit(OpCodes.Initobj, type);
2700 temp_storage.Emit(ec);
2701 temp_storage.Release (ec);
2705 public override SLE.Expression MakeExpression (BuilderContext ctx)
2707 return SLE.Expression.Default (type.GetMetaInfo ());
2711 protected override void CloneTo (CloneContext clonectx, Expression t)
2713 DefaultValueExpression target = (DefaultValueExpression) t;
2715 target.expr = expr.Clone (clonectx);
2718 public override object Accept (StructuralVisitor visitor)
2720 return visitor.Visit (this);
2725 /// Binary operators
2727 public class Binary : Expression, IDynamicBinder
2729 public class PredefinedOperator
2731 protected readonly TypeSpec left;
2732 protected readonly TypeSpec right;
2733 protected readonly TypeSpec left_unwrap;
2734 protected readonly TypeSpec right_unwrap;
2735 public readonly Operator OperatorsMask;
2736 public TypeSpec ReturnType;
2738 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2739 : this (ltype, rtype, op_mask, ltype)
2743 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2744 : this (type, type, op_mask, return_type)
2748 public PredefinedOperator (TypeSpec type, Operator op_mask)
2749 : this (type, type, op_mask, type)
2753 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2755 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2756 throw new InternalErrorException ("Only masked values can be used");
2758 if ((op_mask & Operator.NullableMask) != 0) {
2759 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2760 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2762 left_unwrap = ltype;
2763 right_unwrap = rtype;
2768 this.OperatorsMask = op_mask;
2769 this.ReturnType = return_type;
2772 public bool IsLifted {
2774 return (OperatorsMask & Operator.NullableMask) != 0;
2778 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2782 var left_expr = b.left;
2783 var right_expr = b.right;
2785 b.type = ReturnType;
2788 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2789 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2790 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2793 if (right_expr.IsNull) {
2794 if ((b.oper & Operator.EqualityMask) != 0) {
2795 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2796 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2797 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2798 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2799 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2801 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2802 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2804 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2805 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2807 return b.CreateLiftedValueTypeResult (rc, left);
2809 } else if (left_expr.IsNull) {
2810 if ((b.oper & Operator.EqualityMask) != 0) {
2811 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2812 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2813 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2814 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2815 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2817 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2818 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2820 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2821 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2823 return b.CreateLiftedValueTypeResult (rc, right);
2829 // A user operators does not support multiple user conversions, but decimal type
2830 // is considered to be predefined type therefore we apply predefined operators rules
2831 // and then look for decimal user-operator implementation
2833 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2834 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2835 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2837 return b.ResolveUserOperator (rc, b.left, b.right);
2840 c = right_expr as Constant;
2842 if (c.IsDefaultValue) {
2846 // (expr + 0) to expr
2847 // (expr - 0) to expr
2848 // (bool? | false) to bool?
2850 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2851 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2852 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2853 return ReducedExpression.Create (b.left, b).Resolve (rc);
2857 // Optimizes (value &/&& 0) to 0
2859 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2860 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2861 return ReducedExpression.Create (side_effect, b);
2865 // Optimizes (bool? & true) to bool?
2867 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2868 return ReducedExpression.Create (b.left, b).Resolve (rc);
2872 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2873 return ReducedExpression.Create (b.left, b).Resolve (rc);
2875 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2876 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2880 c = b.left as Constant;
2882 if (c.IsDefaultValue) {
2886 // (0 + expr) to expr
2887 // (false | bool?) to bool?
2889 if (b.oper == Operator.Addition ||
2890 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2891 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2892 return ReducedExpression.Create (b.right, b).Resolve (rc);
2896 // Optimizes (false && expr) to false
2898 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2899 // No rhs side-effects
2900 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2901 return ReducedExpression.Create (c, b);
2905 // Optimizes (0 & value) to 0
2907 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2908 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2909 return ReducedExpression.Create (side_effect, b);
2913 // Optimizes (true & bool?) to bool?
2915 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2916 return ReducedExpression.Create (b.right, b).Resolve (rc);
2920 // Optimizes (true || expr) to true
2922 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2923 // No rhs side-effects
2924 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2925 return ReducedExpression.Create (c, b);
2929 if (b.oper == Operator.Multiply && c.IsOneInteger)
2930 return ReducedExpression.Create (b.right, b).Resolve (rc);
2934 var lifted = new Nullable.LiftedBinaryOperator (b);
2936 TypeSpec ltype, rtype;
2937 if (b.left.Type.IsNullableType) {
2938 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2939 ltype = left_unwrap;
2944 if (b.right.Type.IsNullableType) {
2945 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2946 rtype = right_unwrap;
2951 lifted.Left = b.left.IsNull ?
2953 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2955 lifted.Right = b.right.IsNull ?
2957 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2959 return lifted.Resolve (rc);
2962 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2963 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2968 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2971 // We are dealing with primitive types only
2973 return left == ltype && ltype == rtype;
2976 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2979 if (left == lexpr.Type && right == rexpr.Type)
2982 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2983 Convert.ImplicitConversionExists (ec, rexpr, right);
2986 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2988 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2989 return best_operator;
2991 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2995 if (left != null && best_operator.left != null) {
2996 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
3000 // When second argument is same as the first one, the result is same
3002 if (right != null && (left != right || best_operator.left != best_operator.right)) {
3003 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
3006 if (result == 0 || result > 2)
3009 return result == 1 ? best_operator : this;
3013 sealed class PredefinedStringOperator : PredefinedOperator
3015 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
3016 : base (type, type, op_mask, retType)
3020 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3021 : base (ltype, rtype, op_mask, retType)
3025 public override Expression ConvertResult (ResolveContext ec, Binary b)
3028 // Use original expression for nullable arguments
3030 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3032 b.left = unwrap.Original;
3034 unwrap = b.right as Nullable.Unwrap;
3036 b.right = unwrap.Original;
3038 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3039 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3042 // Start a new concat expression using converted expression
3044 return StringConcat.Create (ec, b.left, b.right, b.loc);
3048 sealed class PredefinedEqualityOperator : PredefinedOperator
3050 MethodSpec equal_method, inequal_method;
3052 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3053 : base (arg, arg, Operator.EqualityMask, retType)
3057 public override Expression ConvertResult (ResolveContext ec, Binary b)
3059 b.type = ReturnType;
3061 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3062 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3064 Arguments args = new Arguments (2);
3065 args.Add (new Argument (b.left));
3066 args.Add (new Argument (b.right));
3069 if (b.oper == Operator.Equality) {
3070 if (equal_method == null) {
3071 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3072 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3073 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3074 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3076 throw new NotImplementedException (left.GetSignatureForError ());
3079 method = equal_method;
3081 if (inequal_method == null) {
3082 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3083 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3084 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3085 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3087 throw new NotImplementedException (left.GetSignatureForError ());
3090 method = inequal_method;
3093 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3097 class PredefinedPointerOperator : PredefinedOperator
3099 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3100 : base (ltype, rtype, op_mask)
3104 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3105 : base (ltype, rtype, op_mask, retType)
3109 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3110 : base (type, op_mask, return_type)
3114 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3117 if (!lexpr.Type.IsPointer)
3120 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3124 if (right == null) {
3125 if (!rexpr.Type.IsPointer)
3128 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3135 public override Expression ConvertResult (ResolveContext ec, Binary b)
3138 b.left = EmptyCast.Create (b.left, left);
3139 } else if (right != null) {
3140 b.right = EmptyCast.Create (b.right, right);
3143 TypeSpec r_type = ReturnType;
3144 Expression left_arg, right_arg;
3145 if (r_type == null) {
3148 right_arg = b.right;
3149 r_type = b.left.Type;
3153 r_type = b.right.Type;
3157 right_arg = b.right;
3160 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3165 public enum Operator {
3166 Multiply = 0 | ArithmeticMask,
3167 Division = 1 | ArithmeticMask,
3168 Modulus = 2 | ArithmeticMask,
3169 Addition = 3 | ArithmeticMask | AdditionMask,
3170 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3172 LeftShift = 5 | ShiftMask,
3173 RightShift = 6 | ShiftMask,
3175 LessThan = 7 | ComparisonMask | RelationalMask,
3176 GreaterThan = 8 | ComparisonMask | RelationalMask,
3177 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3178 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3179 Equality = 11 | ComparisonMask | EqualityMask,
3180 Inequality = 12 | ComparisonMask | EqualityMask,
3182 BitwiseAnd = 13 | BitwiseMask,
3183 ExclusiveOr = 14 | BitwiseMask,
3184 BitwiseOr = 15 | BitwiseMask,
3186 LogicalAnd = 16 | LogicalMask,
3187 LogicalOr = 17 | LogicalMask,
3192 ValuesOnlyMask = ArithmeticMask - 1,
3193 ArithmeticMask = 1 << 5,
3195 ComparisonMask = 1 << 7,
3196 EqualityMask = 1 << 8,
3197 BitwiseMask = 1 << 9,
3198 LogicalMask = 1 << 10,
3199 AdditionMask = 1 << 11,
3200 SubtractionMask = 1 << 12,
3201 RelationalMask = 1 << 13,
3203 DecomposedMask = 1 << 19,
3204 NullableMask = 1 << 20
3208 public enum State : byte
3212 UserOperatorsExcluded = 1 << 2
3215 readonly Operator oper;
3216 Expression left, right;
3218 ConvCast.Mode enum_conversion;
3220 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3221 : this (oper, left, right, State.Compound)
3225 public Binary (Operator oper, Expression left, Expression right, State state)
3226 : this (oper, left, right)
3231 public Binary (Operator oper, Expression left, Expression right)
3232 : this (oper, left, right, left.Location)
3236 public Binary (Operator oper, Expression left, Expression right, Location loc)
3246 public bool IsCompound {
3248 return (state & State.Compound) != 0;
3252 public Operator Oper {
3258 public Expression Left {
3264 public Expression Right {
3270 public override Location StartLocation {
3272 return left.StartLocation;
3279 /// Returns a stringified representation of the Operator
3281 string OperName (Operator oper)
3285 case Operator.Multiply:
3288 case Operator.Division:
3291 case Operator.Modulus:
3294 case Operator.Addition:
3297 case Operator.Subtraction:
3300 case Operator.LeftShift:
3303 case Operator.RightShift:
3306 case Operator.LessThan:
3309 case Operator.GreaterThan:
3312 case Operator.LessThanOrEqual:
3315 case Operator.GreaterThanOrEqual:
3318 case Operator.Equality:
3321 case Operator.Inequality:
3324 case Operator.BitwiseAnd:
3327 case Operator.BitwiseOr:
3330 case Operator.ExclusiveOr:
3333 case Operator.LogicalOr:
3336 case Operator.LogicalAnd:
3340 s = oper.ToString ();
3350 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3352 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3355 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3357 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3361 l = left.Type.GetSignatureForError ();
3362 r = right.Type.GetSignatureForError ();
3364 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3368 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3370 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3373 public override void FlowAnalysis (FlowAnalysisContext fc)
3376 // Optimized version when on-true/on-false data are not needed
3378 if ((oper & Operator.LogicalMask) == 0) {
3379 left.FlowAnalysis (fc);
3380 right.FlowAnalysis (fc);
3384 left.FlowAnalysisConditional (fc);
3385 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3386 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3388 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3389 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3390 right.FlowAnalysisConditional (fc);
3392 if (oper == Operator.LogicalOr)
3393 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3395 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3398 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3400 if ((oper & Operator.LogicalMask) == 0) {
3401 base.FlowAnalysisConditional (fc);
3405 left.FlowAnalysisConditional (fc);
3406 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3407 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3409 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3410 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3411 right.FlowAnalysisConditional (fc);
3413 var lc = left as Constant;
3414 if (oper == Operator.LogicalOr) {
3415 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3416 if (lc != null && lc.IsDefaultValue)
3417 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3419 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3421 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3422 if (lc != null && !lc.IsDefaultValue)
3423 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3425 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3430 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3432 string GetOperatorExpressionTypeName ()
3435 case Operator.Addition:
3436 return IsCompound ? "AddAssign" : "Add";
3437 case Operator.BitwiseAnd:
3438 return IsCompound ? "AndAssign" : "And";
3439 case Operator.BitwiseOr:
3440 return IsCompound ? "OrAssign" : "Or";
3441 case Operator.Division:
3442 return IsCompound ? "DivideAssign" : "Divide";
3443 case Operator.ExclusiveOr:
3444 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3445 case Operator.Equality:
3447 case Operator.GreaterThan:
3448 return "GreaterThan";
3449 case Operator.GreaterThanOrEqual:
3450 return "GreaterThanOrEqual";
3451 case Operator.Inequality:
3453 case Operator.LeftShift:
3454 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3455 case Operator.LessThan:
3457 case Operator.LessThanOrEqual:
3458 return "LessThanOrEqual";
3459 case Operator.LogicalAnd:
3461 case Operator.LogicalOr:
3463 case Operator.Modulus:
3464 return IsCompound ? "ModuloAssign" : "Modulo";
3465 case Operator.Multiply:
3466 return IsCompound ? "MultiplyAssign" : "Multiply";
3467 case Operator.RightShift:
3468 return IsCompound ? "RightShiftAssign" : "RightShift";
3469 case Operator.Subtraction:
3470 return IsCompound ? "SubtractAssign" : "Subtract";
3472 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3476 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3479 case Operator.Addition:
3480 return CSharp.Operator.OpType.Addition;
3481 case Operator.BitwiseAnd:
3482 case Operator.LogicalAnd:
3483 return CSharp.Operator.OpType.BitwiseAnd;
3484 case Operator.BitwiseOr:
3485 case Operator.LogicalOr:
3486 return CSharp.Operator.OpType.BitwiseOr;
3487 case Operator.Division:
3488 return CSharp.Operator.OpType.Division;
3489 case Operator.Equality:
3490 return CSharp.Operator.OpType.Equality;
3491 case Operator.ExclusiveOr:
3492 return CSharp.Operator.OpType.ExclusiveOr;
3493 case Operator.GreaterThan:
3494 return CSharp.Operator.OpType.GreaterThan;
3495 case Operator.GreaterThanOrEqual:
3496 return CSharp.Operator.OpType.GreaterThanOrEqual;
3497 case Operator.Inequality:
3498 return CSharp.Operator.OpType.Inequality;
3499 case Operator.LeftShift:
3500 return CSharp.Operator.OpType.LeftShift;
3501 case Operator.LessThan:
3502 return CSharp.Operator.OpType.LessThan;
3503 case Operator.LessThanOrEqual:
3504 return CSharp.Operator.OpType.LessThanOrEqual;
3505 case Operator.Modulus:
3506 return CSharp.Operator.OpType.Modulus;
3507 case Operator.Multiply:
3508 return CSharp.Operator.OpType.Multiply;
3509 case Operator.RightShift:
3510 return CSharp.Operator.OpType.RightShift;
3511 case Operator.Subtraction:
3512 return CSharp.Operator.OpType.Subtraction;
3514 throw new InternalErrorException (op.ToString ());
3518 public override bool ContainsEmitWithAwait ()
3520 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3523 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3528 case Operator.Multiply:
3529 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3530 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3531 opcode = OpCodes.Mul_Ovf;
3532 else if (!IsFloat (l))
3533 opcode = OpCodes.Mul_Ovf_Un;
3535 opcode = OpCodes.Mul;
3537 opcode = OpCodes.Mul;
3541 case Operator.Division:
3543 opcode = OpCodes.Div_Un;
3545 opcode = OpCodes.Div;
3548 case Operator.Modulus:
3550 opcode = OpCodes.Rem_Un;
3552 opcode = OpCodes.Rem;
3555 case Operator.Addition:
3556 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3557 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3558 opcode = OpCodes.Add_Ovf;
3559 else if (!IsFloat (l))
3560 opcode = OpCodes.Add_Ovf_Un;
3562 opcode = OpCodes.Add;
3564 opcode = OpCodes.Add;
3567 case Operator.Subtraction:
3568 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3569 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3570 opcode = OpCodes.Sub_Ovf;
3571 else if (!IsFloat (l))
3572 opcode = OpCodes.Sub_Ovf_Un;
3574 opcode = OpCodes.Sub;
3576 opcode = OpCodes.Sub;
3579 case Operator.RightShift:
3580 if (!(right is IntConstant)) {
3581 ec.EmitInt (GetShiftMask (l));
3582 ec.Emit (OpCodes.And);
3586 opcode = OpCodes.Shr_Un;
3588 opcode = OpCodes.Shr;
3591 case Operator.LeftShift:
3592 if (!(right is IntConstant)) {
3593 ec.EmitInt (GetShiftMask (l));
3594 ec.Emit (OpCodes.And);
3597 opcode = OpCodes.Shl;
3600 case Operator.Equality:
3601 opcode = OpCodes.Ceq;
3604 case Operator.Inequality:
3605 ec.Emit (OpCodes.Ceq);
3608 opcode = OpCodes.Ceq;
3611 case Operator.LessThan:
3613 opcode = OpCodes.Clt_Un;
3615 opcode = OpCodes.Clt;
3618 case Operator.GreaterThan:
3620 opcode = OpCodes.Cgt_Un;
3622 opcode = OpCodes.Cgt;
3625 case Operator.LessThanOrEqual:
3626 if (IsUnsigned (l) || IsFloat (l))
3627 ec.Emit (OpCodes.Cgt_Un);
3629 ec.Emit (OpCodes.Cgt);
3632 opcode = OpCodes.Ceq;
3635 case Operator.GreaterThanOrEqual:
3636 if (IsUnsigned (l) || IsFloat (l))
3637 ec.Emit (OpCodes.Clt_Un);
3639 ec.Emit (OpCodes.Clt);
3643 opcode = OpCodes.Ceq;
3646 case Operator.BitwiseOr:
3647 opcode = OpCodes.Or;
3650 case Operator.BitwiseAnd:
3651 opcode = OpCodes.And;
3654 case Operator.ExclusiveOr:
3655 opcode = OpCodes.Xor;
3659 throw new InternalErrorException (oper.ToString ());
3665 static int GetShiftMask (TypeSpec type)
3667 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3670 static bool IsUnsigned (TypeSpec t)
3672 switch (t.BuiltinType) {
3673 case BuiltinTypeSpec.Type.Char:
3674 case BuiltinTypeSpec.Type.UInt:
3675 case BuiltinTypeSpec.Type.ULong:
3676 case BuiltinTypeSpec.Type.UShort:
3677 case BuiltinTypeSpec.Type.Byte:
3684 static bool IsFloat (TypeSpec t)
3686 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3689 public Expression ResolveOperator (ResolveContext rc)
3691 eclass = ExprClass.Value;
3693 TypeSpec l = left.Type;
3694 TypeSpec r = right.Type;
3696 bool primitives_only = false;
3699 // Handles predefined primitive types
3701 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3702 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3703 if ((oper & Operator.ShiftMask) == 0) {
3704 if (!DoBinaryOperatorPromotion (rc))
3707 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3711 if (l.IsPointer || r.IsPointer)
3712 return ResolveOperatorPointer (rc, l, r);
3715 if ((state & State.UserOperatorsExcluded) == 0) {
3716 expr = ResolveUserOperator (rc, left, right);
3721 bool lenum = l.IsEnum;
3722 bool renum = r.IsEnum;
3723 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3727 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3728 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3733 if ((oper & Operator.BitwiseMask) != 0) {
3734 expr = EmptyCast.Create (expr, type);
3735 enum_conversion = GetEnumResultCast (type);
3737 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3738 expr = OptimizeAndOperation (expr);
3742 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3743 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3746 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3747 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3751 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3754 // We cannot break here there is also Enum + String possible match
3755 // which is not ambiguous with predefined enum operators
3758 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3759 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3763 } else if (l.IsDelegate || r.IsDelegate) {
3767 expr = ResolveOperatorDelegate (rc, l, r);
3769 // TODO: Can this be ambiguous
3777 // Equality operators are more complicated
3779 if ((oper & Operator.EqualityMask) != 0) {
3780 return ResolveEquality (rc, l, r, primitives_only);
3783 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3787 if (primitives_only)
3791 // Lifted operators have lower priority
3793 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3796 static bool IsEnumOrNullableEnum (TypeSpec type)
3798 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3802 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3803 // if 'left' is not an enumeration constant, create one from the type of 'right'
3804 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3807 case Operator.BitwiseOr:
3808 case Operator.BitwiseAnd:
3809 case Operator.ExclusiveOr:
3810 case Operator.Equality:
3811 case Operator.Inequality:
3812 case Operator.LessThan:
3813 case Operator.LessThanOrEqual:
3814 case Operator.GreaterThan:
3815 case Operator.GreaterThanOrEqual:
3816 if (left.Type.IsEnum)
3819 if (left.IsZeroInteger)
3820 return left.Reduce (ec, right.Type);
3824 case Operator.Addition:
3825 case Operator.Subtraction:
3828 case Operator.Multiply:
3829 case Operator.Division:
3830 case Operator.Modulus:
3831 case Operator.LeftShift:
3832 case Operator.RightShift:
3833 if (right.Type.IsEnum || left.Type.IsEnum)
3842 // The `|' operator used on types which were extended is dangerous
3844 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3846 OpcodeCast lcast = left as OpcodeCast;
3847 if (lcast != null) {
3848 if (IsUnsigned (lcast.UnderlyingType))
3852 OpcodeCast rcast = right as OpcodeCast;
3853 if (rcast != null) {
3854 if (IsUnsigned (rcast.UnderlyingType))
3858 if (lcast == null && rcast == null)
3861 // FIXME: consider constants
3863 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3864 ec.Report.Warning (675, 3, loc,
3865 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3866 ltype.GetSignatureForError ());
3869 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3871 return new PredefinedOperator[] {
3873 // Pointer arithmetic:
3875 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3876 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3877 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3878 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3880 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3881 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3882 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3883 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3886 // T* operator + (int y, T* x);
3887 // T* operator + (uint y, T *x);
3888 // T* operator + (long y, T *x);
3889 // T* operator + (ulong y, T *x);
3891 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3892 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3893 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3894 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3897 // long operator - (T* x, T *y)
3899 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3903 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3905 TypeSpec bool_type = types.Bool;
3908 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3909 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3910 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3911 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3912 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3913 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3914 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3916 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3917 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3918 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3919 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3920 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3921 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3922 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3924 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3925 // Remaining string operators are in lifted tables
3927 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3929 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3930 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3931 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3935 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3937 var types = module.Compiler.BuiltinTypes;
3940 // Not strictly lifted but need to be in second group otherwise expressions like
3941 // int + null would resolve to +(object, string) instead of +(int?, int?)
3943 var string_operators = new [] {
3944 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3945 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3948 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3949 if (nullable == null)
3950 return string_operators;
3952 var bool_type = types.Bool;
3954 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3955 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3956 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3957 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3958 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3959 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3960 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3961 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3964 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3965 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3966 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3967 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3968 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3969 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3970 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3972 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3973 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3974 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3975 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3976 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3977 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3978 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3980 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3982 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3983 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3984 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3986 string_operators [0],
3987 string_operators [1]
3991 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3993 TypeSpec bool_type = types.Bool;
3996 new PredefinedEqualityOperator (types.String, bool_type),
3997 new PredefinedEqualityOperator (types.Delegate, bool_type),
3998 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3999 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
4000 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
4001 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
4002 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
4003 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
4004 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
4005 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
4009 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
4011 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4013 if (nullable == null)
4014 return new PredefinedOperator [0];
4016 var types = module.Compiler.BuiltinTypes;
4017 var bool_type = types.Bool;
4018 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
4019 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4020 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4021 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4022 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4023 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4024 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4025 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4028 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4029 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4030 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4031 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4032 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4033 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4034 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4035 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4040 // 7.2.6.2 Binary numeric promotions
4042 bool DoBinaryOperatorPromotion (ResolveContext rc)
4044 TypeSpec ltype = left.Type;
4045 if (ltype.IsNullableType) {
4046 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4050 // This is numeric promotion code only
4052 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4055 TypeSpec rtype = right.Type;
4056 if (rtype.IsNullableType) {
4057 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4060 var lb = ltype.BuiltinType;
4061 var rb = rtype.BuiltinType;
4065 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4066 type = rc.BuiltinTypes.Decimal;
4067 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4068 type = rc.BuiltinTypes.Double;
4069 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4070 type = rc.BuiltinTypes.Float;
4071 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4072 type = rc.BuiltinTypes.ULong;
4074 if (IsSignedType (lb)) {
4075 expr = ConvertSignedConstant (left, type);
4079 } else if (IsSignedType (rb)) {
4080 expr = ConvertSignedConstant (right, type);
4086 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4087 type = rc.BuiltinTypes.Long;
4088 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4089 type = rc.BuiltinTypes.UInt;
4091 if (IsSignedType (lb)) {
4092 expr = ConvertSignedConstant (left, type);
4094 type = rc.BuiltinTypes.Long;
4095 } else if (IsSignedType (rb)) {
4096 expr = ConvertSignedConstant (right, type);
4098 type = rc.BuiltinTypes.Long;
4101 type = rc.BuiltinTypes.Int;
4104 if (ltype != type) {
4105 expr = PromoteExpression (rc, left, type);
4112 if (rtype != type) {
4113 expr = PromoteExpression (rc, right, type);
4123 static bool IsSignedType (BuiltinTypeSpec.Type type)
4126 case BuiltinTypeSpec.Type.Int:
4127 case BuiltinTypeSpec.Type.Short:
4128 case BuiltinTypeSpec.Type.SByte:
4129 case BuiltinTypeSpec.Type.Long:
4136 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4138 var c = expr as Constant;
4142 return c.ConvertImplicitly (type);
4145 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4147 if (expr.Type.IsNullableType) {
4148 return Convert.ImplicitConversionStandard (rc, expr,
4149 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4152 var c = expr as Constant;
4154 return c.ConvertImplicitly (type);
4156 return Convert.ImplicitNumericConversion (expr, type);
4159 protected override Expression DoResolve (ResolveContext ec)
4164 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4165 left = ((ParenthesizedExpression) left).Expr;
4166 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4170 if (left.eclass == ExprClass.Type) {
4171 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4175 left = left.Resolve (ec);
4180 right = right.Resolve (ec);
4184 Constant lc = left as Constant;
4185 Constant rc = right as Constant;
4187 // The conversion rules are ignored in enum context but why
4188 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4189 lc = EnumLiftUp (ec, lc, rc);
4191 rc = EnumLiftUp (ec, rc, lc);
4194 if (rc != null && lc != null) {
4195 int prev_e = ec.Report.Errors;
4196 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4197 if (e != null || ec.Report.Errors != prev_e)
4201 // Comparison warnings
4202 if ((oper & Operator.ComparisonMask) != 0) {
4203 if (left.Equals (right)) {
4204 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4206 CheckOutOfRangeComparison (ec, lc, right.Type);
4207 CheckOutOfRangeComparison (ec, rc, left.Type);
4210 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4211 return DoResolveDynamic (ec);
4213 return DoResolveCore (ec, left, right);
4216 Expression DoResolveDynamic (ResolveContext rc)
4219 var rt = right.Type;
4220 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4221 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4222 Error_OperatorCannotBeApplied (rc, left, right);
4229 // Special handling for logical boolean operators which require rhs not to be
4230 // evaluated based on lhs value
4232 if ((oper & Operator.LogicalMask) != 0) {
4233 Expression cond_left, cond_right, expr;
4235 args = new Arguments (2);
4237 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4238 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4240 var cond_args = new Arguments (1);
4241 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4244 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4245 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4247 left = temp.CreateReferenceExpression (rc, loc);
4248 if (oper == Operator.LogicalAnd) {
4249 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4252 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4256 args.Add (new Argument (left));
4257 args.Add (new Argument (right));
4258 cond_right = new DynamicExpressionStatement (this, args, loc);
4260 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4262 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4263 rc.Report.Error (7083, left.Location,
4264 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4265 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4269 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4270 args.Add (new Argument (right));
4271 right = new DynamicExpressionStatement (this, args, loc);
4274 // bool && dynamic => (temp = left) ? temp && right : temp;
4275 // bool || dynamic => (temp = left) ? temp : temp || right;
4277 if (oper == Operator.LogicalAnd) {
4279 cond_right = temp.CreateReferenceExpression (rc, loc);
4281 cond_left = temp.CreateReferenceExpression (rc, loc);
4285 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4288 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4291 args = new Arguments (2);
4292 args.Add (new Argument (left));
4293 args.Add (new Argument (right));
4294 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4297 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4299 Expression expr = ResolveOperator (ec);
4301 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4303 if (left == null || right == null)
4304 throw new InternalErrorException ("Invalid conversion");
4306 if (oper == Operator.BitwiseOr)
4307 CheckBitwiseOrOnSignExtended (ec);
4312 public override SLE.Expression MakeExpression (BuilderContext ctx)
4314 return MakeExpression (ctx, left, right);
4317 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4319 var le = left.MakeExpression (ctx);
4320 var re = right.MakeExpression (ctx);
4321 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4324 case Operator.Addition:
4325 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4326 case Operator.BitwiseAnd:
4327 return SLE.Expression.And (le, re);
4328 case Operator.BitwiseOr:
4329 return SLE.Expression.Or (le, re);
4330 case Operator.Division:
4331 return SLE.Expression.Divide (le, re);
4332 case Operator.Equality:
4333 return SLE.Expression.Equal (le, re);
4334 case Operator.ExclusiveOr:
4335 return SLE.Expression.ExclusiveOr (le, re);
4336 case Operator.GreaterThan:
4337 return SLE.Expression.GreaterThan (le, re);
4338 case Operator.GreaterThanOrEqual:
4339 return SLE.Expression.GreaterThanOrEqual (le, re);
4340 case Operator.Inequality:
4341 return SLE.Expression.NotEqual (le, re);
4342 case Operator.LeftShift:
4343 return SLE.Expression.LeftShift (le, re);
4344 case Operator.LessThan:
4345 return SLE.Expression.LessThan (le, re);
4346 case Operator.LessThanOrEqual:
4347 return SLE.Expression.LessThanOrEqual (le, re);
4348 case Operator.LogicalAnd:
4349 return SLE.Expression.AndAlso (le, re);
4350 case Operator.LogicalOr:
4351 return SLE.Expression.OrElse (le, re);
4352 case Operator.Modulus:
4353 return SLE.Expression.Modulo (le, re);
4354 case Operator.Multiply:
4355 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4356 case Operator.RightShift:
4357 return SLE.Expression.RightShift (le, re);
4358 case Operator.Subtraction:
4359 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4361 throw new NotImplementedException (oper.ToString ());
4366 // D operator + (D x, D y)
4367 // D operator - (D x, D y)
4369 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4371 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4373 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4374 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4379 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4380 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4390 MethodSpec method = null;
4391 Arguments args = new Arguments (2);
4392 args.Add (new Argument (left));
4393 args.Add (new Argument (right));
4395 if (oper == Operator.Addition) {
4396 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4397 } else if (oper == Operator.Subtraction) {
4398 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4402 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4404 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4405 return new ClassCast (expr, l);
4409 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4411 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4414 // bool operator == (E x, E y);
4415 // bool operator != (E x, E y);
4416 // bool operator < (E x, E y);
4417 // bool operator > (E x, E y);
4418 // bool operator <= (E x, E y);
4419 // bool operator >= (E x, E y);
4421 // E operator & (E x, E y);
4422 // E operator | (E x, E y);
4423 // E operator ^ (E x, E y);
4426 if ((oper & Operator.ComparisonMask) != 0) {
4427 type = rc.BuiltinTypes.Bool;
4433 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4439 if (ltype == rtype) {
4443 var lifted = new Nullable.LiftedBinaryOperator (this);
4445 lifted.Right = right;
4446 return lifted.Resolve (rc);
4449 if (renum && !ltype.IsNullableType) {
4450 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4455 } else if (lenum && !rtype.IsNullableType) {
4456 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4464 // Now try lifted version of predefined operator
4466 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4467 if (nullable_type != null) {
4468 if (renum && !ltype.IsNullableType) {
4469 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4471 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4474 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4477 if ((oper & Operator.BitwiseMask) != 0)
4481 if ((oper & Operator.BitwiseMask) != 0)
4482 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4484 return CreateLiftedValueTypeResult (rc, rtype);
4488 var lifted = new Nullable.LiftedBinaryOperator (this);
4490 lifted.Right = right;
4491 return lifted.Resolve (rc);
4493 } else if (lenum && !rtype.IsNullableType) {
4494 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4496 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4499 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4502 if ((oper & Operator.BitwiseMask) != 0)
4506 if ((oper & Operator.BitwiseMask) != 0)
4507 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4509 return CreateLiftedValueTypeResult (rc, ltype);
4513 var lifted = new Nullable.LiftedBinaryOperator (this);
4515 lifted.Right = expr;
4516 return lifted.Resolve (rc);
4518 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4519 Nullable.Unwrap unwrap = null;
4520 if (left.IsNull || right.IsNull) {
4521 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4522 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4524 if ((oper & Operator.RelationalMask) != 0)
4525 return CreateLiftedValueTypeResult (rc, rtype);
4527 if ((oper & Operator.BitwiseMask) != 0)
4528 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4531 return CreateLiftedValueTypeResult (rc, left.Type);
4533 // Equality operators are valid between E? and null
4535 unwrap = new Nullable.Unwrap (right);
4537 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4541 if ((oper & Operator.BitwiseMask) != 0)
4546 var lifted = new Nullable.LiftedBinaryOperator (this);
4548 lifted.Right = right;
4549 lifted.UnwrapRight = unwrap;
4550 return lifted.Resolve (rc);
4552 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4553 Nullable.Unwrap unwrap = null;
4554 if (right.IsNull || left.IsNull) {
4555 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4556 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4558 if ((oper & Operator.RelationalMask) != 0)
4559 return CreateLiftedValueTypeResult (rc, ltype);
4561 if ((oper & Operator.BitwiseMask) != 0)
4562 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4565 return CreateLiftedValueTypeResult (rc, right.Type);
4567 // Equality operators are valid between E? and null
4569 unwrap = new Nullable.Unwrap (left);
4571 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4575 if ((oper & Operator.BitwiseMask) != 0)
4580 var lifted = new Nullable.LiftedBinaryOperator (this);
4582 lifted.UnwrapLeft = unwrap;
4583 lifted.Right = expr;
4584 return lifted.Resolve (rc);
4592 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4594 TypeSpec underlying_type;
4595 if (expr.Type.IsNullableType) {
4596 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4598 underlying_type = EnumSpec.GetUnderlyingType (nt);
4600 underlying_type = nt;
4601 } else if (expr.Type.IsEnum) {
4602 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4604 underlying_type = expr.Type;
4607 switch (underlying_type.BuiltinType) {
4608 case BuiltinTypeSpec.Type.SByte:
4609 case BuiltinTypeSpec.Type.Byte:
4610 case BuiltinTypeSpec.Type.Short:
4611 case BuiltinTypeSpec.Type.UShort:
4612 underlying_type = rc.BuiltinTypes.Int;
4616 if (expr.Type.IsNullableType || liftType)
4617 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4619 if (expr.Type == underlying_type)
4622 return EmptyCast.Create (expr, underlying_type);
4625 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4628 // U operator - (E e, E f)
4629 // E operator - (E e, U x) // Internal decomposition operator
4630 // E operator - (U x, E e) // Internal decomposition operator
4632 // E operator + (E e, U x)
4633 // E operator + (U x, E e)
4642 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4648 if (!enum_type.IsNullableType) {
4649 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4651 if (oper == Operator.Subtraction)
4652 expr = ConvertEnumSubtractionResult (rc, expr);
4654 expr = ConvertEnumAdditionalResult (expr, enum_type);
4656 enum_conversion = GetEnumResultCast (expr.Type);
4661 var nullable = rc.Module.PredefinedTypes.Nullable;
4664 // Don't try nullable version when nullable type is undefined
4666 if (!nullable.IsDefined)
4669 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4672 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4674 if (oper == Operator.Subtraction)
4675 expr = ConvertEnumSubtractionResult (rc, expr);
4677 expr = ConvertEnumAdditionalResult (expr, enum_type);
4679 enum_conversion = GetEnumResultCast (expr.Type);
4685 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4687 return EmptyCast.Create (expr, enumType);
4690 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4693 // Enumeration subtraction has different result type based on
4696 TypeSpec result_type;
4697 if (left.Type == right.Type) {
4698 var c = right as EnumConstant;
4699 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4701 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4702 // E which is not what expressions E - 1 or 0 - E return
4704 result_type = left.Type;
4706 result_type = left.Type.IsNullableType ?
4707 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4708 EnumSpec.GetUnderlyingType (left.Type);
4711 if (IsEnumOrNullableEnum (left.Type)) {
4712 result_type = left.Type;
4714 result_type = right.Type;
4717 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4718 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4721 return EmptyCast.Create (expr, result_type);
4724 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4726 if (type.IsNullableType)
4727 type = Nullable.NullableInfo.GetUnderlyingType (type);
4730 type = EnumSpec.GetUnderlyingType (type);
4732 switch (type.BuiltinType) {
4733 case BuiltinTypeSpec.Type.SByte:
4734 return ConvCast.Mode.I4_I1;
4735 case BuiltinTypeSpec.Type.Byte:
4736 return ConvCast.Mode.I4_U1;
4737 case BuiltinTypeSpec.Type.Short:
4738 return ConvCast.Mode.I4_I2;
4739 case BuiltinTypeSpec.Type.UShort:
4740 return ConvCast.Mode.I4_U2;
4747 // Equality operators rules
4749 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4752 type = ec.BuiltinTypes.Bool;
4753 bool no_arg_conv = false;
4755 if (!primitives_only) {
4758 // a, Both operands are reference-type values or the value null
4759 // b, One operand is a value of type T where T is a type-parameter and
4760 // the other operand is the value null. Furthermore T does not have the
4761 // value type constraint
4763 // LAMESPEC: Very confusing details in the specification, basically any
4764 // reference like type-parameter is allowed
4766 var tparam_l = l as TypeParameterSpec;
4767 var tparam_r = r as TypeParameterSpec;
4768 if (tparam_l != null) {
4769 if (right is NullLiteral) {
4770 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4773 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4777 if (!tparam_l.IsReferenceType)
4780 l = tparam_l.GetEffectiveBase ();
4781 left = new BoxedCast (left, l);
4782 } else if (left is NullLiteral && tparam_r == null) {
4783 if (TypeSpec.IsReferenceType (r))
4786 if (r.Kind == MemberKind.InternalCompilerType)
4790 if (tparam_r != null) {
4791 if (left is NullLiteral) {
4792 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4795 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4799 if (!tparam_r.IsReferenceType)
4802 r = tparam_r.GetEffectiveBase ();
4803 right = new BoxedCast (right, r);
4804 } else if (right is NullLiteral) {
4805 if (TypeSpec.IsReferenceType (l))
4808 if (l.Kind == MemberKind.InternalCompilerType)
4813 // LAMESPEC: method groups can be compared when they convert to other side delegate
4816 if (right.eclass == ExprClass.MethodGroup) {
4817 result = Convert.ImplicitConversion (ec, right, l, loc);
4823 } else if (r.IsDelegate && l != r) {
4826 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4827 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4834 no_arg_conv = l == r && !l.IsStruct;
4839 // bool operator != (string a, string b)
4840 // bool operator == (string a, string b)
4842 // bool operator != (Delegate a, Delegate b)
4843 // bool operator == (Delegate a, Delegate b)
4845 // bool operator != (bool a, bool b)
4846 // bool operator == (bool a, bool b)
4848 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4849 // they implement an implicit conversion to any of types above. This does
4850 // not apply when both operands are of same reference type
4852 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4853 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4858 // Now try lifted version of predefined operators
4860 if (no_arg_conv && !l.IsNullableType) {
4862 // Optimizes cases which won't match
4865 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4871 // The == and != operators permit one operand to be a value of a nullable
4872 // type and the other to be the null literal, even if no predefined or user-defined
4873 // operator (in unlifted or lifted form) exists for the operation.
4875 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4876 var lifted = new Nullable.LiftedBinaryOperator (this);
4878 lifted.Right = right;
4879 return lifted.Resolve (ec);
4884 // bool operator != (object a, object b)
4885 // bool operator == (object a, object b)
4887 // An explicit reference conversion exists from the
4888 // type of either operand to the type of the other operand.
4891 // Optimize common path
4893 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4896 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4897 !Convert.ExplicitReferenceConversionExists (r, l))
4900 // Reject allowed explicit conversions like int->object
4901 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4904 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4905 ec.Report.Warning (253, 2, loc,
4906 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4907 l.GetSignatureForError ());
4909 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4910 ec.Report.Warning (252, 2, loc,
4911 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4912 r.GetSignatureForError ());
4918 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4921 // bool operator == (void* x, void* y);
4922 // bool operator != (void* x, void* y);
4923 // bool operator < (void* x, void* y);
4924 // bool operator > (void* x, void* y);
4925 // bool operator <= (void* x, void* y);
4926 // bool operator >= (void* x, void* y);
4928 if ((oper & Operator.ComparisonMask) != 0) {
4931 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4938 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4944 type = ec.BuiltinTypes.Bool;
4948 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4952 // Build-in operators method overloading
4954 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4956 PredefinedOperator best_operator = null;
4957 TypeSpec l = left.Type;
4958 TypeSpec r = right.Type;
4959 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4961 foreach (PredefinedOperator po in operators) {
4962 if ((po.OperatorsMask & oper_mask) == 0)
4965 if (primitives_only) {
4966 if (!po.IsPrimitiveApplicable (l, r))
4969 if (!po.IsApplicable (ec, left, right))
4973 if (best_operator == null) {
4975 if (primitives_only)
4981 best_operator = po.ResolveBetterOperator (ec, best_operator);
4983 if (best_operator == null) {
4984 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4985 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4992 if (best_operator == null)
4995 return best_operator.ConvertResult (ec, this);
4999 // Optimize & constant expressions with 0 value
5001 Expression OptimizeAndOperation (Expression expr)
5003 Constant rc = right as Constant;
5004 Constant lc = left as Constant;
5005 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
5007 // The result is a constant with side-effect
5009 Constant side_effect = rc == null ?
5010 new SideEffectConstant (lc, right, loc) :
5011 new SideEffectConstant (rc, left, loc);
5013 return ReducedExpression.Create (side_effect, expr);
5020 // Value types can be compared with the null literal because of the lifting
5021 // language rules. However the result is always true or false.
5023 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5025 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5026 type = rc.BuiltinTypes.Bool;
5030 // FIXME: Handle side effect constants
5031 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5033 if ((Oper & Operator.EqualityMask) != 0) {
5034 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5035 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5037 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5038 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5045 // Performs user-operator overloading
5047 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5049 Expression oper_expr;
5051 var op = ConvertBinaryToUserOperator (oper);
5053 if (l.IsNullableType)
5054 l = Nullable.NullableInfo.GetUnderlyingType (l);
5056 if (r.IsNullableType)
5057 r = Nullable.NullableInfo.GetUnderlyingType (r);
5059 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5060 IList<MemberSpec> right_operators = null;
5063 right_operators = MemberCache.GetUserOperator (r, op, false);
5064 if (right_operators == null && left_operators == null)
5066 } else if (left_operators == null) {
5070 Arguments args = new Arguments (2);
5071 Argument larg = new Argument (left);
5073 Argument rarg = new Argument (right);
5077 // User-defined operator implementations always take precedence
5078 // over predefined operator implementations
5080 if (left_operators != null && right_operators != null) {
5081 left_operators = CombineUserOperators (left_operators, right_operators);
5082 } else if (right_operators != null) {
5083 left_operators = right_operators;
5086 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5087 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5089 var res = new OverloadResolver (left_operators, restr, loc);
5091 var oper_method = res.ResolveOperator (rc, ref args);
5092 if (oper_method == null) {
5094 // Logical && and || cannot be lifted
5096 if ((oper & Operator.LogicalMask) != 0)
5100 // Apply lifted user operators only for liftable types. Implicit conversion
5101 // to nullable types is not allowed
5103 if (!IsLiftedOperatorApplicable ())
5106 // TODO: Cache the result in module container
5107 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5108 if (lifted_methods == null)
5111 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5113 oper_method = res.ResolveOperator (rc, ref args);
5114 if (oper_method == null)
5117 MethodSpec best_original = null;
5118 foreach (MethodSpec ms in left_operators) {
5119 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5125 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5127 // Expression trees use lifted notation in this case
5129 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5130 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5133 var ptypes = best_original.Parameters.Types;
5135 if (left.IsNull || right.IsNull) {
5137 // The lifted operator produces a null value if one or both operands are null
5139 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5140 type = oper_method.ReturnType;
5141 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5145 // The lifted operator produces the value false if one or both operands are null for
5146 // relational operators.
5148 if ((oper & Operator.RelationalMask) != 0) {
5150 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5151 // because return type is actually bool
5153 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5156 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5157 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5161 type = oper_method.ReturnType;
5162 var lifted = new Nullable.LiftedBinaryOperator (this);
5163 lifted.UserOperator = best_original;
5165 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5166 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5169 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5170 lifted.UnwrapRight = new Nullable.Unwrap (right);
5173 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5174 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5176 return lifted.Resolve (rc);
5179 if ((oper & Operator.LogicalMask) != 0) {
5180 // TODO: CreateExpressionTree is allocated every time
5181 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5182 oper == Operator.LogicalAnd, loc).Resolve (rc);
5184 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5187 this.left = larg.Expr;
5188 this.right = rarg.Expr;
5193 bool IsLiftedOperatorApplicable ()
5195 if (left.Type.IsNullableType) {
5196 if ((oper & Operator.EqualityMask) != 0)
5197 return !right.IsNull;
5202 if (right.Type.IsNullableType) {
5203 if ((oper & Operator.EqualityMask) != 0)
5204 return !left.IsNull;
5209 if (TypeSpec.IsValueType (left.Type))
5210 return right.IsNull;
5212 if (TypeSpec.IsValueType (right.Type))
5218 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5220 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5221 if (nullable_type == null)
5225 // Lifted operators permit predefined and user-defined operators that operate
5226 // on non-nullable value types to also be used with nullable forms of those types.
5227 // Lifted operators are constructed from predefined and user-defined operators
5228 // that meet certain requirements
5230 List<MemberSpec> lifted = null;
5231 foreach (MethodSpec oper in operators) {
5233 if ((Oper & Operator.ComparisonMask) != 0) {
5235 // Result type must be of type bool for lifted comparison operators
5237 rt = oper.ReturnType;
5238 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5241 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5247 var ptypes = oper.Parameters.Types;
5248 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5252 // LAMESPEC: I am not sure why but for equality operators to be lifted
5253 // both types have to match
5255 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5259 lifted = new List<MemberSpec> ();
5262 // The lifted form is constructed by adding a single ? modifier to each operand and
5263 // result type except for comparison operators where return type is bool
5266 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5268 var parameters = ParametersCompiled.CreateFullyResolved (
5269 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5270 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5272 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5273 rt, parameters, oper.Modifiers);
5275 lifted.Add (lifted_op);
5282 // Merge two sets of user operators into one, they are mostly distinguish
5283 // except when they share base type and it contains an operator
5285 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5287 var combined = new List<MemberSpec> (left.Count + right.Count);
5288 combined.AddRange (left);
5289 foreach (var r in right) {
5291 foreach (var l in left) {
5292 if (l.DeclaringType == r.DeclaringType) {
5305 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5307 if (c is IntegralConstant || c is CharConstant) {
5309 c.ConvertExplicitly (true, type);
5310 } catch (OverflowException) {
5311 ec.Report.Warning (652, 2, loc,
5312 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5313 type.GetSignatureForError ());
5319 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5320 /// context of a conditional bool expression. This function will return
5321 /// false if it is was possible to use EmitBranchable, or true if it was.
5323 /// The expression's code is generated, and we will generate a branch to `target'
5324 /// if the resulting expression value is equal to isTrue
5326 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5328 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5329 left = left.EmitToField (ec);
5331 if ((oper & Operator.LogicalMask) == 0) {
5332 right = right.EmitToField (ec);
5337 // This is more complicated than it looks, but its just to avoid
5338 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5339 // but on top of that we want for == and != to use a special path
5340 // if we are comparing against null
5342 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5343 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5346 // put the constant on the rhs, for simplicity
5348 if (left is Constant) {
5349 Expression swap = right;
5355 // brtrue/brfalse works with native int only
5357 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5358 left.EmitBranchable (ec, target, my_on_true);
5361 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5362 // right is a boolean, and it's not 'false' => it is 'true'
5363 left.EmitBranchable (ec, target, !my_on_true);
5367 } else if (oper == Operator.LogicalAnd) {
5370 Label tests_end = ec.DefineLabel ();
5372 left.EmitBranchable (ec, tests_end, false);
5373 right.EmitBranchable (ec, target, true);
5374 ec.MarkLabel (tests_end);
5377 // This optimizes code like this
5378 // if (true && i > 4)
5380 if (!(left is Constant))
5381 left.EmitBranchable (ec, target, false);
5383 if (!(right is Constant))
5384 right.EmitBranchable (ec, target, false);
5389 } else if (oper == Operator.LogicalOr){
5391 left.EmitBranchable (ec, target, true);
5392 right.EmitBranchable (ec, target, true);
5395 Label tests_end = ec.DefineLabel ();
5396 left.EmitBranchable (ec, tests_end, true);
5397 right.EmitBranchable (ec, target, false);
5398 ec.MarkLabel (tests_end);
5403 } else if ((oper & Operator.ComparisonMask) == 0) {
5404 base.EmitBranchable (ec, target, on_true);
5411 TypeSpec t = left.Type;
5412 bool is_float = IsFloat (t);
5413 bool is_unsigned = is_float || IsUnsigned (t);
5416 case Operator.Equality:
5418 ec.Emit (OpCodes.Beq, target);
5420 ec.Emit (OpCodes.Bne_Un, target);
5423 case Operator.Inequality:
5425 ec.Emit (OpCodes.Bne_Un, target);
5427 ec.Emit (OpCodes.Beq, target);
5430 case Operator.LessThan:
5432 if (is_unsigned && !is_float)
5433 ec.Emit (OpCodes.Blt_Un, target);
5435 ec.Emit (OpCodes.Blt, target);
5438 ec.Emit (OpCodes.Bge_Un, target);
5440 ec.Emit (OpCodes.Bge, target);
5443 case Operator.GreaterThan:
5445 if (is_unsigned && !is_float)
5446 ec.Emit (OpCodes.Bgt_Un, target);
5448 ec.Emit (OpCodes.Bgt, target);
5451 ec.Emit (OpCodes.Ble_Un, target);
5453 ec.Emit (OpCodes.Ble, target);
5456 case Operator.LessThanOrEqual:
5458 if (is_unsigned && !is_float)
5459 ec.Emit (OpCodes.Ble_Un, target);
5461 ec.Emit (OpCodes.Ble, target);
5464 ec.Emit (OpCodes.Bgt_Un, target);
5466 ec.Emit (OpCodes.Bgt, target);
5470 case Operator.GreaterThanOrEqual:
5472 if (is_unsigned && !is_float)
5473 ec.Emit (OpCodes.Bge_Un, target);
5475 ec.Emit (OpCodes.Bge, target);
5478 ec.Emit (OpCodes.Blt_Un, target);
5480 ec.Emit (OpCodes.Blt, target);
5483 throw new InternalErrorException (oper.ToString ());
5487 public override void Emit (EmitContext ec)
5489 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5490 left = left.EmitToField (ec);
5492 if ((oper & Operator.LogicalMask) == 0) {
5493 right = right.EmitToField (ec);
5498 // Handle short-circuit operators differently
5501 if ((oper & Operator.LogicalMask) != 0) {
5502 Label load_result = ec.DefineLabel ();
5503 Label end = ec.DefineLabel ();
5505 bool is_or = oper == Operator.LogicalOr;
5506 left.EmitBranchable (ec, load_result, is_or);
5508 ec.Emit (OpCodes.Br_S, end);
5510 ec.MarkLabel (load_result);
5511 ec.EmitInt (is_or ? 1 : 0);
5517 // Optimize zero-based operations which cannot be optimized at expression level
5519 if (oper == Operator.Subtraction) {
5520 var lc = left as IntegralConstant;
5521 if (lc != null && lc.IsDefaultValue) {
5523 ec.Emit (OpCodes.Neg);
5528 EmitOperator (ec, left, right);
5531 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5536 EmitOperatorOpcode (ec, oper, left.Type, right);
5539 // Emit result enumerable conversion this way because it's quite complicated get it
5540 // to resolved tree because expression tree cannot see it.
5542 if (enum_conversion != 0)
5543 ConvCast.Emit (ec, enum_conversion);
5546 public override void EmitSideEffect (EmitContext ec)
5548 if ((oper & Operator.LogicalMask) != 0 ||
5549 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5550 base.EmitSideEffect (ec);
5552 left.EmitSideEffect (ec);
5553 right.EmitSideEffect (ec);
5557 public override Expression EmitToField (EmitContext ec)
5559 if ((oper & Operator.LogicalMask) == 0) {
5560 var await_expr = left as Await;
5561 if (await_expr != null && right.IsSideEffectFree) {
5562 await_expr.Statement.EmitPrologue (ec);
5563 left = await_expr.Statement.GetResultExpression (ec);
5567 await_expr = right as Await;
5568 if (await_expr != null && left.IsSideEffectFree) {
5569 await_expr.Statement.EmitPrologue (ec);
5570 right = await_expr.Statement.GetResultExpression (ec);
5575 return base.EmitToField (ec);
5578 protected override void CloneTo (CloneContext clonectx, Expression t)
5580 Binary target = (Binary) t;
5582 target.left = left.Clone (clonectx);
5583 target.right = right.Clone (clonectx);
5586 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5588 Arguments binder_args = new Arguments (4);
5590 MemberAccess sle = new MemberAccess (new MemberAccess (
5591 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5593 CSharpBinderFlags flags = 0;
5594 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5595 flags = CSharpBinderFlags.CheckedContext;
5597 if ((oper & Operator.LogicalMask) != 0)
5598 flags |= CSharpBinderFlags.BinaryOperationLogical;
5600 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5601 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5602 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5603 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5605 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5608 public override Expression CreateExpressionTree (ResolveContext ec)
5610 return CreateExpressionTree (ec, null);
5613 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5616 bool lift_arg = false;
5619 case Operator.Addition:
5620 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5621 method_name = "AddChecked";
5623 method_name = "Add";
5625 case Operator.BitwiseAnd:
5626 method_name = "And";
5628 case Operator.BitwiseOr:
5631 case Operator.Division:
5632 method_name = "Divide";
5634 case Operator.Equality:
5635 method_name = "Equal";
5638 case Operator.ExclusiveOr:
5639 method_name = "ExclusiveOr";
5641 case Operator.GreaterThan:
5642 method_name = "GreaterThan";
5645 case Operator.GreaterThanOrEqual:
5646 method_name = "GreaterThanOrEqual";
5649 case Operator.Inequality:
5650 method_name = "NotEqual";
5653 case Operator.LeftShift:
5654 method_name = "LeftShift";
5656 case Operator.LessThan:
5657 method_name = "LessThan";
5660 case Operator.LessThanOrEqual:
5661 method_name = "LessThanOrEqual";
5664 case Operator.LogicalAnd:
5665 method_name = "AndAlso";
5667 case Operator.LogicalOr:
5668 method_name = "OrElse";
5670 case Operator.Modulus:
5671 method_name = "Modulo";
5673 case Operator.Multiply:
5674 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5675 method_name = "MultiplyChecked";
5677 method_name = "Multiply";
5679 case Operator.RightShift:
5680 method_name = "RightShift";
5682 case Operator.Subtraction:
5683 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5684 method_name = "SubtractChecked";
5686 method_name = "Subtract";
5690 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5693 Arguments args = new Arguments (2);
5694 args.Add (new Argument (left.CreateExpressionTree (ec)));
5695 args.Add (new Argument (right.CreateExpressionTree (ec)));
5696 if (method != null) {
5698 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5700 args.Add (new Argument (method));
5703 return CreateExpressionFactoryCall (ec, method_name, args);
5706 public override object Accept (StructuralVisitor visitor)
5708 return visitor.Visit (this);
5714 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5715 // b, c, d... may be strings or objects.
5717 public class StringConcat : Expression
5719 Arguments arguments;
5721 StringConcat (Location loc)
5724 arguments = new Arguments (2);
5727 public override bool ContainsEmitWithAwait ()
5729 return arguments.ContainsEmitWithAwait ();
5732 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5734 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5735 throw new ArgumentException ();
5737 var s = new StringConcat (loc);
5738 s.type = rc.BuiltinTypes.String;
5739 s.eclass = ExprClass.Value;
5741 s.Append (rc, left);
5742 s.Append (rc, right);
5746 public override Expression CreateExpressionTree (ResolveContext ec)
5748 Argument arg = arguments [0];
5749 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5753 // Creates nested calls tree from an array of arguments used for IL emit
5755 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5757 Arguments concat_args = new Arguments (2);
5758 Arguments add_args = new Arguments (3);
5760 concat_args.Add (left);
5761 add_args.Add (new Argument (left_etree));
5763 concat_args.Add (arguments [pos]);
5764 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5766 var methods = GetConcatMethodCandidates ();
5767 if (methods == null)
5770 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5771 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5775 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5777 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5778 if (++pos == arguments.Count)
5781 left = new Argument (new EmptyExpression (method.ReturnType));
5782 return CreateExpressionAddCall (ec, left, expr, pos);
5785 protected override Expression DoResolve (ResolveContext ec)
5790 void Append (ResolveContext rc, Expression operand)
5795 StringConstant sc = operand as StringConstant;
5797 if (arguments.Count != 0) {
5798 Argument last_argument = arguments [arguments.Count - 1];
5799 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5800 if (last_expr_constant != null) {
5801 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5807 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5809 StringConcat concat_oper = operand as StringConcat;
5810 if (concat_oper != null) {
5811 arguments.AddRange (concat_oper.arguments);
5816 arguments.Add (new Argument (operand));
5819 IList<MemberSpec> GetConcatMethodCandidates ()
5821 return MemberCache.FindMembers (type, "Concat", true);
5824 public override void Emit (EmitContext ec)
5826 // Optimize by removing any extra null arguments, they are no-op
5827 for (int i = 0; i < arguments.Count; ++i) {
5828 if (arguments[i].Expr is NullConstant)
5829 arguments.RemoveAt (i--);
5832 var members = GetConcatMethodCandidates ();
5833 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5834 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5835 if (method != null) {
5836 var call = new CallEmitter ();
5837 call.EmitPredefined (ec, method, arguments, false);
5841 public override void FlowAnalysis (FlowAnalysisContext fc)
5843 arguments.FlowAnalysis (fc);
5846 public override SLE.Expression MakeExpression (BuilderContext ctx)
5848 if (arguments.Count != 2)
5849 throw new NotImplementedException ("arguments.Count != 2");
5851 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5852 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5857 // User-defined conditional logical operator
5859 public class ConditionalLogicalOperator : UserOperatorCall
5861 readonly bool is_and;
5862 Expression oper_expr;
5864 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5865 : base (oper, arguments, expr_tree, loc)
5867 this.is_and = is_and;
5868 eclass = ExprClass.Unresolved;
5871 protected override Expression DoResolve (ResolveContext ec)
5873 AParametersCollection pd = oper.Parameters;
5874 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5875 ec.Report.Error (217, loc,
5876 "A user-defined operator `{0}' must have each parameter type and return type of the same type in order to be applicable as a short circuit operator",
5877 oper.GetSignatureForError ());
5881 Expression left_dup = new EmptyExpression (type);
5882 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5883 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5884 if (op_true == null || op_false == null) {
5885 ec.Report.Error (218, loc,
5886 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5887 type.GetSignatureForError (), oper.GetSignatureForError ());
5891 oper_expr = is_and ? op_false : op_true;
5892 eclass = ExprClass.Value;
5896 public override void Emit (EmitContext ec)
5898 Label end_target = ec.DefineLabel ();
5901 // Emit and duplicate left argument
5903 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5904 if (right_contains_await) {
5905 arguments[0] = arguments[0].EmitToField (ec, false);
5906 arguments[0].Expr.Emit (ec);
5908 arguments[0].Expr.Emit (ec);
5909 ec.Emit (OpCodes.Dup);
5910 arguments.RemoveAt (0);
5913 oper_expr.EmitBranchable (ec, end_target, true);
5917 if (right_contains_await) {
5919 // Special handling when right expression contains await and left argument
5920 // could not be left on stack before logical branch
5922 Label skip_left_load = ec.DefineLabel ();
5923 ec.Emit (OpCodes.Br_S, skip_left_load);
5924 ec.MarkLabel (end_target);
5925 arguments[0].Expr.Emit (ec);
5926 ec.MarkLabel (skip_left_load);
5928 ec.MarkLabel (end_target);
5933 public class PointerArithmetic : Expression {
5934 Expression left, right;
5935 readonly Binary.Operator op;
5938 // We assume that `l' is always a pointer
5940 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5949 public override bool ContainsEmitWithAwait ()
5951 throw new NotImplementedException ();
5954 public override Expression CreateExpressionTree (ResolveContext ec)
5956 Error_PointerInsideExpressionTree (ec);
5960 protected override Expression DoResolve (ResolveContext ec)
5962 eclass = ExprClass.Variable;
5964 var pc = left.Type as PointerContainer;
5965 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5966 Error_VoidPointerOperation (ec);
5973 public override void Emit (EmitContext ec)
5975 TypeSpec op_type = left.Type;
5977 // It must be either array or fixed buffer
5979 if (TypeManager.HasElementType (op_type)) {
5980 element = TypeManager.GetElementType (op_type);
5982 FieldExpr fe = left as FieldExpr;
5984 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5989 int size = BuiltinTypeSpec.GetSize(element);
5990 TypeSpec rtype = right.Type;
5992 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5994 // handle (pointer - pointer)
5998 ec.Emit (OpCodes.Sub);
6002 ec.Emit (OpCodes.Sizeof, element);
6005 ec.Emit (OpCodes.Div);
6007 ec.Emit (OpCodes.Conv_I8);
6010 // handle + and - on (pointer op int)
6012 Constant left_const = left as Constant;
6013 if (left_const != null) {
6015 // Optimize ((T*)null) pointer operations
6017 if (left_const.IsDefaultValue) {
6018 left = EmptyExpression.Null;
6026 var right_const = right as Constant;
6027 if (right_const != null) {
6029 // Optimize 0-based arithmetic
6031 if (right_const.IsDefaultValue)
6035 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6037 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6039 // TODO: Should be the checks resolve context sensitive?
6040 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6041 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6047 switch (rtype.BuiltinType) {
6048 case BuiltinTypeSpec.Type.SByte:
6049 case BuiltinTypeSpec.Type.Byte:
6050 case BuiltinTypeSpec.Type.Short:
6051 case BuiltinTypeSpec.Type.UShort:
6052 ec.Emit (OpCodes.Conv_I);
6054 case BuiltinTypeSpec.Type.UInt:
6055 ec.Emit (OpCodes.Conv_U);
6059 if (right_const == null && size != 1){
6061 ec.Emit (OpCodes.Sizeof, element);
6064 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6065 ec.Emit (OpCodes.Conv_I8);
6067 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6070 if (left_const == null) {
6071 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6072 ec.Emit (OpCodes.Conv_I);
6073 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6074 ec.Emit (OpCodes.Conv_U);
6076 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6083 // A boolean-expression is an expression that yields a result
6086 public class BooleanExpression : ShimExpression
6088 public BooleanExpression (Expression expr)
6091 this.loc = expr.Location;
6094 public override Expression CreateExpressionTree (ResolveContext ec)
6096 // TODO: We should emit IsTrue (v4) instead of direct user operator
6097 // call but that would break csc compatibility
6098 return base.CreateExpressionTree (ec);
6101 protected override Expression DoResolve (ResolveContext ec)
6103 // A boolean-expression is required to be of a type
6104 // that can be implicitly converted to bool or of
6105 // a type that implements operator true
6107 expr = expr.Resolve (ec);
6111 Assign ass = expr as Assign;
6112 if (ass != null && ass.Source is Constant) {
6113 ec.Report.Warning (665, 3, loc,
6114 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6117 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6120 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6121 Arguments args = new Arguments (1);
6122 args.Add (new Argument (expr));
6123 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6126 type = ec.BuiltinTypes.Bool;
6127 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6128 if (converted != null)
6132 // If no implicit conversion to bool exists, try using `operator true'
6134 converted = GetOperatorTrue (ec, expr, loc);
6135 if (converted == null) {
6136 expr.Error_ValueCannotBeConverted (ec, type, false);
6143 public override object Accept (StructuralVisitor visitor)
6145 return visitor.Visit (this);
6149 public class BooleanExpressionFalse : Unary
6151 public BooleanExpressionFalse (Expression expr)
6152 : base (Operator.LogicalNot, expr, expr.Location)
6156 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6158 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6163 /// Implements the ternary conditional operator (?:)
6165 public class Conditional : Expression {
6166 Expression expr, true_expr, false_expr;
6168 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6171 this.true_expr = true_expr;
6172 this.false_expr = false_expr;
6178 public Expression Expr {
6184 public Expression TrueExpr {
6190 public Expression FalseExpr {
6198 public override bool ContainsEmitWithAwait ()
6200 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6203 public override Expression CreateExpressionTree (ResolveContext ec)
6205 Arguments args = new Arguments (3);
6206 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6207 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6208 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6209 return CreateExpressionFactoryCall (ec, "Condition", args);
6212 protected override Expression DoResolve (ResolveContext ec)
6214 expr = expr.Resolve (ec);
6215 true_expr = true_expr.Resolve (ec);
6216 false_expr = false_expr.Resolve (ec);
6218 if (true_expr == null || false_expr == null || expr == null)
6221 eclass = ExprClass.Value;
6222 TypeSpec true_type = true_expr.Type;
6223 TypeSpec false_type = false_expr.Type;
6227 // First, if an implicit conversion exists from true_expr
6228 // to false_expr, then the result type is of type false_expr.Type
6230 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6231 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6232 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6234 // Check if both can convert implicitly to each other's type
6238 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6239 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6241 // LAMESPEC: There seems to be hardcoded promotition to int type when
6242 // both sides are numeric constants and one side is int constant and
6243 // other side is numeric constant convertible to int.
6245 // var res = condition ? (short)1 : 1;
6247 // Type of res is int even if according to the spec the conversion is
6248 // ambiguous because 1 literal can be converted to short.
6250 if (conv_false_expr != null) {
6251 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6253 conv_false_expr = null;
6254 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6255 conv_false_expr = null;
6259 if (conv_false_expr != null) {
6260 ec.Report.Error (172, true_expr.Location,
6261 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6262 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6267 if (true_expr.Type != type)
6268 true_expr = EmptyCast.Create (true_expr, type);
6269 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6272 if (false_type != InternalType.ErrorType) {
6273 ec.Report.Error (173, true_expr.Location,
6274 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6275 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6281 Constant c = expr as Constant;
6283 bool is_false = c.IsDefaultValue;
6286 // Don't issue the warning for constant expressions
6288 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6289 // CSC: Missing warning
6290 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6293 return ReducedExpression.Create (
6294 is_false ? false_expr : true_expr, this,
6295 false_expr is Constant && true_expr is Constant).Resolve (ec);
6301 public override void Emit (EmitContext ec)
6303 Label false_target = ec.DefineLabel ();
6304 Label end_target = ec.DefineLabel ();
6306 expr.EmitBranchable (ec, false_target, false);
6307 true_expr.Emit (ec);
6310 // Verifier doesn't support interface merging. When there are two types on
6311 // the stack without common type hint and the common type is an interface.
6312 // Use temporary local to give verifier hint on what type to unify the stack
6314 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6315 var temp = ec.GetTemporaryLocal (type);
6316 ec.Emit (OpCodes.Stloc, temp);
6317 ec.Emit (OpCodes.Ldloc, temp);
6318 ec.FreeTemporaryLocal (temp, type);
6321 ec.Emit (OpCodes.Br, end_target);
6322 ec.MarkLabel (false_target);
6323 false_expr.Emit (ec);
6324 ec.MarkLabel (end_target);
6327 public override void FlowAnalysis (FlowAnalysisContext fc)
6329 expr.FlowAnalysisConditional (fc);
6330 var expr_true = fc.DefiniteAssignmentOnTrue;
6331 var expr_false = fc.DefiniteAssignmentOnFalse;
6333 fc.BranchDefiniteAssignment (expr_true);
6334 true_expr.FlowAnalysis (fc);
6335 var true_fc = fc.DefiniteAssignment;
6337 fc.BranchDefiniteAssignment (expr_false);
6338 false_expr.FlowAnalysis (fc);
6340 fc.DefiniteAssignment &= true_fc;
6343 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6345 expr.FlowAnalysisConditional (fc);
6346 var expr_true = fc.DefiniteAssignmentOnTrue;
6347 var expr_false = fc.DefiniteAssignmentOnFalse;
6349 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6350 true_expr.FlowAnalysisConditional (fc);
6351 var true_fc = fc.DefiniteAssignment;
6352 var true_da_true = fc.DefiniteAssignmentOnTrue;
6353 var true_da_false = fc.DefiniteAssignmentOnFalse;
6355 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6356 false_expr.FlowAnalysisConditional (fc);
6358 fc.DefiniteAssignment &= true_fc;
6359 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6360 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6363 protected override void CloneTo (CloneContext clonectx, Expression t)
6365 Conditional target = (Conditional) t;
6367 target.expr = expr.Clone (clonectx);
6368 target.true_expr = true_expr.Clone (clonectx);
6369 target.false_expr = false_expr.Clone (clonectx);
6373 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6375 LocalTemporary temp;
6378 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6379 public abstract void SetHasAddressTaken ();
6381 public abstract bool IsLockedByStatement { get; set; }
6383 public abstract bool IsFixed { get; }
6384 public abstract bool IsRef { get; }
6385 public abstract string Name { get; }
6388 // Variable IL data, it has to be protected to encapsulate hoisted variables
6390 protected abstract ILocalVariable Variable { get; }
6393 // Variable flow-analysis data
6395 public abstract VariableInfo VariableInfo { get; }
6398 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6400 HoistedVariable hv = GetHoistedVariable (ec);
6402 hv.AddressOf (ec, mode);
6406 Variable.EmitAddressOf (ec);
6409 public override bool ContainsEmitWithAwait ()
6414 public override Expression CreateExpressionTree (ResolveContext ec)
6416 HoistedVariable hv = GetHoistedVariable (ec);
6418 return hv.CreateExpressionTree ();
6420 Arguments arg = new Arguments (1);
6421 arg.Add (new Argument (this));
6422 return CreateExpressionFactoryCall (ec, "Constant", arg);
6425 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6427 if (IsLockedByStatement) {
6428 rc.Report.Warning (728, 2, loc,
6429 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6436 public override void Emit (EmitContext ec)
6441 public override void EmitSideEffect (EmitContext ec)
6447 // This method is used by parameters that are references, that are
6448 // being passed as references: we only want to pass the pointer (that
6449 // is already stored in the parameter, not the address of the pointer,
6450 // and not the value of the variable).
6452 public void EmitLoad (EmitContext ec)
6457 public void Emit (EmitContext ec, bool leave_copy)
6459 HoistedVariable hv = GetHoistedVariable (ec);
6461 hv.Emit (ec, leave_copy);
6469 // If we are a reference, we loaded on the stack a pointer
6470 // Now lets load the real value
6472 ec.EmitLoadFromPtr (type);
6476 ec.Emit (OpCodes.Dup);
6479 temp = new LocalTemporary (Type);
6485 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6486 bool prepare_for_load)
6488 HoistedVariable hv = GetHoistedVariable (ec);
6490 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6494 New n_source = source as New;
6495 if (n_source != null) {
6496 if (!n_source.Emit (ec, this)) {
6500 ec.EmitLoadFromPtr (type);
6512 ec.Emit (OpCodes.Dup);
6514 temp = new LocalTemporary (Type);
6520 ec.EmitStoreFromPtr (type);
6522 Variable.EmitAssign (ec);
6530 public override Expression EmitToField (EmitContext ec)
6532 HoistedVariable hv = GetHoistedVariable (ec);
6534 return hv.EmitToField (ec);
6537 return base.EmitToField (ec);
6540 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6542 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6545 public HoistedVariable GetHoistedVariable (EmitContext ec)
6547 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6550 public override string GetSignatureForError ()
6555 public bool IsHoisted {
6556 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6561 // Resolved reference to a local variable
6563 public class LocalVariableReference : VariableReference
6565 public LocalVariable local_info;
6567 public LocalVariableReference (LocalVariable li, Location l)
6569 this.local_info = li;
6573 public override VariableInfo VariableInfo {
6574 get { return local_info.VariableInfo; }
6577 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6579 return local_info.HoistedVariant;
6585 // A local variable is always fixed
6587 public override bool IsFixed {
6593 public override bool IsLockedByStatement {
6595 return local_info.IsLocked;
6598 local_info.IsLocked = value;
6602 public override bool IsRef {
6603 get { return false; }
6606 public override string Name {
6607 get { return local_info.Name; }
6612 public override void FlowAnalysis (FlowAnalysisContext fc)
6614 VariableInfo variable_info = VariableInfo;
6615 if (variable_info == null)
6618 if (fc.IsDefinitelyAssigned (variable_info))
6621 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6622 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6625 public override void SetHasAddressTaken ()
6627 local_info.SetHasAddressTaken ();
6630 void DoResolveBase (ResolveContext ec)
6632 eclass = ExprClass.Variable;
6633 type = local_info.Type;
6636 // If we are referencing a variable from the external block
6637 // flag it for capturing
6639 if (ec.MustCaptureVariable (local_info)) {
6640 if (local_info.AddressTaken) {
6641 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6642 } else if (local_info.IsFixed) {
6643 ec.Report.Error (1764, loc,
6644 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6645 GetSignatureForError ());
6648 if (ec.IsVariableCapturingRequired) {
6649 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6650 storey.CaptureLocalVariable (ec, local_info);
6655 protected override Expression DoResolve (ResolveContext ec)
6657 local_info.SetIsUsed ();
6661 if (local_info.Type == InternalType.VarOutType) {
6662 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6663 GetSignatureForError ());
6665 type = InternalType.ErrorType;
6671 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6674 // Don't be too pedantic when variable is used as out param or for some broken code
6675 // which uses property/indexer access to run some initialization
6677 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6678 local_info.SetIsUsed ();
6680 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6681 if (rhs == EmptyExpression.LValueMemberAccess) {
6682 // CS1654 already reported
6686 if (rhs == EmptyExpression.OutAccess) {
6687 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6688 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6689 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6690 } else if (rhs == EmptyExpression.UnaryAddress) {
6691 code = 459; msg = "Cannot take the address of {1} `{0}'";
6693 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6695 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6699 if (eclass == ExprClass.Unresolved)
6702 return base.DoResolveLValue (ec, rhs);
6705 public override int GetHashCode ()
6707 return local_info.GetHashCode ();
6710 public override bool Equals (object obj)
6712 LocalVariableReference lvr = obj as LocalVariableReference;
6716 return local_info == lvr.local_info;
6719 protected override ILocalVariable Variable {
6720 get { return local_info; }
6723 public override string ToString ()
6725 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6728 protected override void CloneTo (CloneContext clonectx, Expression t)
6735 /// This represents a reference to a parameter in the intermediate
6738 public class ParameterReference : VariableReference
6740 protected ParametersBlock.ParameterInfo pi;
6742 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6750 public override bool IsLockedByStatement {
6755 pi.IsLocked = value;
6759 public override bool IsRef {
6760 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6763 bool HasOutModifier {
6764 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6767 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6769 return pi.Parameter.HoistedVariant;
6773 // A ref or out parameter is classified as a moveable variable, even
6774 // if the argument given for the parameter is a fixed variable
6776 public override bool IsFixed {
6777 get { return !IsRef; }
6780 public override string Name {
6781 get { return Parameter.Name; }
6784 public Parameter Parameter {
6785 get { return pi.Parameter; }
6788 public override VariableInfo VariableInfo {
6789 get { return pi.VariableInfo; }
6792 protected override ILocalVariable Variable {
6793 get { return Parameter; }
6798 public override void AddressOf (EmitContext ec, AddressOp mode)
6801 // ParameterReferences might already be a reference
6808 base.AddressOf (ec, mode);
6811 public override void SetHasAddressTaken ()
6813 Parameter.HasAddressTaken = true;
6816 bool DoResolveBase (ResolveContext ec)
6818 if (eclass != ExprClass.Unresolved)
6821 type = pi.ParameterType;
6822 eclass = ExprClass.Variable;
6825 // If we are referencing a parameter from the external block
6826 // flag it for capturing
6828 if (ec.MustCaptureVariable (pi)) {
6829 if (Parameter.HasAddressTaken)
6830 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6833 ec.Report.Error (1628, loc,
6834 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6835 Name, ec.CurrentAnonymousMethod.ContainerType);
6838 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6839 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6840 storey.CaptureParameter (ec, pi, this);
6847 public override int GetHashCode ()
6849 return Name.GetHashCode ();
6852 public override bool Equals (object obj)
6854 ParameterReference pr = obj as ParameterReference;
6858 return Name == pr.Name;
6861 protected override void CloneTo (CloneContext clonectx, Expression target)
6867 public override Expression CreateExpressionTree (ResolveContext ec)
6869 HoistedVariable hv = GetHoistedVariable (ec);
6871 return hv.CreateExpressionTree ();
6873 return Parameter.ExpressionTreeVariableReference ();
6876 protected override Expression DoResolve (ResolveContext ec)
6878 if (!DoResolveBase (ec))
6884 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6886 if (!DoResolveBase (ec))
6889 if (Parameter.HoistedVariant != null)
6890 Parameter.HoistedVariant.IsAssigned = true;
6892 return base.DoResolveLValue (ec, right_side);
6895 public override void FlowAnalysis (FlowAnalysisContext fc)
6897 VariableInfo variable_info = VariableInfo;
6898 if (variable_info == null)
6901 if (fc.IsDefinitelyAssigned (variable_info))
6904 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6905 fc.SetVariableAssigned (variable_info);
6910 /// Invocation of methods or delegates.
6912 public class Invocation : ExpressionStatement
6914 public class Predefined : Invocation
6916 public Predefined (MethodGroupExpr expr, Arguments arguments)
6917 : base (expr, arguments)
6922 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6924 mg.BestCandidate.CheckObsoleteness (rc, loc);
6930 protected Arguments arguments;
6931 protected Expression expr;
6932 protected MethodGroupExpr mg;
6933 bool conditional_access_receiver;
6935 public Invocation (Expression expr, Arguments arguments)
6938 this.arguments = arguments;
6940 loc = expr.Location;
6945 public Arguments Arguments {
6951 public Expression Exp {
6957 public MethodGroupExpr MethodGroup {
6963 public override Location StartLocation {
6965 return expr.StartLocation;
6971 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6973 if (MethodGroup == null)
6976 var candidate = MethodGroup.BestCandidate;
6977 if (candidate == null || !(candidate.IsStatic || Exp is This))
6980 var args_count = arguments == null ? 0 : arguments.Count;
6981 if (args_count != body.Parameters.Count)
6984 var lambda_parameters = body.Block.Parameters.FixedParameters;
6985 for (int i = 0; i < args_count; ++i) {
6986 var pr = arguments[i].Expr as ParameterReference;
6990 if (lambda_parameters[i] != pr.Parameter)
6993 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6997 var emg = MethodGroup as ExtensionMethodGroupExpr;
6999 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
7000 if (candidate.IsGeneric) {
7001 var targs = new TypeExpression [candidate.Arity];
7002 for (int i = 0; i < targs.Length; ++i) {
7003 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
7006 mg.SetTypeArguments (null, new TypeArguments (targs));
7015 protected override void CloneTo (CloneContext clonectx, Expression t)
7017 Invocation target = (Invocation) t;
7019 if (arguments != null)
7020 target.arguments = arguments.Clone (clonectx);
7022 target.expr = expr.Clone (clonectx);
7025 public override bool ContainsEmitWithAwait ()
7027 if (arguments != null && arguments.ContainsEmitWithAwait ())
7030 return mg.ContainsEmitWithAwait ();
7033 public override Expression CreateExpressionTree (ResolveContext ec)
7035 Expression instance = mg.IsInstance ?
7036 mg.InstanceExpression.CreateExpressionTree (ec) :
7037 new NullLiteral (loc);
7039 var args = Arguments.CreateForExpressionTree (ec, arguments,
7041 mg.CreateExpressionTree (ec));
7043 return CreateExpressionFactoryCall (ec, "Call", args);
7046 void ResolveConditionalAccessReceiver (ResolveContext rc)
7048 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7049 conditional_access_receiver = true;
7053 protected override Expression DoResolve (ResolveContext rc)
7055 ResolveConditionalAccessReceiver (rc);
7056 return DoResolveInvocation (rc);
7059 Expression DoResolveInvocation (ResolveContext ec)
7061 Expression member_expr;
7062 var atn = expr as ATypeNameExpression;
7064 var flags = default (ResolveContext.FlagsHandle);
7065 if (conditional_access_receiver)
7066 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7069 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7070 if (member_expr != null) {
7071 var name_of = member_expr as NameOf;
7072 if (name_of != null) {
7073 return name_of.ResolveOverload (ec, arguments);
7076 member_expr = member_expr.Resolve (ec);
7079 member_expr = expr.Resolve (ec);
7082 if (conditional_access_receiver)
7085 if (member_expr == null)
7089 // Next, evaluate all the expressions in the argument list
7091 bool dynamic_arg = false;
7092 if (arguments != null)
7093 arguments.Resolve (ec, out dynamic_arg);
7095 TypeSpec expr_type = member_expr.Type;
7096 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7097 return DoResolveDynamic (ec, member_expr);
7099 mg = member_expr as MethodGroupExpr;
7100 Expression invoke = null;
7103 if (expr_type != null && expr_type.IsDelegate) {
7104 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7105 invoke = invoke.Resolve (ec);
7106 if (invoke == null || !dynamic_arg)
7109 if (member_expr is RuntimeValueExpression) {
7110 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7111 member_expr.Type.GetSignatureForError ());
7115 MemberExpr me = member_expr as MemberExpr;
7117 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7121 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7122 member_expr.GetSignatureForError ());
7127 if (invoke == null) {
7128 mg = DoResolveOverload (ec);
7134 return DoResolveDynamic (ec, member_expr);
7136 var method = mg.BestCandidate;
7137 type = mg.BestCandidateReturnType;
7138 if (conditional_access_receiver)
7139 type = LiftMemberType (ec, type);
7141 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7143 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7145 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7149 IsSpecialMethodInvocation (ec, method, loc);
7151 eclass = ExprClass.Value;
7155 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7158 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7160 args = dmb.Arguments;
7161 if (arguments != null)
7162 args.AddRange (arguments);
7163 } else if (mg == null) {
7164 if (arguments == null)
7165 args = new Arguments (1);
7169 args.Insert (0, new Argument (memberExpr));
7173 ec.Report.Error (1971, loc,
7174 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7179 if (arguments == null)
7180 args = new Arguments (1);
7184 MemberAccess ma = expr as MemberAccess;
7186 var inst = mg.InstanceExpression;
7187 var left_type = inst as TypeExpr;
7188 if (left_type != null) {
7189 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7190 } else if (inst != null) {
7192 // Any value type has to be pass as by-ref to get back the same
7193 // instance on which the member was called
7195 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7196 Argument.AType.Ref : Argument.AType.None;
7197 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7199 } else { // is SimpleName
7201 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7203 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7208 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7211 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7213 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7216 public override void FlowAnalysis (FlowAnalysisContext fc)
7218 if (mg.IsConditionallyExcluded)
7221 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7223 mg.FlowAnalysis (fc);
7225 if (arguments != null)
7226 arguments.FlowAnalysis (fc);
7228 if (conditional_access_receiver)
7229 fc.DefiniteAssignment = da;
7232 public override string GetSignatureForError ()
7234 return mg.GetSignatureForError ();
7237 public override bool HasConditionalAccess ()
7239 return expr.HasConditionalAccess ();
7243 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7244 // or the type dynamic, then the member is invocable
7246 public static bool IsMemberInvocable (MemberSpec member)
7248 switch (member.Kind) {
7249 case MemberKind.Event:
7251 case MemberKind.Field:
7252 case MemberKind.Property:
7253 var m = member as IInterfaceMemberSpec;
7254 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7260 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7262 if (!method.IsReservedMethod)
7265 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7268 ec.Report.SymbolRelatedToPreviousError (method);
7269 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7270 method.GetSignatureForError ());
7275 public override void Emit (EmitContext ec)
7277 if (mg.IsConditionallyExcluded)
7280 if (conditional_access_receiver)
7281 mg.EmitCall (ec, arguments, type, false);
7283 mg.EmitCall (ec, arguments, false);
7286 public override void EmitStatement (EmitContext ec)
7288 if (mg.IsConditionallyExcluded)
7291 if (conditional_access_receiver)
7292 mg.EmitCall (ec, arguments, type, true);
7294 mg.EmitCall (ec, arguments, true);
7297 public override SLE.Expression MakeExpression (BuilderContext ctx)
7299 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7302 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7305 throw new NotSupportedException ();
7307 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7308 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7312 public override object Accept (StructuralVisitor visitor)
7314 return visitor.Visit (this);
7319 // Implements simple new expression
7321 public class New : ExpressionStatement, IMemoryLocation
7323 protected Arguments arguments;
7326 // During bootstrap, it contains the RequestedType,
7327 // but if `type' is not null, it *might* contain a NewDelegate
7328 // (because of field multi-initialization)
7330 protected Expression RequestedType;
7332 protected MethodSpec method;
7334 public New (Expression requested_type, Arguments arguments, Location l)
7336 RequestedType = requested_type;
7337 this.arguments = arguments;
7342 public Arguments Arguments {
7349 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7351 public bool IsGeneratedStructConstructor {
7353 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7357 public Expression TypeExpression {
7359 return RequestedType;
7366 /// Converts complex core type syntax like 'new int ()' to simple constant
7368 public static Constant Constantify (TypeSpec t, Location loc)
7370 switch (t.BuiltinType) {
7371 case BuiltinTypeSpec.Type.Int:
7372 return new IntConstant (t, 0, loc);
7373 case BuiltinTypeSpec.Type.UInt:
7374 return new UIntConstant (t, 0, loc);
7375 case BuiltinTypeSpec.Type.Long:
7376 return new LongConstant (t, 0, loc);
7377 case BuiltinTypeSpec.Type.ULong:
7378 return new ULongConstant (t, 0, loc);
7379 case BuiltinTypeSpec.Type.Float:
7380 return new FloatConstant (t, 0, loc);
7381 case BuiltinTypeSpec.Type.Double:
7382 return new DoubleConstant (t, 0, loc);
7383 case BuiltinTypeSpec.Type.Short:
7384 return new ShortConstant (t, 0, loc);
7385 case BuiltinTypeSpec.Type.UShort:
7386 return new UShortConstant (t, 0, loc);
7387 case BuiltinTypeSpec.Type.SByte:
7388 return new SByteConstant (t, 0, loc);
7389 case BuiltinTypeSpec.Type.Byte:
7390 return new ByteConstant (t, 0, loc);
7391 case BuiltinTypeSpec.Type.Char:
7392 return new CharConstant (t, '\0', loc);
7393 case BuiltinTypeSpec.Type.Bool:
7394 return new BoolConstant (t, false, loc);
7395 case BuiltinTypeSpec.Type.Decimal:
7396 return new DecimalConstant (t, 0, loc);
7400 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7402 if (t.IsNullableType)
7403 return Nullable.LiftedNull.Create (t, loc);
7408 public override bool ContainsEmitWithAwait ()
7410 return arguments != null && arguments.ContainsEmitWithAwait ();
7414 // Checks whether the type is an interface that has the
7415 // [ComImport, CoClass] attributes and must be treated
7418 public Expression CheckComImport (ResolveContext ec)
7420 if (!type.IsInterface)
7424 // Turn the call into:
7425 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7427 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7428 if (real_class == null)
7431 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7432 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7433 return cast.Resolve (ec);
7436 public override Expression CreateExpressionTree (ResolveContext ec)
7439 if (method == null) {
7440 args = new Arguments (1);
7441 args.Add (new Argument (new TypeOf (type, loc)));
7443 args = Arguments.CreateForExpressionTree (ec,
7444 arguments, new TypeOfMethod (method, loc));
7447 return CreateExpressionFactoryCall (ec, "New", args);
7450 protected override Expression DoResolve (ResolveContext ec)
7452 type = RequestedType.ResolveAsType (ec);
7456 eclass = ExprClass.Value;
7458 if (type.IsPointer) {
7459 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7460 type.GetSignatureForError ());
7464 if (arguments == null) {
7465 Constant c = Constantify (type, RequestedType.Location);
7467 return ReducedExpression.Create (c, this);
7470 if (type.IsDelegate) {
7471 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7474 var tparam = type as TypeParameterSpec;
7475 if (tparam != null) {
7477 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7478 // where type parameter constraint is inflated to struct
7480 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7481 ec.Report.Error (304, loc,
7482 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7483 type.GetSignatureForError ());
7486 if ((arguments != null) && (arguments.Count != 0)) {
7487 ec.Report.Error (417, loc,
7488 "`{0}': cannot provide arguments when creating an instance of a variable type",
7489 type.GetSignatureForError ());
7495 if (type.IsStatic) {
7496 ec.Report.SymbolRelatedToPreviousError (type);
7497 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7501 if (type.IsInterface || type.IsAbstract){
7502 if (!TypeManager.IsGenericType (type)) {
7503 RequestedType = CheckComImport (ec);
7504 if (RequestedType != null)
7505 return RequestedType;
7508 ec.Report.SymbolRelatedToPreviousError (type);
7509 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7514 if (arguments != null) {
7515 arguments.Resolve (ec, out dynamic);
7520 method = ConstructorLookup (ec, type, ref arguments, loc);
7523 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7524 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7530 void DoEmitTypeParameter (EmitContext ec)
7532 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7536 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7537 ec.Emit (OpCodes.Call, ctor_factory);
7541 // This Emit can be invoked in two contexts:
7542 // * As a mechanism that will leave a value on the stack (new object)
7543 // * As one that wont (init struct)
7545 // If we are dealing with a ValueType, we have a few
7546 // situations to deal with:
7548 // * The target is a ValueType, and we have been provided
7549 // the instance (this is easy, we are being assigned).
7551 // * The target of New is being passed as an argument,
7552 // to a boxing operation or a function that takes a
7555 // In this case, we need to create a temporary variable
7556 // that is the argument of New.
7558 // Returns whether a value is left on the stack
7560 // *** Implementation note ***
7562 // To benefit from this optimization, each assignable expression
7563 // has to manually cast to New and call this Emit.
7565 // TODO: It's worth to implement it for arrays and fields
7567 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7569 bool is_value_type = type.IsStructOrEnum;
7570 VariableReference vr = target as VariableReference;
7572 if (target != null && is_value_type && (vr != null || method == null)) {
7573 target.AddressOf (ec, AddressOp.Store);
7574 } else if (vr != null && vr.IsRef) {
7578 if (arguments != null) {
7579 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7580 arguments = arguments.Emit (ec, false, true);
7582 arguments.Emit (ec);
7585 if (is_value_type) {
7586 if (method == null) {
7587 ec.Emit (OpCodes.Initobj, type);
7592 ec.MarkCallEntry (loc);
7593 ec.Emit (OpCodes.Call, method);
7598 if (type is TypeParameterSpec) {
7599 DoEmitTypeParameter (ec);
7603 ec.MarkCallEntry (loc);
7604 ec.Emit (OpCodes.Newobj, method);
7608 public override void Emit (EmitContext ec)
7610 LocalTemporary v = null;
7611 if (method == null && type.IsStructOrEnum) {
7612 // TODO: Use temporary variable from pool
7613 v = new LocalTemporary (type);
7620 public override void EmitStatement (EmitContext ec)
7622 LocalTemporary v = null;
7623 if (method == null && TypeSpec.IsValueType (type)) {
7624 // TODO: Use temporary variable from pool
7625 v = new LocalTemporary (type);
7629 ec.Emit (OpCodes.Pop);
7632 public override void FlowAnalysis (FlowAnalysisContext fc)
7634 if (arguments != null)
7635 arguments.FlowAnalysis (fc);
7638 public void AddressOf (EmitContext ec, AddressOp mode)
7640 EmitAddressOf (ec, mode);
7643 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7645 LocalTemporary value_target = new LocalTemporary (type);
7647 if (type is TypeParameterSpec) {
7648 DoEmitTypeParameter (ec);
7649 value_target.Store (ec);
7650 value_target.AddressOf (ec, mode);
7651 return value_target;
7654 value_target.AddressOf (ec, AddressOp.Store);
7656 if (method == null) {
7657 ec.Emit (OpCodes.Initobj, type);
7659 if (arguments != null)
7660 arguments.Emit (ec);
7662 ec.Emit (OpCodes.Call, method);
7665 value_target.AddressOf (ec, mode);
7666 return value_target;
7669 protected override void CloneTo (CloneContext clonectx, Expression t)
7671 New target = (New) t;
7673 target.RequestedType = RequestedType.Clone (clonectx);
7674 if (arguments != null){
7675 target.arguments = arguments.Clone (clonectx);
7679 public override SLE.Expression MakeExpression (BuilderContext ctx)
7682 return base.MakeExpression (ctx);
7684 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7688 public override object Accept (StructuralVisitor visitor)
7690 return visitor.Visit (this);
7695 // Array initializer expression, the expression is allowed in
7696 // variable or field initialization only which makes it tricky as
7697 // the type has to be infered based on the context either from field
7698 // type or variable type (think of multiple declarators)
7700 public class ArrayInitializer : Expression
7702 List<Expression> elements;
7703 BlockVariable variable;
7705 public ArrayInitializer (List<Expression> init, Location loc)
7711 public ArrayInitializer (int count, Location loc)
7712 : this (new List<Expression> (count), loc)
7716 public ArrayInitializer (Location loc)
7724 get { return elements.Count; }
7727 public List<Expression> Elements {
7733 public Expression this [int index] {
7735 return elements [index];
7739 public BlockVariable VariableDeclaration {
7750 public void Add (Expression expr)
7752 elements.Add (expr);
7755 public override bool ContainsEmitWithAwait ()
7757 throw new NotSupportedException ();
7760 public override Expression CreateExpressionTree (ResolveContext ec)
7762 throw new NotSupportedException ("ET");
7765 protected override void CloneTo (CloneContext clonectx, Expression t)
7767 var target = (ArrayInitializer) t;
7769 target.elements = new List<Expression> (elements.Count);
7770 foreach (var element in elements)
7771 target.elements.Add (element.Clone (clonectx));
7774 protected override Expression DoResolve (ResolveContext rc)
7776 var current_field = rc.CurrentMemberDefinition as FieldBase;
7777 TypeExpression type;
7778 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7779 type = new TypeExpression (current_field.MemberType, current_field.Location);
7780 } else if (variable != null) {
7781 if (variable.TypeExpression is VarExpr) {
7782 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7783 return EmptyExpression.Null;
7786 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7788 throw new NotImplementedException ("Unexpected array initializer context");
7791 return new ArrayCreation (type, this).Resolve (rc);
7794 public override void Emit (EmitContext ec)
7796 throw new InternalErrorException ("Missing Resolve call");
7799 public override void FlowAnalysis (FlowAnalysisContext fc)
7801 throw new InternalErrorException ("Missing Resolve call");
7804 public override object Accept (StructuralVisitor visitor)
7806 return visitor.Visit (this);
7811 /// 14.5.10.2: Represents an array creation expression.
7815 /// There are two possible scenarios here: one is an array creation
7816 /// expression that specifies the dimensions and optionally the
7817 /// initialization data and the other which does not need dimensions
7818 /// specified but where initialization data is mandatory.
7820 public class ArrayCreation : Expression
7822 FullNamedExpression requested_base_type;
7823 ArrayInitializer initializers;
7826 // The list of Argument types.
7827 // This is used to construct the `newarray' or constructor signature
7829 protected List<Expression> arguments;
7831 protected TypeSpec array_element_type;
7833 protected int dimensions;
7834 protected readonly ComposedTypeSpecifier rank;
7835 Expression first_emit;
7836 LocalTemporary first_emit_temp;
7838 protected List<Expression> array_data;
7840 Dictionary<int, int> bounds;
7843 // The number of constants in array initializers
7844 int const_initializers_count;
7845 bool only_constant_initializers;
7847 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7848 : this (requested_base_type, rank, initializers, l)
7850 arguments = new List<Expression> (exprs);
7851 num_arguments = arguments.Count;
7855 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7857 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7859 this.requested_base_type = requested_base_type;
7861 this.initializers = initializers;
7865 num_arguments = rank.Dimension;
7869 // For compiler generated single dimensional arrays only
7871 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7872 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7877 // For expressions like int[] foo = { 1, 2, 3 };
7879 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7880 : this (requested_base_type, null, initializers, initializers.Location)
7884 public ComposedTypeSpecifier Rank {
7890 public FullNamedExpression TypeExpression {
7892 return this.requested_base_type;
7896 public ArrayInitializer Initializers {
7898 return this.initializers;
7902 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7904 if (initializers != null && bounds == null) {
7906 // We use this to store all the data values in the order in which we
7907 // will need to store them in the byte blob later
7909 array_data = new List<Expression> (probe.Count);
7910 bounds = new Dictionary<int, int> ();
7913 if (specified_dims) {
7914 Expression a = arguments [idx];
7919 a = ConvertExpressionToArrayIndex (ec, a);
7925 if (initializers != null) {
7926 Constant c = a as Constant;
7927 if (c == null && a is ArrayIndexCast)
7928 c = ((ArrayIndexCast) a).Child as Constant;
7931 ec.Report.Error (150, a.Location, "A constant value is expected");
7937 value = System.Convert.ToInt32 (c.GetValue ());
7939 ec.Report.Error (150, a.Location, "A constant value is expected");
7943 // TODO: probe.Count does not fit ulong in
7944 if (value != probe.Count) {
7945 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7949 bounds[idx] = value;
7953 if (initializers == null)
7956 for (int i = 0; i < probe.Count; ++i) {
7958 if (o is ArrayInitializer) {
7959 var sub_probe = o as ArrayInitializer;
7960 if (idx + 1 >= dimensions){
7961 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7965 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7966 if (!bounds.ContainsKey(idx + 1))
7967 bounds[idx + 1] = sub_probe.Count;
7969 if (bounds[idx + 1] != sub_probe.Count) {
7970 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7974 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7977 } else if (child_bounds > 1) {
7978 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7980 Expression element = ResolveArrayElement (ec, o);
7981 if (element == null)
7984 // Initializers with the default values can be ignored
7985 Constant c = element as Constant;
7987 if (!c.IsDefaultInitializer (array_element_type)) {
7988 ++const_initializers_count;
7991 only_constant_initializers = false;
7994 array_data.Add (element);
8001 public override bool ContainsEmitWithAwait ()
8003 foreach (var arg in arguments) {
8004 if (arg.ContainsEmitWithAwait ())
8008 return InitializersContainAwait ();
8011 public override Expression CreateExpressionTree (ResolveContext ec)
8015 if (array_data == null) {
8016 args = new Arguments (arguments.Count + 1);
8017 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8018 foreach (Expression a in arguments)
8019 args.Add (new Argument (a.CreateExpressionTree (ec)));
8021 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8024 if (dimensions > 1) {
8025 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8029 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8030 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8031 if (array_data != null) {
8032 for (int i = 0; i < array_data.Count; ++i) {
8033 Expression e = array_data [i];
8034 args.Add (new Argument (e.CreateExpressionTree (ec)));
8038 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8041 void UpdateIndices (ResolveContext rc)
8044 for (var probe = initializers; probe != null;) {
8045 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8047 bounds[i++] = probe.Count;
8049 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8050 probe = (ArrayInitializer) probe[0];
8051 } else if (dimensions > i) {
8059 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8061 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8064 public override void FlowAnalysis (FlowAnalysisContext fc)
8066 foreach (var arg in arguments)
8067 arg.FlowAnalysis (fc);
8069 if (array_data != null) {
8070 foreach (var ad in array_data)
8071 ad.FlowAnalysis (fc);
8075 bool InitializersContainAwait ()
8077 if (array_data == null)
8080 foreach (var expr in array_data) {
8081 if (expr.ContainsEmitWithAwait ())
8088 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8090 element = element.Resolve (ec);
8091 if (element == null)
8094 if (element is CompoundAssign.TargetExpression) {
8095 if (first_emit != null)
8096 throw new InternalErrorException ("Can only handle one mutator at a time");
8097 first_emit = element;
8098 element = first_emit_temp = new LocalTemporary (element.Type);
8101 return Convert.ImplicitConversionRequired (
8102 ec, element, array_element_type, loc);
8105 protected bool ResolveInitializers (ResolveContext ec)
8108 only_constant_initializers = true;
8111 if (arguments != null) {
8113 for (int i = 0; i < arguments.Count; ++i) {
8114 res &= CheckIndices (ec, initializers, i, true, dimensions);
8115 if (initializers != null)
8122 arguments = new List<Expression> ();
8124 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8133 // Resolved the type of the array
8135 bool ResolveArrayType (ResolveContext ec)
8140 FullNamedExpression array_type_expr;
8141 if (num_arguments > 0) {
8142 array_type_expr = new ComposedCast (requested_base_type, rank);
8144 array_type_expr = requested_base_type;
8147 type = array_type_expr.ResolveAsType (ec);
8148 if (array_type_expr == null)
8151 var ac = type as ArrayContainer;
8153 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8157 array_element_type = ac.Element;
8158 dimensions = ac.Rank;
8163 protected override Expression DoResolve (ResolveContext ec)
8168 if (!ResolveArrayType (ec))
8172 // validate the initializers and fill in any missing bits
8174 if (!ResolveInitializers (ec))
8177 eclass = ExprClass.Value;
8181 byte [] MakeByteBlob ()
8186 int count = array_data.Count;
8188 TypeSpec element_type = array_element_type;
8189 if (element_type.IsEnum)
8190 element_type = EnumSpec.GetUnderlyingType (element_type);
8192 factor = BuiltinTypeSpec.GetSize (element_type);
8194 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8196 data = new byte [(count * factor + 3) & ~3];
8199 for (int i = 0; i < count; ++i) {
8200 var c = array_data[i] as Constant;
8206 object v = c.GetValue ();
8208 switch (element_type.BuiltinType) {
8209 case BuiltinTypeSpec.Type.Long:
8210 long lval = (long) v;
8212 for (int j = 0; j < factor; ++j) {
8213 data[idx + j] = (byte) (lval & 0xFF);
8217 case BuiltinTypeSpec.Type.ULong:
8218 ulong ulval = (ulong) v;
8220 for (int j = 0; j < factor; ++j) {
8221 data[idx + j] = (byte) (ulval & 0xFF);
8222 ulval = (ulval >> 8);
8225 case BuiltinTypeSpec.Type.Float:
8226 var fval = SingleConverter.SingleToInt32Bits((float) v);
8228 data[idx] = (byte) (fval & 0xff);
8229 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8230 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8231 data[idx + 3] = (byte) (fval >> 24);
8233 case BuiltinTypeSpec.Type.Double:
8234 element = BitConverter.GetBytes ((double) v);
8236 for (int j = 0; j < factor; ++j)
8237 data[idx + j] = element[j];
8239 // FIXME: Handle the ARM float format.
8240 if (!BitConverter.IsLittleEndian)
8241 System.Array.Reverse (data, idx, 8);
8243 case BuiltinTypeSpec.Type.Char:
8244 int chval = (int) ((char) v);
8246 data[idx] = (byte) (chval & 0xff);
8247 data[idx + 1] = (byte) (chval >> 8);
8249 case BuiltinTypeSpec.Type.Short:
8250 int sval = (int) ((short) v);
8252 data[idx] = (byte) (sval & 0xff);
8253 data[idx + 1] = (byte) (sval >> 8);
8255 case BuiltinTypeSpec.Type.UShort:
8256 int usval = (int) ((ushort) v);
8258 data[idx] = (byte) (usval & 0xff);
8259 data[idx + 1] = (byte) (usval >> 8);
8261 case BuiltinTypeSpec.Type.Int:
8264 data[idx] = (byte) (val & 0xff);
8265 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8266 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8267 data[idx + 3] = (byte) (val >> 24);
8269 case BuiltinTypeSpec.Type.UInt:
8270 uint uval = (uint) v;
8272 data[idx] = (byte) (uval & 0xff);
8273 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8274 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8275 data[idx + 3] = (byte) (uval >> 24);
8277 case BuiltinTypeSpec.Type.SByte:
8278 data[idx] = (byte) (sbyte) v;
8280 case BuiltinTypeSpec.Type.Byte:
8281 data[idx] = (byte) v;
8283 case BuiltinTypeSpec.Type.Bool:
8284 data[idx] = (byte) ((bool) v ? 1 : 0);
8286 case BuiltinTypeSpec.Type.Decimal:
8287 int[] bits = Decimal.GetBits ((decimal) v);
8290 // FIXME: For some reason, this doesn't work on the MS runtime.
8291 int[] nbits = new int[4];
8297 for (int j = 0; j < 4; j++) {
8298 data[p++] = (byte) (nbits[j] & 0xff);
8299 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8300 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8301 data[p++] = (byte) (nbits[j] >> 24);
8305 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8314 public override SLE.Expression MakeExpression (BuilderContext ctx)
8317 return base.MakeExpression (ctx);
8319 var initializers = new SLE.Expression [array_data.Count];
8320 for (var i = 0; i < initializers.Length; i++) {
8321 if (array_data [i] == null)
8322 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8324 initializers [i] = array_data [i].MakeExpression (ctx);
8327 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8332 // Emits the initializers for the array
8334 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8336 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8341 // First, the static data
8343 byte [] data = MakeByteBlob ();
8344 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8346 if (stackArray == null) {
8347 ec.Emit (OpCodes.Dup);
8349 stackArray.Emit (ec);
8352 ec.Emit (OpCodes.Ldtoken, fb);
8353 ec.Emit (OpCodes.Call, m);
8358 // Emits pieces of the array that can not be computed at compile
8359 // time (variables and string locations).
8361 // This always expect the top value on the stack to be the array
8363 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8365 int dims = bounds.Count;
8366 var current_pos = new int [dims];
8368 for (int i = 0; i < array_data.Count; i++){
8370 Expression e = array_data [i];
8371 var c = e as Constant;
8373 // Constant can be initialized via StaticInitializer
8374 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8378 if (stackArray != null) {
8379 if (e.ContainsEmitWithAwait ()) {
8380 e = e.EmitToField (ec);
8383 stackArray.EmitLoad (ec);
8385 ec.Emit (OpCodes.Dup);
8388 for (int idx = 0; idx < dims; idx++)
8389 ec.EmitInt (current_pos [idx]);
8392 // If we are dealing with a struct, get the
8393 // address of it, so we can store it.
8395 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8396 ec.Emit (OpCodes.Ldelema, etype);
8400 ec.EmitArrayStore ((ArrayContainer) type);
8406 for (int j = dims - 1; j >= 0; j--){
8408 if (current_pos [j] < bounds [j])
8410 current_pos [j] = 0;
8414 if (stackArray != null)
8415 stackArray.PrepareCleanup (ec);
8418 public override void Emit (EmitContext ec)
8420 var await_field = EmitToFieldSource (ec);
8421 if (await_field != null)
8422 await_field.Emit (ec);
8425 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8427 if (first_emit != null) {
8428 first_emit.Emit (ec);
8429 first_emit_temp.Store (ec);
8432 StackFieldExpr await_stack_field;
8433 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8434 await_stack_field = ec.GetTemporaryField (type);
8437 await_stack_field = null;
8440 EmitExpressionsList (ec, arguments);
8442 ec.EmitArrayNew ((ArrayContainer) type);
8444 if (initializers == null)
8445 return await_stack_field;
8447 if (await_stack_field != null)
8448 await_stack_field.EmitAssignFromStack (ec);
8452 // Emit static initializer for arrays which contain more than 2 items and
8453 // the static initializer will initialize at least 25% of array values or there
8454 // is more than 10 items to be initialized
8456 // NOTE: const_initializers_count does not contain default constant values.
8458 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8459 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8460 EmitStaticInitializers (ec, await_stack_field);
8462 if (!only_constant_initializers)
8463 EmitDynamicInitializers (ec, false, await_stack_field);
8467 EmitDynamicInitializers (ec, true, await_stack_field);
8470 if (first_emit_temp != null)
8471 first_emit_temp.Release (ec);
8473 return await_stack_field;
8476 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8478 // no multi dimensional or jagged arrays
8479 if (arguments.Count != 1 || array_element_type.IsArray) {
8480 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8484 // No array covariance, except for array -> object
8485 if (type != targetType) {
8486 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8487 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8491 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8492 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8497 // Single dimensional array of 0 size
8498 if (array_data == null) {
8499 IntConstant ic = arguments[0] as IntConstant;
8500 if (ic == null || !ic.IsDefaultValue) {
8501 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8509 enc.Encode (array_data.Count);
8510 foreach (var element in array_data) {
8511 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8515 protected override void CloneTo (CloneContext clonectx, Expression t)
8517 ArrayCreation target = (ArrayCreation) t;
8519 if (requested_base_type != null)
8520 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8522 if (arguments != null){
8523 target.arguments = new List<Expression> (arguments.Count);
8524 foreach (Expression e in arguments)
8525 target.arguments.Add (e.Clone (clonectx));
8528 if (initializers != null)
8529 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8532 public override object Accept (StructuralVisitor visitor)
8534 return visitor.Visit (this);
8539 // Represents an implicitly typed array epxression
8541 class ImplicitlyTypedArrayCreation : ArrayCreation
8543 TypeInferenceContext best_type_inference;
8545 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8546 : base (null, rank, initializers, loc)
8550 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8551 : base (null, initializers, loc)
8555 protected override Expression DoResolve (ResolveContext ec)
8560 dimensions = rank.Dimension;
8562 best_type_inference = new TypeInferenceContext ();
8564 if (!ResolveInitializers (ec))
8567 best_type_inference.FixAllTypes (ec);
8568 array_element_type = best_type_inference.InferredTypeArguments[0];
8569 best_type_inference = null;
8571 if (array_element_type == null ||
8572 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8573 arguments.Count != rank.Dimension) {
8574 ec.Report.Error (826, loc,
8575 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8580 // At this point we found common base type for all initializer elements
8581 // but we have to be sure that all static initializer elements are of
8584 UnifyInitializerElement (ec);
8586 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8587 eclass = ExprClass.Value;
8592 // Converts static initializer only
8594 void UnifyInitializerElement (ResolveContext ec)
8596 for (int i = 0; i < array_data.Count; ++i) {
8597 Expression e = array_data[i];
8599 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8603 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8605 element = element.Resolve (ec);
8606 if (element != null)
8607 best_type_inference.AddCommonTypeBound (element.Type);
8613 sealed class CompilerGeneratedThis : This
8615 public CompilerGeneratedThis (TypeSpec type, Location loc)
8621 protected override Expression DoResolve (ResolveContext rc)
8623 eclass = ExprClass.Variable;
8625 var block = rc.CurrentBlock;
8626 if (block != null) {
8627 var top = block.ParametersBlock.TopBlock;
8628 if (top.ThisVariable != null)
8629 variable_info = top.ThisVariable.VariableInfo;
8636 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8638 return DoResolve (rc);
8641 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8648 /// Represents the `this' construct
8651 public class This : VariableReference
8653 sealed class ThisVariable : ILocalVariable
8655 public static readonly ILocalVariable Instance = new ThisVariable ();
8657 public void Emit (EmitContext ec)
8662 public void EmitAssign (EmitContext ec)
8664 throw new InvalidOperationException ();
8667 public void EmitAddressOf (EmitContext ec)
8673 protected VariableInfo variable_info;
8675 public This (Location loc)
8682 public override string Name {
8683 get { return "this"; }
8686 public override bool IsLockedByStatement {
8694 public override bool IsRef {
8695 get { return type.IsStruct; }
8698 public override bool IsSideEffectFree {
8704 protected override ILocalVariable Variable {
8705 get { return ThisVariable.Instance; }
8708 public override VariableInfo VariableInfo {
8709 get { return variable_info; }
8712 public override bool IsFixed {
8713 get { return false; }
8718 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8721 // It's null for all cases when we don't need to check `this'
8722 // definitive assignment
8724 if (variable_info == null)
8727 if (fc.IsDefinitelyAssigned (variable_info))
8730 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8733 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8735 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8736 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8737 } else if (ec.CurrentAnonymousMethod != null) {
8738 ec.Report.Error (1673, loc,
8739 "Anonymous methods inside structs cannot access instance members of `this'. " +
8740 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8742 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8746 public override void FlowAnalysis (FlowAnalysisContext fc)
8748 CheckStructThisDefiniteAssignment (fc);
8751 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8756 AnonymousMethodStorey storey = ae.Storey;
8757 return storey != null ? storey.HoistedThis : null;
8760 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8762 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8765 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8768 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8774 public virtual void ResolveBase (ResolveContext ec)
8776 eclass = ExprClass.Variable;
8777 type = ec.CurrentType;
8779 if (!IsThisAvailable (ec, false)) {
8780 Error_ThisNotAvailable (ec);
8784 var block = ec.CurrentBlock;
8785 if (block != null) {
8786 var top = block.ParametersBlock.TopBlock;
8787 if (top.ThisVariable != null)
8788 variable_info = top.ThisVariable.VariableInfo;
8790 AnonymousExpression am = ec.CurrentAnonymousMethod;
8791 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8793 // Hoisted this is almost like hoisted variable but not exactly. When
8794 // there is no variable hoisted we can simply emit an instance method
8795 // without lifting this into a storey. Unfotunatelly this complicates
8796 // things in other cases because we don't know where this will be hoisted
8797 // until top-level block is fully resolved
8799 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8800 am.SetHasThisAccess ();
8805 protected override Expression DoResolve (ResolveContext ec)
8811 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8813 if (eclass == ExprClass.Unresolved)
8817 if (right_side == EmptyExpression.UnaryAddress)
8818 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8819 else if (right_side == EmptyExpression.OutAccess)
8820 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8822 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8828 public override int GetHashCode()
8830 throw new NotImplementedException ();
8833 public override bool Equals (object obj)
8835 This t = obj as This;
8842 protected override void CloneTo (CloneContext clonectx, Expression t)
8847 public override void SetHasAddressTaken ()
8852 public override object Accept (StructuralVisitor visitor)
8854 return visitor.Visit (this);
8859 /// Represents the `__arglist' construct
8861 public class ArglistAccess : Expression
8863 public ArglistAccess (Location loc)
8868 protected override void CloneTo (CloneContext clonectx, Expression target)
8873 public override bool ContainsEmitWithAwait ()
8878 public override Expression CreateExpressionTree (ResolveContext ec)
8880 throw new NotSupportedException ("ET");
8883 protected override Expression DoResolve (ResolveContext ec)
8885 eclass = ExprClass.Variable;
8886 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8888 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8889 ec.Report.Error (190, loc,
8890 "The __arglist construct is valid only within a variable argument method");
8896 public override void Emit (EmitContext ec)
8898 ec.Emit (OpCodes.Arglist);
8901 public override object Accept (StructuralVisitor visitor)
8903 return visitor.Visit (this);
8908 /// Represents the `__arglist (....)' construct
8910 public class Arglist : Expression
8912 Arguments arguments;
8914 public Arglist (Location loc)
8919 public Arglist (Arguments args, Location l)
8925 public Arguments Arguments {
8931 public MetaType[] ArgumentTypes {
8933 if (arguments == null)
8934 return MetaType.EmptyTypes;
8936 var retval = new MetaType[arguments.Count];
8937 for (int i = 0; i < retval.Length; i++)
8938 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8944 public override bool ContainsEmitWithAwait ()
8946 throw new NotImplementedException ();
8949 public override Expression CreateExpressionTree (ResolveContext ec)
8951 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8955 protected override Expression DoResolve (ResolveContext ec)
8957 eclass = ExprClass.Variable;
8958 type = InternalType.Arglist;
8959 if (arguments != null) {
8960 bool dynamic; // Can be ignored as there is always only 1 overload
8961 arguments.Resolve (ec, out dynamic);
8967 public override void Emit (EmitContext ec)
8969 if (arguments != null)
8970 arguments.Emit (ec);
8973 protected override void CloneTo (CloneContext clonectx, Expression t)
8975 Arglist target = (Arglist) t;
8977 if (arguments != null)
8978 target.arguments = arguments.Clone (clonectx);
8981 public override object Accept (StructuralVisitor visitor)
8983 return visitor.Visit (this);
8987 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8989 FullNamedExpression texpr;
8991 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8998 public FullNamedExpression TypeExpression {
9004 public override bool ContainsEmitWithAwait ()
9009 public void AddressOf (EmitContext ec, AddressOp mode)
9012 ec.Emit (OpCodes.Refanyval, type);
9015 protected override Expression DoResolve (ResolveContext rc)
9017 expr = expr.Resolve (rc);
9018 type = texpr.ResolveAsType (rc);
9019 if (expr == null || type == null)
9022 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9023 eclass = ExprClass.Variable;
9027 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9029 return DoResolve (rc);
9032 public override void Emit (EmitContext ec)
9035 ec.Emit (OpCodes.Refanyval, type);
9036 ec.EmitLoadFromPtr (type);
9039 public void Emit (EmitContext ec, bool leave_copy)
9041 throw new NotImplementedException ();
9044 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9047 ec.Emit (OpCodes.Refanyval, type);
9050 LocalTemporary temporary = null;
9052 ec.Emit (OpCodes.Dup);
9053 temporary = new LocalTemporary (source.Type);
9054 temporary.Store (ec);
9057 ec.EmitStoreFromPtr (type);
9059 if (temporary != null) {
9060 temporary.Emit (ec);
9061 temporary.Release (ec);
9065 public override object Accept (StructuralVisitor visitor)
9067 return visitor.Visit (this);
9071 public class RefTypeExpr : ShimExpression
9073 public RefTypeExpr (Expression expr, Location loc)
9079 protected override Expression DoResolve (ResolveContext rc)
9081 expr = expr.Resolve (rc);
9085 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9089 type = rc.BuiltinTypes.Type;
9090 eclass = ExprClass.Value;
9094 public override void Emit (EmitContext ec)
9097 ec.Emit (OpCodes.Refanytype);
9098 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9100 ec.Emit (OpCodes.Call, m);
9103 public override object Accept (StructuralVisitor visitor)
9105 return visitor.Visit (this);
9109 public class MakeRefExpr : ShimExpression
9111 public MakeRefExpr (Expression expr, Location loc)
9117 public override bool ContainsEmitWithAwait ()
9119 throw new NotImplementedException ();
9122 protected override Expression DoResolve (ResolveContext rc)
9124 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9125 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9126 eclass = ExprClass.Value;
9130 public override void Emit (EmitContext ec)
9132 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9133 ec.Emit (OpCodes.Mkrefany, expr.Type);
9136 public override object Accept (StructuralVisitor visitor)
9138 return visitor.Visit (this);
9143 /// Implements the typeof operator
9145 public class TypeOf : Expression {
9146 FullNamedExpression QueriedType;
9149 public TypeOf (FullNamedExpression queried_type, Location l)
9151 QueriedType = queried_type;
9156 // Use this constructor for any compiler generated typeof expression
9158 public TypeOf (TypeSpec type, Location loc)
9160 this.typearg = type;
9166 public override bool IsSideEffectFree {
9172 public TypeSpec TypeArgument {
9178 public FullNamedExpression TypeExpression {
9187 protected override void CloneTo (CloneContext clonectx, Expression t)
9189 TypeOf target = (TypeOf) t;
9190 if (QueriedType != null)
9191 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9194 public override bool ContainsEmitWithAwait ()
9199 public override Expression CreateExpressionTree (ResolveContext ec)
9201 Arguments args = new Arguments (2);
9202 args.Add (new Argument (this));
9203 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9204 return CreateExpressionFactoryCall (ec, "Constant", args);
9207 protected override Expression DoResolve (ResolveContext ec)
9209 if (eclass != ExprClass.Unresolved)
9212 if (typearg == null) {
9214 // Pointer types are allowed without explicit unsafe, they are just tokens
9216 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9217 typearg = QueriedType.ResolveAsType (ec, true);
9220 if (typearg == null)
9223 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9224 ec.Report.Error (1962, QueriedType.Location,
9225 "The typeof operator cannot be used on the dynamic type");
9229 type = ec.BuiltinTypes.Type;
9231 // Even though what is returned is a type object, it's treated as a value by the compiler.
9232 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9233 eclass = ExprClass.Value;
9237 static bool ContainsDynamicType (TypeSpec type)
9239 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9242 var element_container = type as ElementTypeSpec;
9243 if (element_container != null)
9244 return ContainsDynamicType (element_container.Element);
9246 foreach (var t in type.TypeArguments) {
9247 if (ContainsDynamicType (t)) {
9255 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9257 // Target type is not System.Type therefore must be object
9258 // and we need to use different encoding sequence
9259 if (targetType != type)
9262 if (typearg is InflatedTypeSpec) {
9265 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9266 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9267 typearg.GetSignatureForError ());
9271 gt = gt.DeclaringType;
9272 } while (gt != null);
9275 if (ContainsDynamicType (typearg)) {
9276 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9280 enc.EncodeTypeName (typearg);
9283 public override void Emit (EmitContext ec)
9285 ec.Emit (OpCodes.Ldtoken, typearg);
9286 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9288 ec.Emit (OpCodes.Call, m);
9291 public override object Accept (StructuralVisitor visitor)
9293 return visitor.Visit (this);
9297 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9299 public TypeOfMethod (MethodSpec method, Location loc)
9300 : base (method, loc)
9304 protected override Expression DoResolve (ResolveContext ec)
9306 if (member.IsConstructor) {
9307 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9309 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9315 return base.DoResolve (ec);
9318 public override void Emit (EmitContext ec)
9320 ec.Emit (OpCodes.Ldtoken, member);
9323 ec.Emit (OpCodes.Castclass, type);
9326 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9328 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9331 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9333 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9337 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9339 protected readonly T member;
9341 protected TypeOfMember (T member, Location loc)
9343 this.member = member;
9347 public override bool IsSideEffectFree {
9353 public override bool ContainsEmitWithAwait ()
9358 public override Expression CreateExpressionTree (ResolveContext ec)
9360 Arguments args = new Arguments (2);
9361 args.Add (new Argument (this));
9362 args.Add (new Argument (new TypeOf (type, loc)));
9363 return CreateExpressionFactoryCall (ec, "Constant", args);
9366 protected override Expression DoResolve (ResolveContext ec)
9368 eclass = ExprClass.Value;
9372 public override void Emit (EmitContext ec)
9374 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9375 PredefinedMember<MethodSpec> p;
9377 p = GetTypeFromHandleGeneric (ec);
9378 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9380 p = GetTypeFromHandle (ec);
9383 var mi = p.Resolve (loc);
9385 ec.Emit (OpCodes.Call, mi);
9388 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9389 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9392 sealed class TypeOfField : TypeOfMember<FieldSpec>
9394 public TypeOfField (FieldSpec field, Location loc)
9399 protected override Expression DoResolve (ResolveContext ec)
9401 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9405 return base.DoResolve (ec);
9408 public override void Emit (EmitContext ec)
9410 ec.Emit (OpCodes.Ldtoken, member);
9414 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9416 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9419 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9421 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9426 /// Implements the sizeof expression
9428 public class SizeOf : Expression {
9429 readonly Expression texpr;
9430 TypeSpec type_queried;
9432 public SizeOf (Expression queried_type, Location l)
9434 this.texpr = queried_type;
9438 public override bool IsSideEffectFree {
9444 public Expression TypeExpression {
9450 public override bool ContainsEmitWithAwait ()
9455 public override Expression CreateExpressionTree (ResolveContext ec)
9457 Error_PointerInsideExpressionTree (ec);
9461 protected override Expression DoResolve (ResolveContext ec)
9463 type_queried = texpr.ResolveAsType (ec);
9464 if (type_queried == null)
9467 if (type_queried.IsEnum)
9468 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9470 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9472 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9475 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9480 ec.Report.Error (233, loc,
9481 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9482 type_queried.GetSignatureForError ());
9485 type = ec.BuiltinTypes.Int;
9486 eclass = ExprClass.Value;
9490 public override void Emit (EmitContext ec)
9492 ec.Emit (OpCodes.Sizeof, type_queried);
9495 protected override void CloneTo (CloneContext clonectx, Expression t)
9499 public override object Accept (StructuralVisitor visitor)
9501 return visitor.Visit (this);
9506 /// Implements the qualified-alias-member (::) expression.
9508 public class QualifiedAliasMember : MemberAccess
9510 readonly string alias;
9511 public static readonly string GlobalAlias = "global";
9513 public QualifiedAliasMember (string alias, string identifier, Location l)
9514 : base (null, identifier, l)
9519 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9520 : base (null, identifier, targs, l)
9525 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9526 : base (null, identifier, arity, l)
9531 public string Alias {
9537 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9539 if (alias == GlobalAlias)
9540 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9542 int errors = mc.Module.Compiler.Report.Errors;
9543 var expr = mc.LookupNamespaceAlias (alias);
9545 if (errors == mc.Module.Compiler.Report.Errors)
9546 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9554 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9556 expr = CreateExpressionFromAlias (mc);
9560 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9563 protected override Expression DoResolve (ResolveContext rc)
9565 return ResolveAsTypeOrNamespace (rc, false);
9568 public override string GetSignatureForError ()
9571 if (targs != null) {
9572 name = Name + "<" + targs.GetSignatureForError () + ">";
9575 return alias + "::" + name;
9578 public override bool HasConditionalAccess ()
9583 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9585 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9586 rc.Module.Compiler.Report.Error (687, loc,
9587 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9588 GetSignatureForError ());
9593 return DoResolve (rc);
9596 protected override void CloneTo (CloneContext clonectx, Expression t)
9601 public override object Accept (StructuralVisitor visitor)
9603 return visitor.Visit (this);
9608 /// Implements the member access expression
9610 public class MemberAccess : ATypeNameExpression
9612 protected Expression expr;
9614 public MemberAccess (Expression expr, string id)
9615 : base (id, expr.Location)
9620 public MemberAccess (Expression expr, string identifier, Location loc)
9621 : base (identifier, loc)
9626 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9627 : base (identifier, args, loc)
9632 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9633 : base (identifier, arity, loc)
9638 public Expression LeftExpression {
9644 public override Location StartLocation {
9646 return expr == null ? loc : expr.StartLocation;
9650 protected override Expression DoResolve (ResolveContext rc)
9652 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9654 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9659 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9661 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9663 if (e is TypeExpr) {
9664 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9669 e = e.ResolveLValue (rc, rhs);
9674 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9676 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9677 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9679 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9682 public override bool HasConditionalAccess ()
9684 return LeftExpression.HasConditionalAccess ();
9687 public static bool IsValidDotExpression (TypeSpec type)
9689 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9690 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9692 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9695 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9697 var sn = expr as SimpleName;
9698 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9701 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9704 // Resolve expression which does have type set as we need expression type
9705 // with disable flow analysis as we don't know whether left side expression
9706 // is used as variable or type
9708 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9709 expr = expr.Resolve (rc);
9710 } else if (expr is TypeParameterExpr) {
9711 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9715 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9716 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9717 expr = expr.Resolve (rc, flags);
9720 expr = expr.Resolve (rc, flags);
9727 var ns = expr as NamespaceExpression;
9729 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9731 if (retval == null) {
9732 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9737 if (HasTypeArguments)
9738 return new GenericTypeExpr (retval.Type, targs, loc);
9740 targs.Resolve (rc, false);
9747 TypeSpec expr_type = expr.Type;
9748 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9749 me = expr as MemberExpr;
9751 me.ResolveInstanceExpression (rc, null);
9753 Arguments args = new Arguments (1);
9754 args.Add (new Argument (expr));
9755 return new DynamicMemberBinder (Name, args, loc);
9758 var cma = this as ConditionalMemberAccess;
9760 if (!IsNullPropagatingValid (expr.Type)) {
9761 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9765 if (expr_type.IsNullableType) {
9766 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9767 expr_type = expr.Type;
9771 if (!IsValidDotExpression (expr_type)) {
9772 Error_OperatorCannotBeApplied (rc, expr_type);
9776 var lookup_arity = Arity;
9777 bool errorMode = false;
9778 Expression member_lookup;
9780 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9781 if (member_lookup == null) {
9783 // Try to look for extension method when member lookup failed
9785 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9786 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9787 if (methods != null) {
9788 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9789 if (HasTypeArguments) {
9790 if (!targs.Resolve (rc, false))
9793 emg.SetTypeArguments (rc, targs);
9797 emg.ConditionalAccess = true;
9799 // TODO: it should really skip the checks bellow
9800 return emg.Resolve (rc);
9806 if (member_lookup == null) {
9807 var dep = expr_type.GetMissingDependencies ();
9809 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9810 } else if (expr is TypeExpr) {
9811 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9813 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9819 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9820 // Leave it to overload resolution to report correct error
9821 } else if (!(member_lookup is TypeExpr)) {
9822 // TODO: rc.SymbolRelatedToPreviousError
9823 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9828 if (member_lookup != null)
9832 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9836 TypeExpr texpr = member_lookup as TypeExpr;
9837 if (texpr != null) {
9838 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9839 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9840 Name, texpr.GetSignatureForError ());
9843 if (!texpr.Type.IsAccessible (rc)) {
9844 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9845 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9849 if (HasTypeArguments) {
9850 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9853 return member_lookup;
9856 me = member_lookup as MemberExpr;
9858 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9863 me.ConditionalAccess = true;
9866 me = me.ResolveMemberAccess (rc, expr, sn);
9869 if (!targs.Resolve (rc, false))
9872 me.SetTypeArguments (rc, targs);
9878 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9880 FullNamedExpression fexpr = expr as FullNamedExpression;
9881 if (fexpr == null) {
9882 expr.ResolveAsType (rc);
9886 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9888 if (expr_resolved == null)
9891 var ns = expr_resolved as NamespaceExpression;
9893 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9895 if (retval == null) {
9896 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9897 } else if (Arity > 0) {
9898 if (HasTypeArguments) {
9899 retval = new GenericTypeExpr (retval.Type, targs, loc);
9900 if (retval.ResolveAsType (rc) == null)
9903 targs.Resolve (rc, allowUnboundTypeArguments);
9905 retval = new GenericOpenTypeExpr (retval.Type, loc);
9912 var tnew_expr = expr_resolved.ResolveAsType (rc);
9913 if (tnew_expr == null)
9916 TypeSpec expr_type = tnew_expr;
9917 if (TypeManager.IsGenericParameter (expr_type)) {
9918 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9919 tnew_expr.GetSignatureForError ());
9923 var qam = this as QualifiedAliasMember;
9925 rc.Module.Compiler.Report.Error (431, loc,
9926 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9931 TypeSpec nested = null;
9932 while (expr_type != null) {
9933 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9934 if (nested == null) {
9935 if (expr_type == tnew_expr) {
9936 Error_IdentifierNotFound (rc, expr_type);
9940 expr_type = tnew_expr;
9941 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9942 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9946 if (nested.IsAccessible (rc))
9950 // Keep looking after inaccessible candidate but only if
9951 // we are not in same context as the definition itself
9953 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9956 expr_type = expr_type.BaseType;
9961 if (HasTypeArguments) {
9962 texpr = new GenericTypeExpr (nested, targs, loc);
9964 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9966 texpr = new GenericOpenTypeExpr (nested, loc);
9968 } else if (expr_resolved is GenericOpenTypeExpr) {
9969 texpr = new GenericOpenTypeExpr (nested, loc);
9971 texpr = new TypeExpression (nested, loc);
9974 if (texpr.ResolveAsType (rc) == null)
9980 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9982 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9984 if (nested != null) {
9985 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9989 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9990 if (any_other_member != null) {
9991 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9995 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9996 Name, expr_type.GetSignatureForError ());
9999 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10001 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10004 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10006 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10007 ec.Report.SymbolRelatedToPreviousError (type);
10009 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10011 // a using directive or an assembly reference
10012 if (cand != null) {
10013 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10015 missing = "an assembly reference";
10018 ec.Report.Error (1061, loc,
10019 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10020 type.GetSignatureForError (), name, missing);
10024 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10027 public override string GetSignatureForError ()
10029 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10032 protected override void CloneTo (CloneContext clonectx, Expression t)
10034 MemberAccess target = (MemberAccess) t;
10036 target.expr = expr.Clone (clonectx);
10039 public override object Accept (StructuralVisitor visitor)
10041 return visitor.Visit (this);
10045 public class ConditionalMemberAccess : MemberAccess
10047 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10048 : base (expr, identifier, args, loc)
10052 public override bool HasConditionalAccess ()
10059 /// Implements checked expressions
10061 public class CheckedExpr : Expression {
10063 public Expression Expr;
10065 public CheckedExpr (Expression e, Location l)
10071 public override bool ContainsEmitWithAwait ()
10073 return Expr.ContainsEmitWithAwait ();
10076 public override Expression CreateExpressionTree (ResolveContext ec)
10078 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10079 return Expr.CreateExpressionTree (ec);
10082 protected override Expression DoResolve (ResolveContext ec)
10084 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10085 Expr = Expr.Resolve (ec);
10090 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10093 eclass = Expr.eclass;
10098 public override void Emit (EmitContext ec)
10100 using (ec.With (EmitContext.Options.CheckedScope, true))
10104 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10106 using (ec.With (EmitContext.Options.CheckedScope, true))
10107 Expr.EmitBranchable (ec, target, on_true);
10110 public override void FlowAnalysis (FlowAnalysisContext fc)
10112 Expr.FlowAnalysis (fc);
10115 public override SLE.Expression MakeExpression (BuilderContext ctx)
10117 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10118 return Expr.MakeExpression (ctx);
10122 protected override void CloneTo (CloneContext clonectx, Expression t)
10124 CheckedExpr target = (CheckedExpr) t;
10126 target.Expr = Expr.Clone (clonectx);
10129 public override object Accept (StructuralVisitor visitor)
10131 return visitor.Visit (this);
10136 /// Implements the unchecked expression
10138 public class UnCheckedExpr : Expression {
10140 public Expression Expr;
10142 public UnCheckedExpr (Expression e, Location l)
10148 public override bool ContainsEmitWithAwait ()
10150 return Expr.ContainsEmitWithAwait ();
10153 public override Expression CreateExpressionTree (ResolveContext ec)
10155 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10156 return Expr.CreateExpressionTree (ec);
10159 protected override Expression DoResolve (ResolveContext ec)
10161 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10162 Expr = Expr.Resolve (ec);
10167 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10170 eclass = Expr.eclass;
10175 public override void Emit (EmitContext ec)
10177 using (ec.With (EmitContext.Options.CheckedScope, false))
10181 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10183 using (ec.With (EmitContext.Options.CheckedScope, false))
10184 Expr.EmitBranchable (ec, target, on_true);
10187 public override void FlowAnalysis (FlowAnalysisContext fc)
10189 Expr.FlowAnalysis (fc);
10192 protected override void CloneTo (CloneContext clonectx, Expression t)
10194 UnCheckedExpr target = (UnCheckedExpr) t;
10196 target.Expr = Expr.Clone (clonectx);
10199 public override object Accept (StructuralVisitor visitor)
10201 return visitor.Visit (this);
10206 /// An Element Access expression.
10208 /// During semantic analysis these are transformed into
10209 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10211 public class ElementAccess : Expression
10213 public Arguments Arguments;
10214 public Expression Expr;
10215 bool conditional_access_receiver;
10217 public ElementAccess (Expression e, Arguments args, Location loc)
10221 this.Arguments = args;
10224 public bool ConditionalAccess { get; set; }
10226 public override Location StartLocation {
10228 return Expr.StartLocation;
10232 public override bool ContainsEmitWithAwait ()
10234 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10238 // We perform some simple tests, and then to "split" the emit and store
10239 // code we create an instance of a different class, and return that.
10241 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10243 if (conditionalAccessReceiver)
10244 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10246 Expr = Expr.Resolve (ec);
10248 if (conditionalAccessReceiver)
10249 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10256 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10257 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10261 if (type.IsArray) {
10262 var aa = new ArrayAccess (this, loc) {
10263 ConditionalAccess = ConditionalAccess,
10266 if (conditionalAccessReceiver)
10267 aa.SetConditionalAccessReceiver ();
10272 if (type.IsPointer)
10273 return Expr.MakePointerAccess (ec, type, Arguments);
10275 FieldExpr fe = Expr as FieldExpr;
10277 var ff = fe.Spec as FixedFieldSpec;
10279 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10283 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10284 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10285 var indexer = new IndexerExpr (indexers, type, this) {
10286 ConditionalAccess = ConditionalAccess
10289 if (conditionalAccessReceiver)
10290 indexer.SetConditionalAccessReceiver ();
10295 Error_CannotApplyIndexing (ec, type, loc);
10300 public override Expression CreateExpressionTree (ResolveContext ec)
10302 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10303 Expr.CreateExpressionTree (ec));
10305 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10308 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10310 if (type != InternalType.ErrorType) {
10311 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10312 type.GetSignatureForError ());
10316 public override bool HasConditionalAccess ()
10318 return ConditionalAccess || Expr.HasConditionalAccess ();
10321 void ResolveConditionalAccessReceiver (ResolveContext rc)
10323 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10324 conditional_access_receiver = true;
10328 protected override Expression DoResolve (ResolveContext rc)
10330 ResolveConditionalAccessReceiver (rc);
10332 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10336 return expr.Resolve (rc);
10339 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10341 var res = CreateAccessExpression (ec, false);
10345 return res.ResolveLValue (ec, rhs);
10348 public override void Emit (EmitContext ec)
10350 throw new Exception ("Should never be reached");
10353 public override void FlowAnalysis (FlowAnalysisContext fc)
10355 Expr.FlowAnalysis (fc);
10357 Arguments.FlowAnalysis (fc);
10360 public override string GetSignatureForError ()
10362 return Expr.GetSignatureForError ();
10365 protected override void CloneTo (CloneContext clonectx, Expression t)
10367 ElementAccess target = (ElementAccess) t;
10369 target.Expr = Expr.Clone (clonectx);
10370 if (Arguments != null)
10371 target.Arguments = Arguments.Clone (clonectx);
10374 public override object Accept (StructuralVisitor visitor)
10376 return visitor.Visit (this);
10381 /// Implements array access
10383 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10385 // Points to our "data" repository
10389 LocalTemporary temp;
10391 bool? has_await_args;
10392 bool conditional_access_receiver;
10394 public ArrayAccess (ElementAccess ea_data, Location l)
10400 public bool ConditionalAccess { get; set; }
10402 public void AddressOf (EmitContext ec, AddressOp mode)
10404 var ac = (ArrayContainer) ea.Expr.Type;
10406 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10407 LoadInstanceAndArguments (ec, false, true);
10410 LoadInstanceAndArguments (ec, false, false);
10412 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10413 ec.Emit (OpCodes.Readonly);
10415 ec.EmitArrayAddress (ac);
10418 public override Expression CreateExpressionTree (ResolveContext ec)
10420 if (ConditionalAccess)
10421 Error_NullShortCircuitInsideExpressionTree (ec);
10423 return ea.CreateExpressionTree (ec);
10426 public override bool ContainsEmitWithAwait ()
10428 return ea.ContainsEmitWithAwait ();
10431 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10433 if (HasConditionalAccess ())
10434 Error_NullPropagatingLValue (ec);
10436 return DoResolve (ec);
10439 protected override Expression DoResolve (ResolveContext ec)
10441 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10443 ea.Arguments.Resolve (ec, out dynamic);
10445 var ac = ea.Expr.Type as ArrayContainer;
10446 int rank = ea.Arguments.Count;
10447 if (ac.Rank != rank) {
10448 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10449 rank.ToString (), ac.Rank.ToString ());
10454 if (type.IsPointer && !ec.IsUnsafe) {
10455 UnsafeError (ec, ea.Location);
10458 if (conditional_access_receiver)
10459 type = LiftMemberType (ec, type);
10461 foreach (Argument a in ea.Arguments) {
10462 var na = a as NamedArgument;
10464 ElementAccess.Error_NamedArgument (na, ec.Report);
10466 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10469 eclass = ExprClass.Variable;
10474 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10476 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10479 public override void FlowAnalysis (FlowAnalysisContext fc)
10481 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10483 ea.FlowAnalysis (fc);
10485 if (conditional_access_receiver)
10486 fc.DefiniteAssignment = da;
10489 public override bool HasConditionalAccess ()
10491 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10495 // Load the array arguments into the stack.
10497 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10499 if (prepareAwait) {
10500 ea.Expr = ea.Expr.EmitToField (ec);
10502 var ie = new InstanceEmitter (ea.Expr, false);
10503 ie.Emit (ec, ConditionalAccess);
10505 if (duplicateArguments) {
10506 ec.Emit (OpCodes.Dup);
10508 var copy = new LocalTemporary (ea.Expr.Type);
10514 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10515 if (dup_args != null)
10516 ea.Arguments = dup_args;
10519 public void Emit (EmitContext ec, bool leave_copy)
10522 ec.EmitLoadFromPtr (type);
10524 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10525 LoadInstanceAndArguments (ec, false, true);
10528 if (conditional_access_receiver)
10529 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10531 var ac = (ArrayContainer) ea.Expr.Type;
10532 LoadInstanceAndArguments (ec, false, false);
10533 ec.EmitArrayLoad (ac);
10535 if (conditional_access_receiver)
10536 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10540 ec.Emit (OpCodes.Dup);
10541 temp = new LocalTemporary (this.type);
10546 public override void Emit (EmitContext ec)
10551 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10553 var ac = (ArrayContainer) ea.Expr.Type;
10554 TypeSpec t = source.Type;
10556 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10559 // When we are dealing with a struct, get the address of it to avoid value copy
10560 // Same cannot be done for reference type because array covariance and the
10561 // check in ldelema requires to specify the type of array element stored at the index
10563 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10564 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10566 if (has_await_args.Value) {
10567 if (source.ContainsEmitWithAwait ()) {
10568 source = source.EmitToField (ec);
10569 isCompound = false;
10573 LoadInstanceAndArguments (ec, isCompound, false);
10578 ec.EmitArrayAddress (ac);
10581 ec.Emit (OpCodes.Dup);
10585 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10587 if (has_await_args.Value) {
10588 if (source.ContainsEmitWithAwait ())
10589 source = source.EmitToField (ec);
10591 LoadInstanceAndArguments (ec, false, false);
10598 var lt = ea.Expr as LocalTemporary;
10604 ec.Emit (OpCodes.Dup);
10605 temp = new LocalTemporary (this.type);
10610 ec.EmitStoreFromPtr (t);
10612 ec.EmitArrayStore (ac);
10615 if (temp != null) {
10621 public override Expression EmitToField (EmitContext ec)
10624 // Have to be specialized for arrays to get access to
10625 // underlying element. Instead of another result copy we
10626 // need direct access to element
10630 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10632 ea.Expr = ea.Expr.EmitToField (ec);
10633 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10637 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10639 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10642 public override SLE.Expression MakeExpression (BuilderContext ctx)
10644 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10647 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10649 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10650 return Arguments.MakeExpression (ea.Arguments, ctx);
10654 public void SetConditionalAccessReceiver ()
10656 conditional_access_receiver = true;
10661 // Indexer access expression
10663 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10665 IList<MemberSpec> indexers;
10666 Arguments arguments;
10667 TypeSpec queried_type;
10669 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10670 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10674 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10677 this.indexers = indexers;
10678 this.queried_type = queriedType;
10679 this.InstanceExpression = instance;
10680 this.arguments = args;
10685 protected override Arguments Arguments {
10694 protected override TypeSpec DeclaringType {
10696 return best_candidate.DeclaringType;
10700 public override bool IsInstance {
10706 public override bool IsStatic {
10712 public override string KindName {
10713 get { return "indexer"; }
10716 public override string Name {
10724 public override bool ContainsEmitWithAwait ()
10726 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10729 public override Expression CreateExpressionTree (ResolveContext ec)
10731 if (ConditionalAccess) {
10732 Error_NullShortCircuitInsideExpressionTree (ec);
10735 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10736 InstanceExpression.CreateExpressionTree (ec),
10737 new TypeOfMethod (Getter, loc));
10739 return CreateExpressionFactoryCall (ec, "Call", args);
10742 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10744 LocalTemporary await_source_arg = null;
10747 emitting_compound_assignment = true;
10748 if (source is DynamicExpressionStatement) {
10753 emitting_compound_assignment = false;
10755 if (has_await_arguments) {
10756 await_source_arg = new LocalTemporary (Type);
10757 await_source_arg.Store (ec);
10759 arguments.Add (new Argument (await_source_arg));
10762 temp = await_source_arg;
10765 has_await_arguments = false;
10770 ec.Emit (OpCodes.Dup);
10771 temp = new LocalTemporary (Type);
10777 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10778 source = source.EmitToField (ec);
10780 temp = new LocalTemporary (Type);
10787 arguments.Add (new Argument (source));
10790 var call = new CallEmitter ();
10791 call.InstanceExpression = InstanceExpression;
10792 if (arguments == null)
10793 call.InstanceExpressionOnStack = true;
10795 call.Emit (ec, Setter, arguments, loc);
10797 if (temp != null) {
10800 } else if (leave_copy) {
10804 if (await_source_arg != null) {
10805 await_source_arg.Release (ec);
10809 public override void FlowAnalysis (FlowAnalysisContext fc)
10811 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10813 base.FlowAnalysis (fc);
10814 arguments.FlowAnalysis (fc);
10816 if (conditional_access_receiver)
10817 fc.DefiniteAssignment = da;
10820 public override string GetSignatureForError ()
10822 return best_candidate.GetSignatureForError ();
10825 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10828 throw new NotSupportedException ();
10830 var value = new[] { source.MakeExpression (ctx) };
10831 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10832 return SLE.Expression.Block (
10833 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10838 public override SLE.Expression MakeExpression (BuilderContext ctx)
10841 return base.MakeExpression (ctx);
10843 var args = Arguments.MakeExpression (arguments, ctx);
10844 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10848 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10850 if (best_candidate != null)
10853 eclass = ExprClass.IndexerAccess;
10856 arguments.Resolve (rc, out dynamic);
10858 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10861 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10862 res.BaseMembersProvider = this;
10863 res.InstanceQualifier = this;
10865 // TODO: Do I need 2 argument sets?
10866 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10867 if (best_candidate != null)
10868 type = res.BestCandidateReturnType;
10869 else if (!res.BestCandidateIsDynamic)
10874 // It has dynamic arguments
10877 Arguments args = new Arguments (arguments.Count + 1);
10879 rc.Report.Error (1972, loc,
10880 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10882 args.Add (new Argument (InstanceExpression));
10884 args.AddRange (arguments);
10886 best_candidate = null;
10887 return new DynamicIndexBinder (args, loc);
10891 // Try to avoid resolving left expression again
10893 if (right_side != null)
10894 ResolveInstanceExpression (rc, right_side);
10899 protected override void CloneTo (CloneContext clonectx, Expression t)
10901 IndexerExpr target = (IndexerExpr) t;
10903 if (arguments != null)
10904 target.arguments = arguments.Clone (clonectx);
10907 public void SetConditionalAccessReceiver ()
10909 conditional_access_receiver = true;
10912 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10914 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10917 #region IBaseMembersProvider Members
10919 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10921 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10924 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10926 if (queried_type == member.DeclaringType)
10929 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10930 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10933 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10942 // A base access expression
10944 public class BaseThis : This
10946 public BaseThis (Location loc)
10951 public BaseThis (TypeSpec type, Location loc)
10955 eclass = ExprClass.Variable;
10960 public override string Name {
10968 public override Expression CreateExpressionTree (ResolveContext ec)
10970 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10971 return base.CreateExpressionTree (ec);
10974 public override void Emit (EmitContext ec)
10978 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10979 var context_type = ec.CurrentType;
10980 ec.Emit (OpCodes.Ldobj, context_type);
10981 ec.Emit (OpCodes.Box, context_type);
10985 protected override void Error_ThisNotAvailable (ResolveContext ec)
10988 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10990 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10994 public override void ResolveBase (ResolveContext ec)
10996 base.ResolveBase (ec);
10997 type = ec.CurrentType.BaseType;
11000 public override object Accept (StructuralVisitor visitor)
11002 return visitor.Visit (this);
11007 /// This class exists solely to pass the Type around and to be a dummy
11008 /// that can be passed to the conversion functions (this is used by
11009 /// foreach implementation to typecast the object return value from
11010 /// get_Current into the proper type. All code has been generated and
11011 /// we only care about the side effect conversions to be performed
11013 /// This is also now used as a placeholder where a no-action expression
11014 /// is needed (the `New' class).
11016 public class EmptyExpression : Expression
11018 sealed class OutAccessExpression : EmptyExpression
11020 public OutAccessExpression (TypeSpec t)
11025 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11027 rc.Report.Error (206, right_side.Location,
11028 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11034 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11035 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11036 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11037 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11038 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11039 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11040 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11041 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11043 public EmptyExpression (TypeSpec t)
11046 eclass = ExprClass.Value;
11047 loc = Location.Null;
11050 protected override void CloneTo (CloneContext clonectx, Expression target)
11054 public override bool ContainsEmitWithAwait ()
11059 public override Expression CreateExpressionTree (ResolveContext ec)
11061 throw new NotSupportedException ("ET");
11064 protected override Expression DoResolve (ResolveContext ec)
11069 public override void Emit (EmitContext ec)
11071 // nothing, as we only exist to not do anything.
11074 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11078 public override void EmitSideEffect (EmitContext ec)
11082 public override object Accept (StructuralVisitor visitor)
11084 return visitor.Visit (this);
11088 sealed class EmptyAwaitExpression : EmptyExpression
11090 public EmptyAwaitExpression (TypeSpec type)
11095 public override bool ContainsEmitWithAwait ()
11102 // Empty statement expression
11104 public sealed class EmptyExpressionStatement : ExpressionStatement
11106 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11108 private EmptyExpressionStatement ()
11110 loc = Location.Null;
11113 public override bool ContainsEmitWithAwait ()
11118 public override Expression CreateExpressionTree (ResolveContext ec)
11123 public override void EmitStatement (EmitContext ec)
11128 protected override Expression DoResolve (ResolveContext ec)
11130 eclass = ExprClass.Value;
11131 type = ec.BuiltinTypes.Object;
11135 public override void Emit (EmitContext ec)
11140 public override object Accept (StructuralVisitor visitor)
11142 return visitor.Visit (this);
11146 public class ErrorExpression : EmptyExpression
11148 public static readonly ErrorExpression Instance = new ErrorExpression ();
11150 private ErrorExpression ()
11151 : base (InternalType.ErrorType)
11155 public override Expression CreateExpressionTree (ResolveContext ec)
11160 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11165 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11169 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11173 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11177 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11181 public override object Accept (StructuralVisitor visitor)
11183 return visitor.Visit (this);
11187 public class UserCast : Expression {
11191 public UserCast (MethodSpec method, Expression source, Location l)
11193 if (source == null)
11194 throw new ArgumentNullException ("source");
11196 this.method = method;
11197 this.source = source;
11198 type = method.ReturnType;
11202 public Expression Source {
11211 public override bool ContainsEmitWithAwait ()
11213 return source.ContainsEmitWithAwait ();
11216 public override Expression CreateExpressionTree (ResolveContext ec)
11218 Arguments args = new Arguments (3);
11219 args.Add (new Argument (source.CreateExpressionTree (ec)));
11220 args.Add (new Argument (new TypeOf (type, loc)));
11221 args.Add (new Argument (new TypeOfMethod (method, loc)));
11222 return CreateExpressionFactoryCall (ec, "Convert", args);
11225 protected override Expression DoResolve (ResolveContext ec)
11227 method.CheckObsoleteness (ec, source.Location);
11229 eclass = ExprClass.Value;
11233 public override void Emit (EmitContext ec)
11236 ec.MarkCallEntry (loc);
11237 ec.Emit (OpCodes.Call, method);
11240 public override void FlowAnalysis (FlowAnalysisContext fc)
11242 source.FlowAnalysis (fc);
11245 public override string GetSignatureForError ()
11247 return TypeManager.CSharpSignature (method);
11250 public override SLE.Expression MakeExpression (BuilderContext ctx)
11253 return base.MakeExpression (ctx);
11255 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11261 // Holds additional type specifiers like ?, *, []
11263 public class ComposedTypeSpecifier
11265 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11267 public readonly int Dimension;
11268 public readonly Location Location;
11270 public ComposedTypeSpecifier (int specifier, Location loc)
11272 this.Dimension = specifier;
11273 this.Location = loc;
11277 public bool IsNullable {
11279 return Dimension == -1;
11283 public bool IsPointer {
11285 return Dimension == -2;
11289 public ComposedTypeSpecifier Next { get; set; }
11293 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11295 return new ComposedTypeSpecifier (dimension, loc);
11298 public static ComposedTypeSpecifier CreateNullable (Location loc)
11300 return new ComposedTypeSpecifier (-1, loc);
11303 public static ComposedTypeSpecifier CreatePointer (Location loc)
11305 return new ComposedTypeSpecifier (-2, loc);
11308 public string GetSignatureForError ()
11313 ArrayContainer.GetPostfixSignature (Dimension);
11315 return Next != null ? s + Next.GetSignatureForError () : s;
11320 // This class is used to "construct" the type during a typecast
11321 // operation. Since the Type.GetType class in .NET can parse
11322 // the type specification, we just use this to construct the type
11323 // one bit at a time.
11325 public class ComposedCast : TypeExpr {
11326 FullNamedExpression left;
11327 ComposedTypeSpecifier spec;
11329 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11332 throw new ArgumentNullException ("spec");
11336 this.loc = left.Location;
11339 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11341 type = left.ResolveAsType (ec);
11345 eclass = ExprClass.Type;
11347 var single_spec = spec;
11349 if (single_spec.IsNullable) {
11350 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11354 single_spec = single_spec.Next;
11355 } else if (single_spec.IsPointer) {
11356 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11359 if (!ec.IsUnsafe) {
11360 UnsafeError (ec.Module.Compiler.Report, loc);
11364 type = PointerContainer.MakeType (ec.Module, type);
11365 single_spec = single_spec.Next;
11366 } while (single_spec != null && single_spec.IsPointer);
11369 if (single_spec != null && single_spec.Dimension > 0) {
11370 if (type.IsSpecialRuntimeType) {
11371 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11372 } else if (type.IsStatic) {
11373 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11374 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11375 type.GetSignatureForError ());
11377 MakeArray (ec.Module, single_spec);
11384 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11386 if (spec.Next != null)
11387 MakeArray (module, spec.Next);
11389 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11392 public override string GetSignatureForError ()
11394 return left.GetSignatureForError () + spec.GetSignatureForError ();
11397 public override object Accept (StructuralVisitor visitor)
11399 return visitor.Visit (this);
11403 class FixedBufferPtr : Expression
11405 readonly Expression array;
11407 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11409 this.type = array_type;
11410 this.array = array;
11414 public override bool ContainsEmitWithAwait ()
11416 throw new NotImplementedException ();
11419 public override Expression CreateExpressionTree (ResolveContext ec)
11421 Error_PointerInsideExpressionTree (ec);
11425 public override void Emit(EmitContext ec)
11430 protected override Expression DoResolve (ResolveContext ec)
11432 type = PointerContainer.MakeType (ec.Module, type);
11433 eclass = ExprClass.Value;
11440 // This class is used to represent the address of an array, used
11441 // only by the Fixed statement, this generates "&a [0]" construct
11442 // for fixed (char *pa = a)
11444 class ArrayPtr : FixedBufferPtr
11446 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11447 base (array, array_type, l)
11451 public override void Emit (EmitContext ec)
11456 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11461 // Encapsulates a conversion rules required for array indexes
11463 public class ArrayIndexCast : TypeCast
11465 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11466 : base (expr, returnType)
11468 if (expr.Type == returnType) // int -> int
11469 throw new ArgumentException ("unnecessary array index conversion");
11472 public override Expression CreateExpressionTree (ResolveContext ec)
11474 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11475 return base.CreateExpressionTree (ec);
11479 public override void Emit (EmitContext ec)
11483 switch (child.Type.BuiltinType) {
11484 case BuiltinTypeSpec.Type.UInt:
11485 ec.Emit (OpCodes.Conv_U);
11487 case BuiltinTypeSpec.Type.Long:
11488 ec.Emit (OpCodes.Conv_Ovf_I);
11490 case BuiltinTypeSpec.Type.ULong:
11491 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11494 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11500 // Implements the `stackalloc' keyword
11502 public class StackAlloc : Expression {
11507 public StackAlloc (Expression type, Expression count, Location l)
11510 this.count = count;
11514 public Expression TypeExpression {
11520 public Expression CountExpression {
11526 public override bool ContainsEmitWithAwait ()
11531 public override Expression CreateExpressionTree (ResolveContext ec)
11533 throw new NotSupportedException ("ET");
11536 protected override Expression DoResolve (ResolveContext ec)
11538 count = count.Resolve (ec);
11542 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11543 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11548 Constant c = count as Constant;
11549 if (c != null && c.IsNegative) {
11550 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11553 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11554 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11557 otype = texpr.ResolveAsType (ec);
11561 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11564 type = PointerContainer.MakeType (ec.Module, otype);
11565 eclass = ExprClass.Value;
11570 public override void Emit (EmitContext ec)
11572 int size = BuiltinTypeSpec.GetSize (otype);
11577 ec.Emit (OpCodes.Sizeof, otype);
11581 ec.Emit (OpCodes.Mul_Ovf_Un);
11582 ec.Emit (OpCodes.Localloc);
11585 protected override void CloneTo (CloneContext clonectx, Expression t)
11587 StackAlloc target = (StackAlloc) t;
11588 target.count = count.Clone (clonectx);
11589 target.texpr = texpr.Clone (clonectx);
11592 public override object Accept (StructuralVisitor visitor)
11594 return visitor.Visit (this);
11599 // An object initializer expression
11601 public class ElementInitializer : Assign
11603 public readonly string Name;
11605 public ElementInitializer (string name, Expression initializer, Location loc)
11606 : base (null, initializer, loc)
11611 public bool IsDictionaryInitializer {
11613 return Name == null;
11617 protected override void CloneTo (CloneContext clonectx, Expression t)
11619 ElementInitializer target = (ElementInitializer) t;
11620 target.source = source.Clone (clonectx);
11623 public override Expression CreateExpressionTree (ResolveContext ec)
11625 Arguments args = new Arguments (2);
11626 FieldExpr fe = target as FieldExpr;
11628 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11630 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11633 Expression arg_expr;
11634 var cinit = source as CollectionOrObjectInitializers;
11635 if (cinit == null) {
11637 arg_expr = source.CreateExpressionTree (ec);
11639 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11640 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11643 args.Add (new Argument (arg_expr));
11644 return CreateExpressionFactoryCall (ec, mname, args);
11647 protected override Expression DoResolve (ResolveContext ec)
11649 if (source == null)
11650 return EmptyExpressionStatement.Instance;
11652 if (!ResolveElement (ec))
11655 if (source is CollectionOrObjectInitializers) {
11656 Expression previous = ec.CurrentInitializerVariable;
11657 ec.CurrentInitializerVariable = target;
11658 source = source.Resolve (ec);
11659 ec.CurrentInitializerVariable = previous;
11660 if (source == null)
11663 eclass = source.eclass;
11664 type = source.Type;
11668 return base.DoResolve (ec);
11671 public override void EmitStatement (EmitContext ec)
11673 if (source is CollectionOrObjectInitializers)
11676 base.EmitStatement (ec);
11679 protected virtual bool ResolveElement (ResolveContext rc)
11681 var t = rc.CurrentInitializerVariable.Type;
11682 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11683 Arguments args = new Arguments (1);
11684 args.Add (new Argument (rc.CurrentInitializerVariable));
11685 target = new DynamicMemberBinder (Name, args, loc);
11688 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11689 if (member == null) {
11690 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11692 if (member != null) {
11693 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11694 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11699 if (member == null) {
11700 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11704 var me = member as MemberExpr;
11705 if (me is EventExpr) {
11706 me = me.ResolveMemberAccess (rc, null, null);
11707 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11708 rc.Report.Error (1913, loc,
11709 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11710 member.GetSignatureForError ());
11716 rc.Report.Error (1914, loc,
11717 "Static field or property `{0}' cannot be assigned in an object initializer",
11718 me.GetSignatureForError ());
11722 me.InstanceExpression = rc.CurrentInitializerVariable;
11730 // A collection initializer expression
11732 class CollectionElementInitializer : Invocation
11734 public class ElementInitializerArgument : Argument
11736 public ElementInitializerArgument (Expression e)
11742 sealed class AddMemberAccess : MemberAccess
11744 public AddMemberAccess (Expression expr, Location loc)
11745 : base (expr, "Add", loc)
11749 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11751 if (TypeManager.HasElementType (type))
11754 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11758 public CollectionElementInitializer (Expression argument)
11759 : base (null, new Arguments (1))
11761 base.arguments.Add (new ElementInitializerArgument (argument));
11762 this.loc = argument.Location;
11765 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11766 : base (null, new Arguments (arguments.Count))
11768 foreach (Expression e in arguments)
11769 base.arguments.Add (new ElementInitializerArgument (e));
11774 public CollectionElementInitializer (Location loc)
11775 : base (null, null)
11780 public override Expression CreateExpressionTree (ResolveContext ec)
11782 Arguments args = new Arguments (2);
11783 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11785 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11786 foreach (Argument a in arguments) {
11787 if (a.ArgType == Argument.AType.ExtensionType) {
11788 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11791 expr_initializers.Add (a.CreateExpressionTree (ec));
11794 args.Add (new Argument (new ArrayCreation (
11795 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11796 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11799 protected override void CloneTo (CloneContext clonectx, Expression t)
11801 CollectionElementInitializer target = (CollectionElementInitializer) t;
11802 if (arguments != null)
11803 target.arguments = arguments.Clone (clonectx);
11806 protected override Expression DoResolve (ResolveContext ec)
11808 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11810 return base.DoResolve (ec);
11814 class DictionaryElementInitializer : ElementInitializer
11816 readonly Arguments args;
11818 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11819 : base (null, initializer, loc)
11821 this.args = arguments;
11824 public override Expression CreateExpressionTree (ResolveContext ec)
11826 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11830 protected override bool ResolveElement (ResolveContext rc)
11832 var init = rc.CurrentInitializerVariable;
11833 var type = init.Type;
11835 if (type.IsArray) {
11836 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11840 if (type.IsPointer) {
11841 target = init.MakePointerAccess (rc, type, args);
11845 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11846 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11847 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11851 target = new IndexerExpr (indexers, type, init, args, loc).Resolve (rc);
11857 // A block of object or collection initializers
11859 public class CollectionOrObjectInitializers : ExpressionStatement
11861 IList<Expression> initializers;
11862 bool is_collection_initialization;
11864 public CollectionOrObjectInitializers (Location loc)
11865 : this (new Expression[0], loc)
11869 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11871 this.initializers = initializers;
11875 public IList<Expression> Initializers {
11877 return initializers;
11881 public bool IsEmpty {
11883 return initializers.Count == 0;
11887 public bool IsCollectionInitializer {
11889 return is_collection_initialization;
11893 protected override void CloneTo (CloneContext clonectx, Expression target)
11895 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11897 t.initializers = new List<Expression> (initializers.Count);
11898 foreach (var e in initializers)
11899 t.initializers.Add (e.Clone (clonectx));
11902 public override bool ContainsEmitWithAwait ()
11904 foreach (var e in initializers) {
11905 if (e.ContainsEmitWithAwait ())
11912 public override Expression CreateExpressionTree (ResolveContext ec)
11914 return CreateExpressionTree (ec, false);
11917 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11919 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11920 foreach (Expression e in initializers) {
11921 Expression expr = e.CreateExpressionTree (ec);
11923 expr_initializers.Add (expr);
11927 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11929 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11932 protected override Expression DoResolve (ResolveContext ec)
11934 List<string> element_names = null;
11935 for (int i = 0; i < initializers.Count; ++i) {
11936 Expression initializer = initializers [i];
11937 ElementInitializer element_initializer = initializer as ElementInitializer;
11940 if (element_initializer != null) {
11941 element_names = new List<string> (initializers.Count);
11942 if (!element_initializer.IsDictionaryInitializer)
11943 element_names.Add (element_initializer.Name);
11944 } else if (initializer is CompletingExpression) {
11945 initializer.Resolve (ec);
11946 throw new InternalErrorException ("This line should never be reached");
11948 var t = ec.CurrentInitializerVariable.Type;
11949 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11950 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11951 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11952 "object initializer because type `{1}' does not implement `{2}' interface",
11953 ec.CurrentInitializerVariable.GetSignatureForError (),
11954 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11955 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11958 is_collection_initialization = true;
11961 if (is_collection_initialization != (element_initializer == null)) {
11962 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11963 is_collection_initialization ? "collection initializer" : "object initializer");
11967 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11968 if (element_names.Contains (element_initializer.Name)) {
11969 ec.Report.Error (1912, element_initializer.Location,
11970 "An object initializer includes more than one member `{0}' initialization",
11971 element_initializer.Name);
11973 element_names.Add (element_initializer.Name);
11978 Expression e = initializer.Resolve (ec);
11979 if (e == EmptyExpressionStatement.Instance)
11980 initializers.RemoveAt (i--);
11982 initializers [i] = e;
11985 type = ec.CurrentInitializerVariable.Type;
11986 if (is_collection_initialization) {
11987 if (TypeManager.HasElementType (type)) {
11988 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11989 type.GetSignatureForError ());
11993 eclass = ExprClass.Variable;
11997 public override void Emit (EmitContext ec)
11999 EmitStatement (ec);
12002 public override void EmitStatement (EmitContext ec)
12004 foreach (ExpressionStatement e in initializers) {
12005 // TODO: need location region
12006 ec.Mark (e.Location);
12007 e.EmitStatement (ec);
12011 public override void FlowAnalysis (FlowAnalysisContext fc)
12013 foreach (var initializer in initializers) {
12014 if (initializer != null)
12015 initializer.FlowAnalysis (fc);
12021 // New expression with element/object initializers
12023 public class NewInitialize : New
12026 // This class serves as a proxy for variable initializer target instances.
12027 // A real variable is assigned later when we resolve left side of an
12030 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12032 NewInitialize new_instance;
12034 public InitializerTargetExpression (NewInitialize newInstance)
12036 this.type = newInstance.type;
12037 this.loc = newInstance.loc;
12038 this.eclass = newInstance.eclass;
12039 this.new_instance = newInstance;
12042 public override bool ContainsEmitWithAwait ()
12047 public override Expression CreateExpressionTree (ResolveContext ec)
12049 // Should not be reached
12050 throw new NotSupportedException ("ET");
12053 protected override Expression DoResolve (ResolveContext ec)
12058 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12063 public override void Emit (EmitContext ec)
12065 Expression e = (Expression) new_instance.instance;
12069 public override Expression EmitToField (EmitContext ec)
12071 return (Expression) new_instance.instance;
12074 #region IMemoryLocation Members
12076 public void AddressOf (EmitContext ec, AddressOp mode)
12078 new_instance.instance.AddressOf (ec, mode);
12084 CollectionOrObjectInitializers initializers;
12085 IMemoryLocation instance;
12086 DynamicExpressionStatement dynamic;
12088 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12089 : base (requested_type, arguments, l)
12091 this.initializers = initializers;
12094 public CollectionOrObjectInitializers Initializers {
12096 return initializers;
12100 protected override void CloneTo (CloneContext clonectx, Expression t)
12102 base.CloneTo (clonectx, t);
12104 NewInitialize target = (NewInitialize) t;
12105 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12108 public override bool ContainsEmitWithAwait ()
12110 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12113 public override Expression CreateExpressionTree (ResolveContext ec)
12115 Arguments args = new Arguments (2);
12116 args.Add (new Argument (base.CreateExpressionTree (ec)));
12117 if (!initializers.IsEmpty)
12118 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12120 return CreateExpressionFactoryCall (ec,
12121 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12125 protected override Expression DoResolve (ResolveContext ec)
12127 Expression e = base.DoResolve (ec);
12131 if (type.IsDelegate) {
12132 ec.Report.Error (1958, Initializers.Location,
12133 "Object and collection initializers cannot be used to instantiate a delegate");
12136 Expression previous = ec.CurrentInitializerVariable;
12137 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12138 initializers.Resolve (ec);
12139 ec.CurrentInitializerVariable = previous;
12141 dynamic = e as DynamicExpressionStatement;
12142 if (dynamic != null)
12148 public override void Emit (EmitContext ec)
12150 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12151 var fe = ec.GetTemporaryField (type);
12153 if (!Emit (ec, fe))
12162 public override bool Emit (EmitContext ec, IMemoryLocation target)
12165 // Expression is initialized into temporary target then moved
12166 // to real one for atomicity
12168 IMemoryLocation temp_target = target;
12170 LocalTemporary temp = null;
12171 bool by_ref = false;
12172 if (!initializers.IsEmpty) {
12173 temp_target = target as LocalTemporary;
12174 if (temp_target == null)
12175 temp_target = target as StackFieldExpr;
12177 if (temp_target == null) {
12178 var vr = target as VariableReference;
12179 if (vr != null && vr.IsRef) {
12185 if (temp_target == null)
12186 temp_target = temp = new LocalTemporary (type);
12189 bool left_on_stack;
12190 if (dynamic != null) {
12192 left_on_stack = true;
12194 left_on_stack = base.Emit (ec, temp_target);
12197 if (initializers.IsEmpty)
12198 return left_on_stack;
12200 StackFieldExpr sf = null;
12202 // Move a new instance (reference-type) to local temporary variable
12203 if (left_on_stack) {
12205 temp_target = temp = new LocalTemporary (type);
12211 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12213 throw new NotImplementedException ();
12215 sf = ec.GetTemporaryField (type);
12216 sf.EmitAssign (ec, temp, false, false);
12219 left_on_stack = false;
12223 instance = temp_target;
12225 initializers.Emit (ec);
12227 ((Expression)temp_target).Emit (ec);
12233 sf.IsAvailableForReuse = true;
12238 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12240 instance = base.EmitAddressOf (ec, Mode);
12242 if (!initializers.IsEmpty)
12243 initializers.Emit (ec);
12248 public override void FlowAnalysis (FlowAnalysisContext fc)
12250 base.FlowAnalysis (fc);
12251 initializers.FlowAnalysis (fc);
12254 public override object Accept (StructuralVisitor visitor)
12256 return visitor.Visit (this);
12260 public class NewAnonymousType : New
12262 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12264 List<AnonymousTypeParameter> parameters;
12265 readonly TypeContainer parent;
12266 AnonymousTypeClass anonymous_type;
12268 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12269 : base (null, null, loc)
12271 this.parameters = parameters;
12272 this.parent = parent;
12275 public List<AnonymousTypeParameter> Parameters {
12277 return this.parameters;
12281 protected override void CloneTo (CloneContext clonectx, Expression target)
12283 if (parameters == null)
12286 NewAnonymousType t = (NewAnonymousType) target;
12287 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12288 foreach (AnonymousTypeParameter atp in parameters)
12289 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12292 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12294 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12298 type = AnonymousTypeClass.Create (parent, parameters, loc);
12302 int errors = ec.Report.Errors;
12303 type.CreateContainer ();
12304 type.DefineContainer ();
12306 if ((ec.Report.Errors - errors) == 0) {
12307 parent.Module.AddAnonymousType (type);
12308 type.PrepareEmit ();
12314 public override Expression CreateExpressionTree (ResolveContext ec)
12316 if (parameters == null)
12317 return base.CreateExpressionTree (ec);
12319 var init = new ArrayInitializer (parameters.Count, loc);
12320 foreach (var m in anonymous_type.Members) {
12321 var p = m as Property;
12323 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12326 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12327 foreach (Argument a in arguments)
12328 ctor_args.Add (a.CreateExpressionTree (ec));
12330 Arguments args = new Arguments (3);
12331 args.Add (new Argument (new TypeOfMethod (method, loc)));
12332 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12333 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12335 return CreateExpressionFactoryCall (ec, "New", args);
12338 protected override Expression DoResolve (ResolveContext ec)
12340 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12341 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12345 if (parameters == null) {
12346 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12347 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12348 return base.DoResolve (ec);
12351 bool error = false;
12352 arguments = new Arguments (parameters.Count);
12353 var t_args = new TypeSpec [parameters.Count];
12354 for (int i = 0; i < parameters.Count; ++i) {
12355 Expression e = parameters [i].Resolve (ec);
12361 arguments.Add (new Argument (e));
12362 t_args [i] = e.Type;
12368 anonymous_type = CreateAnonymousType (ec, parameters);
12369 if (anonymous_type == null)
12372 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12373 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12374 eclass = ExprClass.Value;
12378 public override object Accept (StructuralVisitor visitor)
12380 return visitor.Visit (this);
12384 public class AnonymousTypeParameter : ShimExpression
12386 public readonly string Name;
12388 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12389 : base (initializer)
12395 public AnonymousTypeParameter (Parameter parameter)
12396 : base (new SimpleName (parameter.Name, parameter.Location))
12398 this.Name = parameter.Name;
12399 this.loc = parameter.Location;
12402 public override bool Equals (object o)
12404 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12405 return other != null && Name == other.Name;
12408 public override int GetHashCode ()
12410 return Name.GetHashCode ();
12413 protected override Expression DoResolve (ResolveContext ec)
12415 Expression e = expr.Resolve (ec);
12419 if (e.eclass == ExprClass.MethodGroup) {
12420 Error_InvalidInitializer (ec, e.ExprClassName);
12425 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12426 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12433 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12435 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12436 Name, initializer);
12440 public class CatchFilterExpression : BooleanExpression
12442 public CatchFilterExpression (Expression expr, Location loc)
12449 public class InterpolatedString : Expression
12451 readonly StringLiteral start, end;
12452 List<Expression> interpolations;
12453 Arguments arguments;
12455 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12457 this.start = start;
12459 this.interpolations = interpolations;
12460 loc = start.Location;
12463 protected override void CloneTo (CloneContext clonectx, Expression t)
12465 InterpolatedString target = (InterpolatedString) t;
12467 if (interpolations != null) {
12468 target.interpolations = new List<Expression> ();
12469 foreach (var interpolation in interpolations) {
12470 target.interpolations.Add (interpolation.Clone (clonectx));
12475 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12477 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12478 if (factory == null)
12481 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12482 var res = new Invocation (ma, arguments).Resolve (rc);
12483 if (res != null && res.Type != type)
12484 res = Convert.ExplicitConversion (rc, res, type, loc);
12489 public override bool ContainsEmitWithAwait ()
12491 if (interpolations == null)
12494 foreach (var expr in interpolations) {
12495 if (expr.ContainsEmitWithAwait ())
12502 public override Expression CreateExpressionTree (ResolveContext rc)
12504 var best = ResolveBestFormatOverload (rc);
12508 Expression instance = new NullLiteral (loc);
12509 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12510 return CreateExpressionFactoryCall (rc, "Call", args);
12513 protected override Expression DoResolve (ResolveContext rc)
12517 if (interpolations == null) {
12519 arguments = new Arguments (1);
12521 for (int i = 0; i < interpolations.Count; i += 2) {
12522 var ipi = (InterpolatedStringInsert)interpolations [i];
12526 arguments = new Arguments (interpolations.Count);
12528 var sb = new StringBuilder (start.Value);
12529 for (int i = 0; i < interpolations.Count; ++i) {
12531 sb.Append ('{').Append (i / 2);
12532 var isi = (InterpolatedStringInsert)interpolations [i];
12533 if (isi.Alignment != null) {
12535 var value = isi.ResolveAligment (rc);
12537 sb.Append (value.Value);
12540 if (isi.Format != null) {
12542 sb.Append (isi.Format);
12546 arguments.Add (new Argument (interpolations [i]));
12548 sb.Append (((StringLiteral)interpolations [i]).Value);
12552 sb.Append (end.Value);
12553 str = sb.ToString ();
12556 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12558 eclass = ExprClass.Value;
12559 type = rc.BuiltinTypes.String;
12563 public override void Emit (EmitContext ec)
12565 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12566 if (interpolations == null) {
12567 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12568 if (str != start.Value)
12569 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12576 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12580 var ca = new CallEmitter ();
12581 ca.Emit (ec, best, arguments, loc);
12584 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12586 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12587 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12588 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12592 public class InterpolatedStringInsert : CompositeExpression
12594 public InterpolatedStringInsert (Expression expr)
12599 public Expression Alignment { get; set; }
12600 public string Format { get; set; }
12602 protected override void CloneTo (CloneContext clonectx, Expression t)
12604 var target = (InterpolatedStringInsert)t;
12605 target.expr = expr.Clone (clonectx);
12606 if (Alignment != null)
12607 target.Alignment = Alignment.Clone (clonectx);
12610 protected override Expression DoResolve (ResolveContext rc)
12612 var expr = base.DoResolve (rc);
12617 // For better error reporting, assumes the built-in implementation uses object
12620 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12623 public int? ResolveAligment (ResolveContext rc)
12625 var c = Alignment.ResolveLabelConstant (rc);
12629 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12633 var value = (int) c.GetValueAsLong ();
12634 if (value > 32767 || value < -32767) {
12635 rc.Report.Warning (8094, 1, Alignment.Location,
12636 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");