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 public ParenthesizedExpression (Expression expr, Location loc)
110 protected override Expression DoResolve (ResolveContext rc)
112 Expression res = null;
114 res = expr.Resolve (rc);
116 var constant = res as Constant;
117 if (constant != null && constant.IsLiteral) {
118 if (res is NullLiteral)
121 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
127 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
129 return expr.DoResolveLValue (ec, right_side);
132 public override object Accept (StructuralVisitor visitor)
134 return visitor.Visit (this);
137 public override bool HasConditionalAccess ()
144 // Unary implements unary expressions.
146 public class Unary : Expression
148 public enum Operator : byte {
149 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
153 public readonly Operator Oper;
154 public Expression Expr;
155 ConvCast.Mode enum_conversion;
157 public Unary (Operator op, Expression expr, Location loc)
165 // This routine will attempt to simplify the unary expression when the
166 // argument is a constant.
168 Constant TryReduceConstant (ResolveContext ec, Constant constant)
172 while (e is EmptyConstantCast)
173 e = ((EmptyConstantCast) e).child;
175 if (e is SideEffectConstant) {
176 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
177 return r == null ? null : new SideEffectConstant (r, e, r.Location);
180 TypeSpec expr_type = e.Type;
183 case Operator.UnaryPlus:
184 // Unary numeric promotions
185 switch (expr_type.BuiltinType) {
186 case BuiltinTypeSpec.Type.Byte:
187 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
188 case BuiltinTypeSpec.Type.SByte:
189 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
190 case BuiltinTypeSpec.Type.Short:
191 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
192 case BuiltinTypeSpec.Type.UShort:
193 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
194 case BuiltinTypeSpec.Type.Char:
195 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
197 // Predefined operators
198 case BuiltinTypeSpec.Type.Int:
199 case BuiltinTypeSpec.Type.UInt:
200 case BuiltinTypeSpec.Type.Long:
201 case BuiltinTypeSpec.Type.ULong:
202 case BuiltinTypeSpec.Type.Float:
203 case BuiltinTypeSpec.Type.Double:
204 case BuiltinTypeSpec.Type.Decimal:
210 case Operator.UnaryNegation:
211 // Unary numeric promotions
212 switch (expr_type.BuiltinType) {
213 case BuiltinTypeSpec.Type.Byte:
214 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
215 case BuiltinTypeSpec.Type.SByte:
216 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
217 case BuiltinTypeSpec.Type.Short:
218 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
219 case BuiltinTypeSpec.Type.UShort:
220 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
221 case BuiltinTypeSpec.Type.Char:
222 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
224 // Predefined operators
225 case BuiltinTypeSpec.Type.Int:
226 int ivalue = ((IntConstant) e).Value;
227 if (ivalue == int.MinValue) {
228 if (ec.ConstantCheckState) {
229 ConstantFold.Error_CompileTimeOverflow (ec, loc);
234 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
236 case BuiltinTypeSpec.Type.Long:
237 long lvalue = ((LongConstant) e).Value;
238 if (lvalue == long.MinValue) {
239 if (ec.ConstantCheckState) {
240 ConstantFold.Error_CompileTimeOverflow (ec, loc);
245 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
247 case BuiltinTypeSpec.Type.UInt:
248 UIntLiteral uil = constant as UIntLiteral;
250 if (uil.Value == int.MaxValue + (uint) 1)
251 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
252 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
254 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
257 case BuiltinTypeSpec.Type.ULong:
258 ULongLiteral ull = constant as ULongLiteral;
259 if (ull != null && ull.Value == 9223372036854775808)
260 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
263 case BuiltinTypeSpec.Type.Float:
264 FloatLiteral fl = constant as FloatLiteral;
265 // For better error reporting
267 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
269 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
271 case BuiltinTypeSpec.Type.Double:
272 DoubleLiteral dl = constant as DoubleLiteral;
273 // For better error reporting
275 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
277 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
279 case BuiltinTypeSpec.Type.Decimal:
280 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
285 case Operator.LogicalNot:
286 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
289 bool b = (bool)e.GetValue ();
290 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
292 case Operator.OnesComplement:
293 // Unary numeric promotions
294 switch (expr_type.BuiltinType) {
295 case BuiltinTypeSpec.Type.Byte:
296 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
297 case BuiltinTypeSpec.Type.SByte:
298 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
299 case BuiltinTypeSpec.Type.Short:
300 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
301 case BuiltinTypeSpec.Type.UShort:
302 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
303 case BuiltinTypeSpec.Type.Char:
304 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
306 // Predefined operators
307 case BuiltinTypeSpec.Type.Int:
308 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
309 case BuiltinTypeSpec.Type.UInt:
310 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
311 case BuiltinTypeSpec.Type.Long:
312 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
313 case BuiltinTypeSpec.Type.ULong:
314 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
316 if (e is EnumConstant) {
317 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
320 // Numeric promotion upgraded types to int but for enum constant
321 // original underlying constant type is needed
323 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
324 int v = ((IntConstant) res).Value;
325 switch (((EnumConstant) e).Child.Type.BuiltinType) {
326 case BuiltinTypeSpec.Type.UShort:
327 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
329 case BuiltinTypeSpec.Type.Short:
330 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
332 case BuiltinTypeSpec.Type.Byte:
333 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
335 case BuiltinTypeSpec.Type.SByte:
336 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
341 res = new EnumConstant (res, expr_type);
347 throw new Exception ("Can not constant fold: " + Oper.ToString());
350 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
352 eclass = ExprClass.Value;
354 TypeSpec expr_type = expr.Type;
355 Expression best_expr;
357 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
360 // Primitive types first
362 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
363 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
364 if (best_expr == null)
367 type = best_expr.Type;
373 // E operator ~(E x);
375 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
376 return ResolveEnumOperator (ec, expr, predefined);
378 return ResolveUserType (ec, expr, predefined);
381 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
383 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
384 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
385 if (best_expr == null)
389 enum_conversion = Binary.GetEnumResultCast (underlying_type);
391 return EmptyCast.Create (this, type);
394 public override bool ContainsEmitWithAwait ()
396 return Expr.ContainsEmitWithAwait ();
399 public override Expression CreateExpressionTree (ResolveContext ec)
401 return CreateExpressionTree (ec, null);
404 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
408 case Operator.AddressOf:
409 Error_PointerInsideExpressionTree (ec);
411 case Operator.UnaryNegation:
412 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
413 method_name = "NegateChecked";
415 method_name = "Negate";
417 case Operator.OnesComplement:
418 case Operator.LogicalNot:
421 case Operator.UnaryPlus:
422 method_name = "UnaryPlus";
425 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
428 Arguments args = new Arguments (2);
429 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
431 args.Add (new Argument (user_op));
433 return CreateExpressionFactoryCall (ec, method_name, args);
436 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
438 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
441 // 7.6.1 Unary plus operator
443 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
444 types.Int, types.UInt,
445 types.Long, types.ULong,
446 types.Float, types.Double,
451 // 7.6.2 Unary minus operator
453 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
454 types.Int, types.Long,
455 types.Float, types.Double,
460 // 7.6.3 Logical negation operator
462 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
467 // 7.6.4 Bitwise complement operator
469 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
470 types.Int, types.UInt,
471 types.Long, types.ULong
474 return predefined_operators;
478 // Unary numeric promotions
480 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
482 TypeSpec expr_type = expr.Type;
483 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
484 switch (expr_type.BuiltinType) {
485 case BuiltinTypeSpec.Type.Byte:
486 case BuiltinTypeSpec.Type.SByte:
487 case BuiltinTypeSpec.Type.Short:
488 case BuiltinTypeSpec.Type.UShort:
489 case BuiltinTypeSpec.Type.Char:
490 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
494 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
495 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
500 protected override Expression DoResolve (ResolveContext ec)
502 if (Oper == Operator.AddressOf) {
503 return ResolveAddressOf (ec);
506 Expr = Expr.Resolve (ec);
510 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
511 Arguments args = new Arguments (1);
512 args.Add (new Argument (Expr));
513 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
516 if (Expr.Type.IsNullableType)
517 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
520 // Attempt to use a constant folding operation.
522 Constant cexpr = Expr as Constant;
524 cexpr = TryReduceConstant (ec, cexpr);
529 Expression expr = ResolveOperator (ec, Expr);
531 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
534 // Reduce unary operator on predefined types
536 if (expr == this && Oper == Operator.UnaryPlus)
542 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
547 public override void Emit (EmitContext ec)
549 EmitOperator (ec, type);
552 protected void EmitOperator (EmitContext ec, TypeSpec type)
555 case Operator.UnaryPlus:
559 case Operator.UnaryNegation:
560 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
561 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
562 Expr = Expr.EmitToField (ec);
565 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
566 ec.Emit (OpCodes.Conv_U8);
568 ec.Emit (OpCodes.Sub_Ovf);
571 ec.Emit (OpCodes.Neg);
576 case Operator.LogicalNot:
579 ec.Emit (OpCodes.Ceq);
582 case Operator.OnesComplement:
584 ec.Emit (OpCodes.Not);
587 case Operator.AddressOf:
588 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
592 throw new Exception ("This should not happen: Operator = "
597 // Same trick as in Binary expression
599 if (enum_conversion != 0) {
600 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
601 ConvCast.Emit (ec, enum_conversion);
606 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
608 if (Oper == Operator.LogicalNot)
609 Expr.EmitBranchable (ec, target, !on_true);
611 base.EmitBranchable (ec, target, on_true);
614 public override void EmitSideEffect (EmitContext ec)
616 Expr.EmitSideEffect (ec);
619 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
621 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
622 oper, type.GetSignatureForError ());
625 public override void FlowAnalysis (FlowAnalysisContext fc)
627 FlowAnalysis (fc, false);
630 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
632 FlowAnalysis (fc, true);
635 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
637 if (Oper == Operator.AddressOf) {
638 var vr = Expr as VariableReference;
639 if (vr != null && vr.VariableInfo != null)
640 fc.SetVariableAssigned (vr.VariableInfo);
645 if (Oper == Operator.LogicalNot && conditional) {
646 Expr.FlowAnalysisConditional (fc);
648 var temp = fc.DefiniteAssignmentOnTrue;
649 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
650 fc.DefiniteAssignmentOnFalse = temp;
652 Expr.FlowAnalysis (fc);
657 // Converts operator to System.Linq.Expressions.ExpressionType enum name
659 string GetOperatorExpressionTypeName ()
662 case Operator.OnesComplement:
663 return "OnesComplement";
664 case Operator.LogicalNot:
666 case Operator.UnaryNegation:
668 case Operator.UnaryPlus:
671 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
675 static bool IsFloat (TypeSpec t)
677 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
681 // Returns a stringified representation of the Operator
683 public static string OperName (Operator oper)
686 case Operator.UnaryPlus:
688 case Operator.UnaryNegation:
690 case Operator.LogicalNot:
692 case Operator.OnesComplement:
694 case Operator.AddressOf:
698 throw new NotImplementedException (oper.ToString ());
701 public override SLE.Expression MakeExpression (BuilderContext ctx)
703 var expr = Expr.MakeExpression (ctx);
704 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
707 case Operator.UnaryNegation:
708 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
709 case Operator.LogicalNot:
710 return SLE.Expression.Not (expr);
711 case Operator.OnesComplement:
712 return SLE.Expression.OnesComplement (expr);
714 throw new NotImplementedException (Oper.ToString ());
718 Expression ResolveAddressOf (ResolveContext ec)
721 UnsafeError (ec, loc);
723 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
724 if (Expr == null || Expr.eclass != ExprClass.Variable) {
725 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
729 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
733 IVariableReference vr = Expr as IVariableReference;
736 is_fixed = vr.IsFixed;
737 vr.SetHasAddressTaken ();
740 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
743 IFixedExpression fe = Expr as IFixedExpression;
744 is_fixed = fe != null && fe.IsFixed;
747 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
748 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
751 type = PointerContainer.MakeType (ec.Module, Expr.Type);
752 eclass = ExprClass.Value;
756 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
758 expr = DoNumericPromotion (rc, Oper, expr);
759 TypeSpec expr_type = expr.Type;
760 foreach (TypeSpec t in predefined) {
768 // Perform user-operator overload resolution
770 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
772 CSharp.Operator.OpType op_type;
774 case Operator.LogicalNot:
775 op_type = CSharp.Operator.OpType.LogicalNot; break;
776 case Operator.OnesComplement:
777 op_type = CSharp.Operator.OpType.OnesComplement; break;
778 case Operator.UnaryNegation:
779 op_type = CSharp.Operator.OpType.UnaryNegation; break;
780 case Operator.UnaryPlus:
781 op_type = CSharp.Operator.OpType.UnaryPlus; break;
783 throw new InternalErrorException (Oper.ToString ());
786 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
790 Arguments args = new Arguments (1);
791 args.Add (new Argument (expr));
793 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
794 var oper = res.ResolveOperator (ec, ref args);
799 Expr = args [0].Expr;
800 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
804 // Unary user type overload resolution
806 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
808 Expression best_expr = ResolveUserOperator (ec, expr);
809 if (best_expr != null)
812 foreach (TypeSpec t in predefined) {
813 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
814 if (oper_expr == null)
817 if (oper_expr == ErrorExpression.Instance)
821 // decimal type is predefined but has user-operators
823 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
824 oper_expr = ResolveUserType (ec, oper_expr, predefined);
826 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
828 if (oper_expr == null)
831 if (best_expr == null) {
832 best_expr = oper_expr;
836 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
838 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
839 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
841 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
848 best_expr = oper_expr;
851 if (best_expr == null)
855 // HACK: Decimal user-operator is included in standard operators
857 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
861 type = best_expr.Type;
865 protected override void CloneTo (CloneContext clonectx, Expression t)
867 Unary target = (Unary) t;
869 target.Expr = Expr.Clone (clonectx);
872 public override object Accept (StructuralVisitor visitor)
874 return visitor.Visit (this);
880 // Unary operators are turned into Indirection expressions
881 // after semantic analysis (this is so we can take the address
882 // of an indirection).
884 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
886 LocalTemporary temporary;
889 public Indirection (Expression expr, Location l)
895 public Expression Expr {
901 public bool IsFixed {
905 public override Location StartLocation {
907 return expr.StartLocation;
911 protected override void CloneTo (CloneContext clonectx, Expression t)
913 Indirection target = (Indirection) t;
914 target.expr = expr.Clone (clonectx);
917 public override bool ContainsEmitWithAwait ()
919 throw new NotImplementedException ();
922 public override Expression CreateExpressionTree (ResolveContext ec)
924 Error_PointerInsideExpressionTree (ec);
928 public override void Emit (EmitContext ec)
933 ec.EmitLoadFromPtr (Type);
936 public void Emit (EmitContext ec, bool leave_copy)
940 ec.Emit (OpCodes.Dup);
941 temporary = new LocalTemporary (expr.Type);
942 temporary.Store (ec);
946 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
948 prepared = isCompound;
953 ec.Emit (OpCodes.Dup);
957 ec.Emit (OpCodes.Dup);
958 temporary = new LocalTemporary (source.Type);
959 temporary.Store (ec);
962 ec.EmitStoreFromPtr (type);
964 if (temporary != null) {
966 temporary.Release (ec);
970 public void AddressOf (EmitContext ec, AddressOp Mode)
975 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
977 return DoResolve (ec);
980 protected override Expression DoResolve (ResolveContext ec)
982 expr = expr.Resolve (ec);
987 UnsafeError (ec, loc);
989 var pc = expr.Type as PointerContainer;
992 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
998 if (type.Kind == MemberKind.Void) {
999 Error_VoidPointerOperation (ec);
1003 eclass = ExprClass.Variable;
1007 public override object Accept (StructuralVisitor visitor)
1009 return visitor.Visit (this);
1014 /// Unary Mutator expressions (pre and post ++ and --)
1018 /// UnaryMutator implements ++ and -- expressions. It derives from
1019 /// ExpressionStatement becuase the pre/post increment/decrement
1020 /// operators can be used in a statement context.
1022 /// FIXME: Idea, we could split this up in two classes, one simpler
1023 /// for the common case, and one with the extra fields for more complex
1024 /// classes (indexers require temporary access; overloaded require method)
1027 public class UnaryMutator : ExpressionStatement
1029 class DynamicPostMutator : Expression, IAssignMethod
1031 LocalTemporary temp;
1034 public DynamicPostMutator (Expression expr)
1037 this.type = expr.Type;
1038 this.loc = expr.Location;
1041 public override Expression CreateExpressionTree (ResolveContext ec)
1043 throw new NotImplementedException ("ET");
1046 protected override Expression DoResolve (ResolveContext rc)
1048 eclass = expr.eclass;
1052 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1054 expr.DoResolveLValue (ec, right_side);
1055 return DoResolve (ec);
1058 public override void Emit (EmitContext ec)
1063 public void Emit (EmitContext ec, bool leave_copy)
1065 throw new NotImplementedException ();
1069 // Emits target assignment using unmodified source value
1071 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1074 // Allocate temporary variable to keep original value before it's modified
1076 temp = new LocalTemporary (type);
1080 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1091 public enum Mode : byte {
1098 PreDecrement = IsDecrement,
1099 PostIncrement = IsPost,
1100 PostDecrement = IsPost | IsDecrement
1104 bool is_expr, recurse;
1106 protected Expression expr;
1108 // Holds the real operation
1109 Expression operation;
1111 public UnaryMutator (Mode m, Expression e, Location loc)
1118 public Mode UnaryMutatorMode {
1124 public Expression Expr {
1130 public override Location StartLocation {
1132 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1136 public override bool ContainsEmitWithAwait ()
1138 return expr.ContainsEmitWithAwait ();
1141 public override Expression CreateExpressionTree (ResolveContext ec)
1143 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1146 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1149 // Predefined ++ and -- operators exist for the following types:
1150 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1152 return new TypeSpec[] {
1168 protected override Expression DoResolve (ResolveContext ec)
1170 expr = expr.Resolve (ec);
1172 if (expr == null || expr.Type == InternalType.ErrorType)
1175 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1177 // Handle postfix unary operators using local
1178 // temporary variable
1180 if ((mode & Mode.IsPost) != 0)
1181 expr = new DynamicPostMutator (expr);
1183 Arguments args = new Arguments (1);
1184 args.Add (new Argument (expr));
1185 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1188 if (expr.Type.IsNullableType)
1189 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1191 return DoResolveOperation (ec);
1194 protected Expression DoResolveOperation (ResolveContext ec)
1196 eclass = ExprClass.Value;
1199 if (expr is RuntimeValueExpression) {
1202 // Use itself at the top of the stack
1203 operation = new EmptyExpression (type);
1207 // The operand of the prefix/postfix increment decrement operators
1208 // should be an expression that is classified as a variable,
1209 // a property access or an indexer access
1211 // TODO: Move to parser, expr is ATypeNameExpression
1212 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1213 expr = expr.ResolveLValue (ec, expr);
1215 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1219 // Step 1: Try to find a user operator, it has priority over predefined ones
1221 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1222 var methods = MemberCache.GetUserOperator (type, user_op, false);
1224 if (methods != null) {
1225 Arguments args = new Arguments (1);
1226 args.Add (new Argument (expr));
1228 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1229 var method = res.ResolveOperator (ec, ref args);
1233 args[0].Expr = operation;
1234 operation = new UserOperatorCall (method, args, null, loc);
1235 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1240 // Step 2: Try predefined types
1243 Expression source = null;
1244 bool primitive_type;
1247 // Predefined without user conversion first for speed-up
1249 // Predefined ++ and -- operators exist for the following types:
1250 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1252 switch (type.BuiltinType) {
1253 case BuiltinTypeSpec.Type.Byte:
1254 case BuiltinTypeSpec.Type.SByte:
1255 case BuiltinTypeSpec.Type.Short:
1256 case BuiltinTypeSpec.Type.UShort:
1257 case BuiltinTypeSpec.Type.Int:
1258 case BuiltinTypeSpec.Type.UInt:
1259 case BuiltinTypeSpec.Type.Long:
1260 case BuiltinTypeSpec.Type.ULong:
1261 case BuiltinTypeSpec.Type.Char:
1262 case BuiltinTypeSpec.Type.Float:
1263 case BuiltinTypeSpec.Type.Double:
1264 case BuiltinTypeSpec.Type.Decimal:
1266 primitive_type = true;
1269 primitive_type = false;
1271 // ++/-- on pointer variables of all types except void*
1272 if (type.IsPointer) {
1273 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1274 Error_VoidPointerOperation (ec);
1280 Expression best_source = null;
1281 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1282 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1284 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1288 if (best_source == null) {
1289 best_source = source;
1293 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1298 best_source = source;
1302 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1306 source = best_source;
1309 // ++/-- on enum types
1310 if (source == null && type.IsEnum)
1313 if (source == null) {
1314 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1321 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1322 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1323 operation = new Binary (op, source, one);
1324 operation = operation.Resolve (ec);
1325 if (operation == null)
1326 throw new NotImplementedException ("should not be reached");
1328 if (operation.Type != type) {
1330 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1332 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1338 void EmitCode (EmitContext ec, bool is_expr)
1341 this.is_expr = is_expr;
1342 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1345 public override void Emit (EmitContext ec)
1348 // We use recurse to allow ourselfs to be the source
1349 // of an assignment. This little hack prevents us from
1350 // having to allocate another expression
1353 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1361 EmitCode (ec, true);
1364 protected virtual void EmitOperation (EmitContext ec)
1366 operation.Emit (ec);
1369 public override void EmitStatement (EmitContext ec)
1371 EmitCode (ec, false);
1374 public override void FlowAnalysis (FlowAnalysisContext fc)
1376 expr.FlowAnalysis (fc);
1380 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1382 string GetOperatorExpressionTypeName ()
1384 return IsDecrement ? "Decrement" : "Increment";
1388 get { return (mode & Mode.IsDecrement) != 0; }
1392 public override SLE.Expression MakeExpression (BuilderContext ctx)
1394 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1395 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1396 return SLE.Expression.Assign (target, source);
1399 public static string OperName (Mode oper)
1401 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1404 protected override void CloneTo (CloneContext clonectx, Expression t)
1406 UnaryMutator target = (UnaryMutator) t;
1408 target.expr = expr.Clone (clonectx);
1411 public override object Accept (StructuralVisitor visitor)
1413 return visitor.Visit (this);
1419 // Base class for the `is' and `as' operators
1421 public abstract class Probe : Expression
1423 public Expression ProbeType;
1424 protected Expression expr;
1425 protected TypeSpec probe_type_expr;
1427 protected Probe (Expression expr, Expression probe_type, Location l)
1429 ProbeType = probe_type;
1434 public Expression Expr {
1440 public override bool ContainsEmitWithAwait ()
1442 return expr.ContainsEmitWithAwait ();
1445 protected Expression ResolveCommon (ResolveContext rc)
1447 expr = expr.Resolve (rc);
1451 ResolveProbeType (rc);
1452 if (probe_type_expr == null)
1455 if (probe_type_expr.IsStatic) {
1456 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1457 probe_type_expr.GetSignatureForError ());
1461 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1462 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1467 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1468 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1476 protected virtual void ResolveProbeType (ResolveContext rc)
1478 probe_type_expr = ProbeType.ResolveAsType (rc);
1481 public override void EmitSideEffect (EmitContext ec)
1483 expr.EmitSideEffect (ec);
1486 public override void FlowAnalysis (FlowAnalysisContext fc)
1488 expr.FlowAnalysis (fc);
1491 public override bool HasConditionalAccess ()
1493 return expr.HasConditionalAccess ();
1496 protected abstract string OperatorName { get; }
1498 protected override void CloneTo (CloneContext clonectx, Expression t)
1500 Probe target = (Probe) t;
1502 target.expr = expr.Clone (clonectx);
1503 target.ProbeType = ProbeType.Clone (clonectx);
1509 /// Implementation of the `is' operator.
1511 public class Is : Probe
1513 Nullable.Unwrap expr_unwrap;
1514 MethodSpec number_mg;
1515 Arguments number_args;
1517 public Is (Expression expr, Expression probe_type, Location l)
1518 : base (expr, probe_type, l)
1522 protected override string OperatorName {
1523 get { return "is"; }
1526 public LocalVariable Variable { get; set; }
1528 public override Expression CreateExpressionTree (ResolveContext ec)
1530 if (Variable != null)
1531 throw new NotSupportedException ();
1533 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1534 expr.CreateExpressionTree (ec),
1535 new TypeOf (probe_type_expr, loc));
1537 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1540 Expression CreateConstantResult (ResolveContext rc, bool result)
1543 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1544 probe_type_expr.GetSignatureForError ());
1546 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1547 probe_type_expr.GetSignatureForError ());
1549 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1550 return expr.IsSideEffectFree ?
1551 ReducedExpression.Create (c, this) :
1552 new SideEffectConstant (c, this, loc);
1555 public override void Emit (EmitContext ec)
1557 if (probe_type_expr == null) {
1558 if (ProbeType is WildcardPattern) {
1559 expr.EmitSideEffect (ec);
1560 ProbeType.Emit (ec);
1562 EmitPatternMatch (ec);
1569 if (expr_unwrap == null) {
1571 ec.Emit (OpCodes.Cgt_Un);
1575 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1577 if (probe_type_expr == null) {
1578 EmitPatternMatch (ec);
1583 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1586 void EmitPatternMatch (EmitContext ec)
1588 var no_match = ec.DefineLabel ();
1589 var end = ec.DefineLabel ();
1591 if (expr_unwrap != null) {
1592 expr_unwrap.EmitCheck (ec);
1594 if (ProbeType.IsNull) {
1596 ec.Emit (OpCodes.Ceq);
1600 ec.Emit (OpCodes.Brfalse_S, no_match);
1601 expr_unwrap.Emit (ec);
1602 ProbeType.Emit (ec);
1603 ec.Emit (OpCodes.Ceq);
1604 ec.Emit (OpCodes.Br_S, end);
1605 ec.MarkLabel (no_match);
1611 if (number_args != null && number_args.Count == 3) {
1612 var ce = new CallEmitter ();
1613 ce.Emit (ec, number_mg, number_args, loc);
1617 var probe_type = ProbeType.Type;
1620 ec.Emit (OpCodes.Isinst, probe_type);
1621 ec.Emit (OpCodes.Dup);
1622 ec.Emit (OpCodes.Brfalse, no_match);
1624 bool complex_pattern = ProbeType is ComplexPatternExpression;
1625 Label prev = ec.RecursivePatternLabel;
1626 if (complex_pattern)
1627 ec.RecursivePatternLabel = ec.DefineLabel ();
1629 if (number_mg != null) {
1630 var ce = new CallEmitter ();
1631 ce.Emit (ec, number_mg, number_args, loc);
1633 if (TypeSpec.IsValueType (probe_type))
1634 ec.Emit (OpCodes.Unbox_Any, probe_type);
1636 ProbeType.Emit (ec);
1637 if (complex_pattern) {
1640 ec.Emit (OpCodes.Ceq);
1643 ec.Emit (OpCodes.Br_S, end);
1644 ec.MarkLabel (no_match);
1646 ec.Emit (OpCodes.Pop);
1648 if (complex_pattern)
1649 ec.MarkLabel (ec.RecursivePatternLabel);
1651 ec.RecursivePatternLabel = prev;
1657 void EmitLoad (EmitContext ec)
1659 Label no_value_label = new Label ();
1661 if (expr_unwrap != null) {
1662 expr_unwrap.EmitCheck (ec);
1664 if (Variable == null)
1667 ec.Emit (OpCodes.Dup);
1668 no_value_label = ec.DefineLabel ();
1669 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1670 expr_unwrap.Emit (ec);
1674 // Only to make verifier happy
1675 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1676 ec.Emit (OpCodes.Box, expr.Type);
1678 ec.Emit (OpCodes.Isinst, probe_type_expr);
1681 if (Variable != null) {
1682 bool value_on_stack;
1683 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1684 ec.Emit (OpCodes.Dup);
1685 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1686 value_on_stack = true;
1688 value_on_stack = false;
1691 Variable.CreateBuilder (ec);
1692 Variable.EmitAssign (ec);
1694 if (expr_unwrap != null) {
1695 ec.MarkLabel (no_value_label);
1696 } else if (!value_on_stack) {
1702 protected override Expression DoResolve (ResolveContext rc)
1704 if (ResolveCommon (rc) == null)
1707 type = rc.BuiltinTypes.Bool;
1708 eclass = ExprClass.Value;
1710 if (probe_type_expr == null)
1711 return ResolveMatchingExpression (rc);
1713 var res = ResolveResultExpression (rc);
1714 if (Variable != null) {
1715 if (res is Constant)
1716 throw new NotImplementedException ("constant in type pattern matching");
1718 Variable.Type = probe_type_expr;
1719 var bc = rc as BlockContext;
1721 Variable.PrepareAssignmentAnalysis (bc);
1727 public override void FlowAnalysis (FlowAnalysisContext fc)
1729 base.FlowAnalysis (fc);
1731 if (Variable != null)
1732 fc.SetVariableAssigned (Variable.VariableInfo, true);
1735 protected override void ResolveProbeType (ResolveContext rc)
1737 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1738 if (ProbeType is PatternExpression) {
1739 ProbeType.Resolve (rc);
1744 // Have to use session recording because we don't have reliable type probing
1745 // mechanism (similar issue as in attributes resolving)
1747 // TODO: This is still wrong because ResolveAsType can be destructive
1749 var type_printer = new SessionReportPrinter ();
1750 var prev_recorder = rc.Report.SetPrinter (type_printer);
1752 probe_type_expr = ProbeType.ResolveAsType (rc);
1753 type_printer.EndSession ();
1755 if (probe_type_expr != null) {
1756 type_printer.Merge (rc.Report.Printer);
1757 rc.Report.SetPrinter (prev_recorder);
1761 var vexpr = ProbeType as VarExpr;
1762 if (vexpr != null && vexpr.InferType (rc, expr)) {
1763 probe_type_expr = vexpr.Type;
1764 rc.Report.SetPrinter (prev_recorder);
1768 var expr_printer = new SessionReportPrinter ();
1769 rc.Report.SetPrinter (expr_printer);
1770 ProbeType = ProbeType.Resolve (rc);
1771 expr_printer.EndSession ();
1773 if (ProbeType != null) {
1774 expr_printer.Merge (rc.Report.Printer);
1776 type_printer.Merge (rc.Report.Printer);
1779 rc.Report.SetPrinter (prev_recorder);
1783 base.ResolveProbeType (rc);
1786 Expression ResolveMatchingExpression (ResolveContext rc)
1788 var mc = ProbeType as Constant;
1790 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1791 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1796 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1798 var c = Expr as Constant;
1800 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1805 if (Expr.Type.IsNullableType) {
1806 expr_unwrap = new Nullable.Unwrap (Expr);
1807 expr_unwrap.Resolve (rc);
1808 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1809 } else if (ProbeType.Type == Expr.Type) {
1810 // TODO: Better error handling
1811 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1812 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1813 var helper = rc.Module.CreatePatterMatchingHelper ();
1814 number_mg = helper.NumberMatcher.Spec;
1817 // There are actually 3 arguments but the first one is already on the stack
1819 number_args = new Arguments (3);
1820 if (!ProbeType.Type.IsEnum)
1821 number_args.Add (new Argument (Expr));
1823 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1824 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1830 if (ProbeType is PatternExpression) {
1831 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1832 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1838 // TODO: Better error message
1839 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1843 Expression ResolveResultExpression (ResolveContext ec)
1845 TypeSpec d = expr.Type;
1846 bool d_is_nullable = false;
1849 // If E is a method group or the null literal, or if the type of E is a reference
1850 // type or a nullable type and the value of E is null, the result is false
1852 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1853 return CreateConstantResult (ec, false);
1855 if (d.IsNullableType) {
1856 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1857 if (!ut.IsGenericParameter) {
1859 d_is_nullable = true;
1863 TypeSpec t = probe_type_expr;
1864 bool t_is_nullable = false;
1865 if (t.IsNullableType) {
1866 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1867 if (!ut.IsGenericParameter) {
1869 t_is_nullable = true;
1876 // D and T are the same value types but D can be null
1878 if (d_is_nullable && !t_is_nullable) {
1879 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1884 // The result is true if D and T are the same value types
1886 return CreateConstantResult (ec, true);
1889 var tp = d as TypeParameterSpec;
1891 return ResolveGenericParameter (ec, t, tp);
1894 // An unboxing conversion exists
1896 if (Convert.ExplicitReferenceConversionExists (d, t))
1900 // open generic type
1902 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1905 var tps = t as TypeParameterSpec;
1907 return ResolveGenericParameter (ec, d, tps);
1909 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1910 ec.Report.Warning (1981, 3, loc,
1911 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1912 OperatorName, t.GetSignatureForError ());
1915 if (TypeManager.IsGenericParameter (d))
1916 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1918 if (TypeSpec.IsValueType (d)) {
1919 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1920 if (d_is_nullable && !t_is_nullable) {
1921 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1925 return CreateConstantResult (ec, true);
1928 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1929 var c = expr as Constant;
1931 return CreateConstantResult (ec, !c.IsNull);
1934 // Do not optimize for imported type or dynamic type
1936 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1937 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1941 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1945 // Turn is check into simple null check for implicitly convertible reference types
1947 return ReducedExpression.Create (
1948 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
1952 if (Convert.ExplicitReferenceConversionExists (d, t))
1956 // open generic type
1958 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1963 return CreateConstantResult (ec, false);
1966 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1968 if (t.IsReferenceType) {
1970 return CreateConstantResult (ec, false);
1973 if (expr.Type.IsGenericParameter) {
1974 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1975 return CreateConstantResult (ec, true);
1977 expr = new BoxedCast (expr, d);
1983 public override object Accept (StructuralVisitor visitor)
1985 return visitor.Visit (this);
1989 class WildcardPattern : PatternExpression
1991 public WildcardPattern (Location loc)
1996 protected override Expression DoResolve (ResolveContext rc)
1998 eclass = ExprClass.Value;
1999 type = rc.BuiltinTypes.Object;
2003 public override void Emit (EmitContext ec)
2009 class RecursivePattern : ComplexPatternExpression
2011 MethodGroupExpr operator_mg;
2012 Arguments operator_args;
2014 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2015 : base (typeExpresion, loc)
2017 Arguments = arguments;
2020 public Arguments Arguments { get; private set; }
2022 protected override Expression DoResolve (ResolveContext rc)
2024 type = TypeExpression.ResolveAsType (rc);
2028 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2029 if (operators == null) {
2030 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2034 var ops = FindMatchingOverloads (operators);
2036 // TODO: better error message
2037 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2042 Arguments.Resolve (rc, out dynamic_args);
2044 throw new NotImplementedException ("dynamic argument");
2046 var op = FindBestOverload (rc, ops);
2048 // TODO: better error message
2049 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2053 var op_types = op.Parameters.Types;
2054 operator_args = new Arguments (op_types.Length);
2055 operator_args.Add (new Argument (new EmptyExpression (type)));
2057 for (int i = 0; i < Arguments.Count; ++i) {
2058 // TODO: Needs releasing optimization
2059 var lt = new LocalTemporary (op_types [i + 1]);
2060 operator_args.Add (new Argument (lt, Argument.AType.Out));
2062 if (comparisons == null)
2063 comparisons = new Expression[Arguments.Count];
2068 var arg = Arguments [i];
2069 var named = arg as NamedArgument;
2070 if (named != null) {
2071 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2072 expr = Arguments [arg_comp_index].Expr;
2078 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2081 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2083 eclass = ExprClass.Value;
2087 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2089 int arg_count = Arguments.Count + 1;
2090 List<MethodSpec> best = null;
2091 foreach (MethodSpec method in members) {
2092 var pm = method.Parameters;
2093 if (pm.Count != arg_count)
2096 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2098 for (int ii = 1; ii < pm.Count; ++ii) {
2099 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2109 best = new List<MethodSpec> ();
2117 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2119 for (int ii = 0; ii < Arguments.Count; ++ii) {
2120 var arg = Arguments [ii];
2121 var expr = arg.Expr;
2122 if (expr is WildcardPattern)
2125 var na = arg as NamedArgument;
2126 for (int i = 0; i < methods.Count; ++i) {
2127 var pd = methods [i].Parameters;
2131 index = pd.GetParameterIndexByName (na.Name);
2133 methods.RemoveAt (i--);
2140 var m = pd.Types [index];
2141 if (!Convert.ImplicitConversionExists (rc, expr, m))
2142 methods.RemoveAt (i--);
2146 if (methods.Count != 1)
2152 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2154 operator_mg.EmitCall (ec, operator_args, false);
2155 ec.Emit (OpCodes.Brfalse, target);
2157 base.EmitBranchable (ec, target, on_true);
2160 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2162 if (expr is WildcardPattern)
2163 return new EmptyExpression (expr.Type);
2165 var recursive = expr as RecursivePattern;
2166 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2170 if (recursive != null) {
2171 recursive.SetParentInstance (lt);
2175 // TODO: Better error handling
2176 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2179 public void SetParentInstance (Expression instance)
2181 operator_args [0] = new Argument (instance);
2185 class PropertyPattern : ComplexPatternExpression
2187 LocalTemporary instance;
2189 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2190 : base (typeExpresion, loc)
2195 public List<PropertyPatternMember> Members { get; private set; }
2197 protected override Expression DoResolve (ResolveContext rc)
2199 type = TypeExpression.ResolveAsType (rc);
2203 comparisons = new Expression[Members.Count];
2205 // TODO: optimize when source is VariableReference, it'd save dup+pop
2206 instance = new LocalTemporary (type);
2208 for (int i = 0; i < Members.Count; i++) {
2209 var lookup = Members [i];
2211 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2212 if (member == null) {
2213 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2214 if (member != null) {
2215 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2220 if (member == null) {
2221 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2225 var pe = member as PropertyExpr;
2226 if (pe == null || member is FieldExpr) {
2227 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2231 // TODO: Obsolete checks
2232 // TODO: check accessibility
2233 if (pe != null && !pe.PropertyInfo.HasGet) {
2234 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2238 var expr = lookup.Expr.Resolve (rc);
2242 var me = (MemberExpr)member;
2243 me.InstanceExpression = instance;
2245 comparisons [i] = ResolveComparison (rc, expr, me);
2248 eclass = ExprClass.Value;
2252 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2254 if (expr is WildcardPattern)
2255 return new EmptyExpression (expr.Type);
2257 return new Is (instance, expr, expr.Location).Resolve (rc);
2260 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2262 instance.Store (ec);
2264 base.EmitBranchable (ec, target, on_true);
2268 class PropertyPatternMember
2270 public PropertyPatternMember (string name, Expression expr, Location loc)
2277 public string Name { get; private set; }
2278 public Expression Expr { get; private set; }
2279 public Location Location { get; private set; }
2282 abstract class PatternExpression : Expression
2284 protected PatternExpression (Location loc)
2289 public override Expression CreateExpressionTree (ResolveContext ec)
2291 throw new NotImplementedException ();
2295 abstract class ComplexPatternExpression : PatternExpression
2297 protected Expression[] comparisons;
2299 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2302 TypeExpression = typeExpresion;
2305 public ATypeNameExpression TypeExpression { get; private set; }
2307 public override void Emit (EmitContext ec)
2309 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2312 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2314 if (comparisons != null) {
2315 foreach (var comp in comparisons) {
2316 comp.EmitBranchable (ec, target, false);
2323 /// Implementation of the `as' operator.
2325 public class As : Probe {
2327 public As (Expression expr, Expression probe_type, Location l)
2328 : base (expr, probe_type, l)
2332 protected override string OperatorName {
2333 get { return "as"; }
2336 public override Expression CreateExpressionTree (ResolveContext ec)
2338 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2339 expr.CreateExpressionTree (ec),
2340 new TypeOf (probe_type_expr, loc));
2342 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2345 public override void Emit (EmitContext ec)
2349 ec.Emit (OpCodes.Isinst, type);
2351 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2352 ec.Emit (OpCodes.Unbox_Any, type);
2355 protected override Expression DoResolve (ResolveContext ec)
2357 if (ResolveCommon (ec) == null)
2360 type = probe_type_expr;
2361 eclass = ExprClass.Value;
2362 TypeSpec etype = expr.Type;
2364 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2365 if (TypeManager.IsGenericParameter (type)) {
2366 ec.Report.Error (413, loc,
2367 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2368 probe_type_expr.GetSignatureForError ());
2370 ec.Report.Error (77, loc,
2371 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2372 type.GetSignatureForError ());
2377 if (expr.IsNull && type.IsNullableType) {
2378 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2381 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2382 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2386 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2388 e = EmptyCast.Create (e, type);
2389 return ReducedExpression.Create (e, this).Resolve (ec);
2392 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2393 if (TypeManager.IsGenericParameter (etype))
2394 expr = new BoxedCast (expr, etype);
2399 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2400 expr = new BoxedCast (expr, etype);
2404 if (etype != InternalType.ErrorType) {
2405 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2406 etype.GetSignatureForError (), type.GetSignatureForError ());
2412 public override object Accept (StructuralVisitor visitor)
2414 return visitor.Visit (this);
2419 // This represents a typecast in the source language.
2421 public class Cast : ShimExpression {
2422 Expression target_type;
2424 public Cast (Expression cast_type, Expression expr, Location loc)
2427 this.target_type = cast_type;
2431 public Expression TargetType {
2432 get { return target_type; }
2435 protected override Expression DoResolve (ResolveContext ec)
2437 expr = expr.Resolve (ec);
2441 type = target_type.ResolveAsType (ec);
2445 if (type.IsStatic) {
2446 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2450 if (type.IsPointer && !ec.IsUnsafe) {
2451 UnsafeError (ec, loc);
2454 eclass = ExprClass.Value;
2456 Constant c = expr as Constant;
2458 c = c.Reduce (ec, type);
2463 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2465 return EmptyCast.Create (res, type);
2470 protected override void CloneTo (CloneContext clonectx, Expression t)
2472 Cast target = (Cast) t;
2474 target.target_type = target_type.Clone (clonectx);
2475 target.expr = expr.Clone (clonectx);
2478 public override object Accept (StructuralVisitor visitor)
2480 return visitor.Visit (this);
2484 public class ImplicitCast : ShimExpression
2488 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2491 this.loc = expr.Location;
2493 this.arrayAccess = arrayAccess;
2496 protected override Expression DoResolve (ResolveContext ec)
2498 expr = expr.Resolve (ec);
2503 expr = ConvertExpressionToArrayIndex (ec, expr);
2505 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2511 public class DeclarationExpression : Expression, IMemoryLocation
2513 LocalVariableReference lvr;
2515 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2517 VariableType = variableType;
2518 Variable = variable;
2519 this.loc = variable.Location;
2522 public LocalVariable Variable { get; set; }
2523 public Expression Initializer { get; set; }
2524 public FullNamedExpression VariableType { get; set; }
2526 public void AddressOf (EmitContext ec, AddressOp mode)
2528 Variable.CreateBuilder (ec);
2530 if (Initializer != null) {
2531 lvr.EmitAssign (ec, Initializer, false, false);
2534 lvr.AddressOf (ec, mode);
2537 protected override void CloneTo (CloneContext clonectx, Expression t)
2539 var target = (DeclarationExpression) t;
2541 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2543 if (Initializer != null)
2544 target.Initializer = Initializer.Clone (clonectx);
2547 public override Expression CreateExpressionTree (ResolveContext rc)
2549 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2553 bool DoResolveCommon (ResolveContext rc)
2555 var var_expr = VariableType as VarExpr;
2556 if (var_expr != null) {
2557 type = InternalType.VarOutType;
2559 type = VariableType.ResolveAsType (rc);
2564 if (Initializer != null) {
2565 Initializer = Initializer.Resolve (rc);
2567 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2568 type = var_expr.Type;
2572 Variable.Type = type;
2573 lvr = new LocalVariableReference (Variable, loc);
2575 eclass = ExprClass.Variable;
2579 protected override Expression DoResolve (ResolveContext rc)
2581 if (DoResolveCommon (rc))
2587 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2589 if (lvr == null && DoResolveCommon (rc))
2590 lvr.ResolveLValue (rc, right_side);
2595 public override void Emit (EmitContext ec)
2597 throw new NotImplementedException ();
2602 // C# 2.0 Default value expression
2604 public class DefaultValueExpression : Expression
2608 public DefaultValueExpression (Expression expr, Location loc)
2614 public Expression Expr {
2620 public override bool IsSideEffectFree {
2626 public override bool ContainsEmitWithAwait ()
2631 public override Expression CreateExpressionTree (ResolveContext ec)
2633 Arguments args = new Arguments (2);
2634 args.Add (new Argument (this));
2635 args.Add (new Argument (new TypeOf (type, loc)));
2636 return CreateExpressionFactoryCall (ec, "Constant", args);
2639 protected override Expression DoResolve (ResolveContext ec)
2641 type = expr.ResolveAsType (ec);
2645 if (type.IsStatic) {
2646 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2650 return new NullLiteral (Location).ConvertImplicitly (type);
2652 if (TypeSpec.IsReferenceType (type))
2653 return new NullConstant (type, loc);
2655 Constant c = New.Constantify (type, expr.Location);
2659 eclass = ExprClass.Variable;
2663 public override void Emit (EmitContext ec)
2665 LocalTemporary temp_storage = new LocalTemporary(type);
2667 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2668 ec.Emit(OpCodes.Initobj, type);
2669 temp_storage.Emit(ec);
2670 temp_storage.Release (ec);
2674 public override SLE.Expression MakeExpression (BuilderContext ctx)
2676 return SLE.Expression.Default (type.GetMetaInfo ());
2680 protected override void CloneTo (CloneContext clonectx, Expression t)
2682 DefaultValueExpression target = (DefaultValueExpression) t;
2684 target.expr = expr.Clone (clonectx);
2687 public override object Accept (StructuralVisitor visitor)
2689 return visitor.Visit (this);
2694 /// Binary operators
2696 public class Binary : Expression, IDynamicBinder
2698 public class PredefinedOperator
2700 protected readonly TypeSpec left;
2701 protected readonly TypeSpec right;
2702 protected readonly TypeSpec left_unwrap;
2703 protected readonly TypeSpec right_unwrap;
2704 public readonly Operator OperatorsMask;
2705 public TypeSpec ReturnType;
2707 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2708 : this (ltype, rtype, op_mask, ltype)
2712 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2713 : this (type, type, op_mask, return_type)
2717 public PredefinedOperator (TypeSpec type, Operator op_mask)
2718 : this (type, type, op_mask, type)
2722 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2724 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2725 throw new InternalErrorException ("Only masked values can be used");
2727 if ((op_mask & Operator.NullableMask) != 0) {
2728 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2729 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2731 left_unwrap = ltype;
2732 right_unwrap = rtype;
2737 this.OperatorsMask = op_mask;
2738 this.ReturnType = return_type;
2741 public bool IsLifted {
2743 return (OperatorsMask & Operator.NullableMask) != 0;
2747 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2751 var left_expr = b.left;
2752 var right_expr = b.right;
2754 b.type = ReturnType;
2757 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2758 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2759 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2762 if (right_expr.IsNull) {
2763 if ((b.oper & Operator.EqualityMask) != 0) {
2764 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2765 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2766 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2767 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2768 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2770 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2771 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2773 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2774 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2776 return b.CreateLiftedValueTypeResult (rc, left);
2778 } else if (left_expr.IsNull) {
2779 if ((b.oper & Operator.EqualityMask) != 0) {
2780 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2781 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2782 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2783 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2784 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2786 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2787 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2789 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2790 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2792 return b.CreateLiftedValueTypeResult (rc, right);
2798 // A user operators does not support multiple user conversions, but decimal type
2799 // is considered to be predefined type therefore we apply predefined operators rules
2800 // and then look for decimal user-operator implementation
2802 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2803 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2804 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2806 return b.ResolveUserOperator (rc, b.left, b.right);
2809 c = right_expr as Constant;
2811 if (c.IsDefaultValue) {
2815 // (expr + 0) to expr
2816 // (expr - 0) to expr
2817 // (bool? | false) to bool?
2819 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2820 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2821 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2822 return ReducedExpression.Create (b.left, b).Resolve (rc);
2826 // Optimizes (value &/&& 0) to 0
2828 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2829 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2830 return ReducedExpression.Create (side_effect, b);
2834 // Optimizes (bool? & true) to bool?
2836 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2837 return ReducedExpression.Create (b.left, b).Resolve (rc);
2841 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2842 return ReducedExpression.Create (b.left, b).Resolve (rc);
2844 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2845 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2849 c = b.left as Constant;
2851 if (c.IsDefaultValue) {
2855 // (0 + expr) to expr
2856 // (false | bool?) to bool?
2858 if (b.oper == Operator.Addition ||
2859 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2860 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2861 return ReducedExpression.Create (b.right, b).Resolve (rc);
2865 // Optimizes (false && expr) to false
2867 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2868 // No rhs side-effects
2869 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2870 return ReducedExpression.Create (c, b);
2874 // Optimizes (0 & value) to 0
2876 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2877 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2878 return ReducedExpression.Create (side_effect, b);
2882 // Optimizes (true & bool?) to bool?
2884 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2885 return ReducedExpression.Create (b.right, b).Resolve (rc);
2889 // Optimizes (true || expr) to true
2891 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2892 // No rhs side-effects
2893 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2894 return ReducedExpression.Create (c, b);
2898 if (b.oper == Operator.Multiply && c.IsOneInteger)
2899 return ReducedExpression.Create (b.right, b).Resolve (rc);
2903 var lifted = new Nullable.LiftedBinaryOperator (b);
2905 TypeSpec ltype, rtype;
2906 if (b.left.Type.IsNullableType) {
2907 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2908 ltype = left_unwrap;
2913 if (b.right.Type.IsNullableType) {
2914 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2915 rtype = right_unwrap;
2920 lifted.Left = b.left.IsNull ?
2921 Nullable.LiftedNull.Create (ltype, b.left.Location) :
2922 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2924 lifted.Right = b.right.IsNull ?
2925 Nullable.LiftedNull.Create (rtype, b.right.Location) :
2926 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2928 return lifted.Resolve (rc);
2931 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2932 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2937 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2940 // We are dealing with primitive types only
2942 return left == ltype && ltype == rtype;
2945 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2948 if (left == lexpr.Type && right == rexpr.Type)
2951 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2952 Convert.ImplicitConversionExists (ec, rexpr, right);
2955 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2957 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2958 return best_operator;
2960 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2964 if (left != null && best_operator.left != null) {
2965 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2969 // When second argument is same as the first one, the result is same
2971 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2972 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2975 if (result == 0 || result > 2)
2978 return result == 1 ? best_operator : this;
2982 sealed class PredefinedStringOperator : PredefinedOperator
2984 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2985 : base (type, type, op_mask, retType)
2989 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2990 : base (ltype, rtype, op_mask, retType)
2994 public override Expression ConvertResult (ResolveContext ec, Binary b)
2997 // Use original expression for nullable arguments
2999 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3001 b.left = unwrap.Original;
3003 unwrap = b.right as Nullable.Unwrap;
3005 b.right = unwrap.Original;
3007 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3008 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3011 // Start a new concat expression using converted expression
3013 return StringConcat.Create (ec, b.left, b.right, b.loc);
3017 sealed class PredefinedEqualityOperator : PredefinedOperator
3019 MethodSpec equal_method, inequal_method;
3021 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3022 : base (arg, arg, Operator.EqualityMask, retType)
3026 public override Expression ConvertResult (ResolveContext ec, Binary b)
3028 b.type = ReturnType;
3030 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3031 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3033 Arguments args = new Arguments (2);
3034 args.Add (new Argument (b.left));
3035 args.Add (new Argument (b.right));
3038 if (b.oper == Operator.Equality) {
3039 if (equal_method == null) {
3040 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3041 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3042 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3043 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3045 throw new NotImplementedException (left.GetSignatureForError ());
3048 method = equal_method;
3050 if (inequal_method == null) {
3051 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3052 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3053 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3054 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3056 throw new NotImplementedException (left.GetSignatureForError ());
3059 method = inequal_method;
3062 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3066 class PredefinedPointerOperator : PredefinedOperator
3068 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3069 : base (ltype, rtype, op_mask)
3073 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3074 : base (ltype, rtype, op_mask, retType)
3078 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3079 : base (type, op_mask, return_type)
3083 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3086 if (!lexpr.Type.IsPointer)
3089 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3093 if (right == null) {
3094 if (!rexpr.Type.IsPointer)
3097 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3104 public override Expression ConvertResult (ResolveContext ec, Binary b)
3107 b.left = EmptyCast.Create (b.left, left);
3108 } else if (right != null) {
3109 b.right = EmptyCast.Create (b.right, right);
3112 TypeSpec r_type = ReturnType;
3113 Expression left_arg, right_arg;
3114 if (r_type == null) {
3117 right_arg = b.right;
3118 r_type = b.left.Type;
3122 r_type = b.right.Type;
3126 right_arg = b.right;
3129 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3134 public enum Operator {
3135 Multiply = 0 | ArithmeticMask,
3136 Division = 1 | ArithmeticMask,
3137 Modulus = 2 | ArithmeticMask,
3138 Addition = 3 | ArithmeticMask | AdditionMask,
3139 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3141 LeftShift = 5 | ShiftMask,
3142 RightShift = 6 | ShiftMask,
3144 LessThan = 7 | ComparisonMask | RelationalMask,
3145 GreaterThan = 8 | ComparisonMask | RelationalMask,
3146 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3147 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3148 Equality = 11 | ComparisonMask | EqualityMask,
3149 Inequality = 12 | ComparisonMask | EqualityMask,
3151 BitwiseAnd = 13 | BitwiseMask,
3152 ExclusiveOr = 14 | BitwiseMask,
3153 BitwiseOr = 15 | BitwiseMask,
3155 LogicalAnd = 16 | LogicalMask,
3156 LogicalOr = 17 | LogicalMask,
3161 ValuesOnlyMask = ArithmeticMask - 1,
3162 ArithmeticMask = 1 << 5,
3164 ComparisonMask = 1 << 7,
3165 EqualityMask = 1 << 8,
3166 BitwiseMask = 1 << 9,
3167 LogicalMask = 1 << 10,
3168 AdditionMask = 1 << 11,
3169 SubtractionMask = 1 << 12,
3170 RelationalMask = 1 << 13,
3172 DecomposedMask = 1 << 19,
3173 NullableMask = 1 << 20
3177 public enum State : byte
3181 UserOperatorsExcluded = 1 << 2
3184 readonly Operator oper;
3185 Expression left, right;
3187 ConvCast.Mode enum_conversion;
3189 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3190 : this (oper, left, right, State.Compound)
3194 public Binary (Operator oper, Expression left, Expression right, State state)
3195 : this (oper, left, right)
3200 public Binary (Operator oper, Expression left, Expression right)
3201 : this (oper, left, right, left.Location)
3205 public Binary (Operator oper, Expression left, Expression right, Location loc)
3215 public bool IsCompound {
3217 return (state & State.Compound) != 0;
3221 public Operator Oper {
3227 public Expression Left {
3233 public Expression Right {
3239 public override Location StartLocation {
3241 return left.StartLocation;
3248 /// Returns a stringified representation of the Operator
3250 string OperName (Operator oper)
3254 case Operator.Multiply:
3257 case Operator.Division:
3260 case Operator.Modulus:
3263 case Operator.Addition:
3266 case Operator.Subtraction:
3269 case Operator.LeftShift:
3272 case Operator.RightShift:
3275 case Operator.LessThan:
3278 case Operator.GreaterThan:
3281 case Operator.LessThanOrEqual:
3284 case Operator.GreaterThanOrEqual:
3287 case Operator.Equality:
3290 case Operator.Inequality:
3293 case Operator.BitwiseAnd:
3296 case Operator.BitwiseOr:
3299 case Operator.ExclusiveOr:
3302 case Operator.LogicalOr:
3305 case Operator.LogicalAnd:
3309 s = oper.ToString ();
3319 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3321 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3324 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3326 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3330 l = left.Type.GetSignatureForError ();
3331 r = right.Type.GetSignatureForError ();
3333 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3337 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3339 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3342 public override void FlowAnalysis (FlowAnalysisContext fc)
3345 // Optimized version when on-true/on-false data are not needed
3347 if ((oper & Operator.LogicalMask) == 0) {
3348 left.FlowAnalysis (fc);
3349 right.FlowAnalysis (fc);
3353 left.FlowAnalysisConditional (fc);
3354 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3355 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3357 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3358 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3359 right.FlowAnalysisConditional (fc);
3361 if (oper == Operator.LogicalOr)
3362 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3364 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3367 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3369 if ((oper & Operator.LogicalMask) == 0) {
3370 base.FlowAnalysisConditional (fc);
3374 left.FlowAnalysisConditional (fc);
3375 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3376 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3378 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3379 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3380 right.FlowAnalysisConditional (fc);
3382 var lc = left as Constant;
3383 if (oper == Operator.LogicalOr) {
3384 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3385 if (lc != null && lc.IsDefaultValue)
3386 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3388 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3390 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3391 if (lc != null && !lc.IsDefaultValue)
3392 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3394 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3399 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3401 string GetOperatorExpressionTypeName ()
3404 case Operator.Addition:
3405 return IsCompound ? "AddAssign" : "Add";
3406 case Operator.BitwiseAnd:
3407 return IsCompound ? "AndAssign" : "And";
3408 case Operator.BitwiseOr:
3409 return IsCompound ? "OrAssign" : "Or";
3410 case Operator.Division:
3411 return IsCompound ? "DivideAssign" : "Divide";
3412 case Operator.ExclusiveOr:
3413 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3414 case Operator.Equality:
3416 case Operator.GreaterThan:
3417 return "GreaterThan";
3418 case Operator.GreaterThanOrEqual:
3419 return "GreaterThanOrEqual";
3420 case Operator.Inequality:
3422 case Operator.LeftShift:
3423 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3424 case Operator.LessThan:
3426 case Operator.LessThanOrEqual:
3427 return "LessThanOrEqual";
3428 case Operator.LogicalAnd:
3430 case Operator.LogicalOr:
3432 case Operator.Modulus:
3433 return IsCompound ? "ModuloAssign" : "Modulo";
3434 case Operator.Multiply:
3435 return IsCompound ? "MultiplyAssign" : "Multiply";
3436 case Operator.RightShift:
3437 return IsCompound ? "RightShiftAssign" : "RightShift";
3438 case Operator.Subtraction:
3439 return IsCompound ? "SubtractAssign" : "Subtract";
3441 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3445 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3448 case Operator.Addition:
3449 return CSharp.Operator.OpType.Addition;
3450 case Operator.BitwiseAnd:
3451 case Operator.LogicalAnd:
3452 return CSharp.Operator.OpType.BitwiseAnd;
3453 case Operator.BitwiseOr:
3454 case Operator.LogicalOr:
3455 return CSharp.Operator.OpType.BitwiseOr;
3456 case Operator.Division:
3457 return CSharp.Operator.OpType.Division;
3458 case Operator.Equality:
3459 return CSharp.Operator.OpType.Equality;
3460 case Operator.ExclusiveOr:
3461 return CSharp.Operator.OpType.ExclusiveOr;
3462 case Operator.GreaterThan:
3463 return CSharp.Operator.OpType.GreaterThan;
3464 case Operator.GreaterThanOrEqual:
3465 return CSharp.Operator.OpType.GreaterThanOrEqual;
3466 case Operator.Inequality:
3467 return CSharp.Operator.OpType.Inequality;
3468 case Operator.LeftShift:
3469 return CSharp.Operator.OpType.LeftShift;
3470 case Operator.LessThan:
3471 return CSharp.Operator.OpType.LessThan;
3472 case Operator.LessThanOrEqual:
3473 return CSharp.Operator.OpType.LessThanOrEqual;
3474 case Operator.Modulus:
3475 return CSharp.Operator.OpType.Modulus;
3476 case Operator.Multiply:
3477 return CSharp.Operator.OpType.Multiply;
3478 case Operator.RightShift:
3479 return CSharp.Operator.OpType.RightShift;
3480 case Operator.Subtraction:
3481 return CSharp.Operator.OpType.Subtraction;
3483 throw new InternalErrorException (op.ToString ());
3487 public override bool ContainsEmitWithAwait ()
3489 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3492 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3497 case Operator.Multiply:
3498 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3499 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3500 opcode = OpCodes.Mul_Ovf;
3501 else if (!IsFloat (l))
3502 opcode = OpCodes.Mul_Ovf_Un;
3504 opcode = OpCodes.Mul;
3506 opcode = OpCodes.Mul;
3510 case Operator.Division:
3512 opcode = OpCodes.Div_Un;
3514 opcode = OpCodes.Div;
3517 case Operator.Modulus:
3519 opcode = OpCodes.Rem_Un;
3521 opcode = OpCodes.Rem;
3524 case Operator.Addition:
3525 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3526 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3527 opcode = OpCodes.Add_Ovf;
3528 else if (!IsFloat (l))
3529 opcode = OpCodes.Add_Ovf_Un;
3531 opcode = OpCodes.Add;
3533 opcode = OpCodes.Add;
3536 case Operator.Subtraction:
3537 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3538 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3539 opcode = OpCodes.Sub_Ovf;
3540 else if (!IsFloat (l))
3541 opcode = OpCodes.Sub_Ovf_Un;
3543 opcode = OpCodes.Sub;
3545 opcode = OpCodes.Sub;
3548 case Operator.RightShift:
3549 if (!(right is IntConstant)) {
3550 ec.EmitInt (GetShiftMask (l));
3551 ec.Emit (OpCodes.And);
3555 opcode = OpCodes.Shr_Un;
3557 opcode = OpCodes.Shr;
3560 case Operator.LeftShift:
3561 if (!(right is IntConstant)) {
3562 ec.EmitInt (GetShiftMask (l));
3563 ec.Emit (OpCodes.And);
3566 opcode = OpCodes.Shl;
3569 case Operator.Equality:
3570 opcode = OpCodes.Ceq;
3573 case Operator.Inequality:
3574 ec.Emit (OpCodes.Ceq);
3577 opcode = OpCodes.Ceq;
3580 case Operator.LessThan:
3582 opcode = OpCodes.Clt_Un;
3584 opcode = OpCodes.Clt;
3587 case Operator.GreaterThan:
3589 opcode = OpCodes.Cgt_Un;
3591 opcode = OpCodes.Cgt;
3594 case Operator.LessThanOrEqual:
3595 if (IsUnsigned (l) || IsFloat (l))
3596 ec.Emit (OpCodes.Cgt_Un);
3598 ec.Emit (OpCodes.Cgt);
3601 opcode = OpCodes.Ceq;
3604 case Operator.GreaterThanOrEqual:
3605 if (IsUnsigned (l) || IsFloat (l))
3606 ec.Emit (OpCodes.Clt_Un);
3608 ec.Emit (OpCodes.Clt);
3612 opcode = OpCodes.Ceq;
3615 case Operator.BitwiseOr:
3616 opcode = OpCodes.Or;
3619 case Operator.BitwiseAnd:
3620 opcode = OpCodes.And;
3623 case Operator.ExclusiveOr:
3624 opcode = OpCodes.Xor;
3628 throw new InternalErrorException (oper.ToString ());
3634 static int GetShiftMask (TypeSpec type)
3636 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3639 static bool IsUnsigned (TypeSpec t)
3641 switch (t.BuiltinType) {
3642 case BuiltinTypeSpec.Type.Char:
3643 case BuiltinTypeSpec.Type.UInt:
3644 case BuiltinTypeSpec.Type.ULong:
3645 case BuiltinTypeSpec.Type.UShort:
3646 case BuiltinTypeSpec.Type.Byte:
3653 static bool IsFloat (TypeSpec t)
3655 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3658 public Expression ResolveOperator (ResolveContext rc)
3660 eclass = ExprClass.Value;
3662 TypeSpec l = left.Type;
3663 TypeSpec r = right.Type;
3665 bool primitives_only = false;
3668 // Handles predefined primitive types
3670 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3671 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3672 if ((oper & Operator.ShiftMask) == 0) {
3673 if (!DoBinaryOperatorPromotion (rc))
3676 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3680 if (l.IsPointer || r.IsPointer)
3681 return ResolveOperatorPointer (rc, l, r);
3684 if ((state & State.UserOperatorsExcluded) == 0) {
3685 expr = ResolveUserOperator (rc, left, right);
3690 bool lenum = l.IsEnum;
3691 bool renum = r.IsEnum;
3692 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3696 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3697 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3702 if ((oper & Operator.BitwiseMask) != 0) {
3703 expr = EmptyCast.Create (expr, type);
3704 enum_conversion = GetEnumResultCast (type);
3706 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3707 expr = OptimizeAndOperation (expr);
3711 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3712 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3715 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3716 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3720 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3723 // We cannot break here there is also Enum + String possible match
3724 // which is not ambiguous with predefined enum operators
3727 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3728 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3732 } else if (l.IsDelegate || r.IsDelegate) {
3736 expr = ResolveOperatorDelegate (rc, l, r);
3738 // TODO: Can this be ambiguous
3746 // Equality operators are more complicated
3748 if ((oper & Operator.EqualityMask) != 0) {
3749 return ResolveEquality (rc, l, r, primitives_only);
3752 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3756 if (primitives_only)
3760 // Lifted operators have lower priority
3762 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3765 static bool IsEnumOrNullableEnum (TypeSpec type)
3767 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3771 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3772 // if 'left' is not an enumeration constant, create one from the type of 'right'
3773 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3776 case Operator.BitwiseOr:
3777 case Operator.BitwiseAnd:
3778 case Operator.ExclusiveOr:
3779 case Operator.Equality:
3780 case Operator.Inequality:
3781 case Operator.LessThan:
3782 case Operator.LessThanOrEqual:
3783 case Operator.GreaterThan:
3784 case Operator.GreaterThanOrEqual:
3785 if (left.Type.IsEnum)
3788 if (left.IsZeroInteger)
3789 return left.Reduce (ec, right.Type);
3793 case Operator.Addition:
3794 case Operator.Subtraction:
3797 case Operator.Multiply:
3798 case Operator.Division:
3799 case Operator.Modulus:
3800 case Operator.LeftShift:
3801 case Operator.RightShift:
3802 if (right.Type.IsEnum || left.Type.IsEnum)
3811 // The `|' operator used on types which were extended is dangerous
3813 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3815 OpcodeCast lcast = left as OpcodeCast;
3816 if (lcast != null) {
3817 if (IsUnsigned (lcast.UnderlyingType))
3821 OpcodeCast rcast = right as OpcodeCast;
3822 if (rcast != null) {
3823 if (IsUnsigned (rcast.UnderlyingType))
3827 if (lcast == null && rcast == null)
3830 // FIXME: consider constants
3832 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3833 ec.Report.Warning (675, 3, loc,
3834 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3835 ltype.GetSignatureForError ());
3838 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3840 return new PredefinedOperator[] {
3842 // Pointer arithmetic:
3844 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3845 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3846 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3847 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3849 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3850 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3851 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3852 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3855 // T* operator + (int y, T* x);
3856 // T* operator + (uint y, T *x);
3857 // T* operator + (long y, T *x);
3858 // T* operator + (ulong y, T *x);
3860 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3861 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3862 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3863 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3866 // long operator - (T* x, T *y)
3868 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3872 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3874 TypeSpec bool_type = types.Bool;
3877 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3878 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3879 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3880 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3881 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3882 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3883 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3885 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3886 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3887 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3888 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3889 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3890 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3891 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3893 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3894 // Remaining string operators are in lifted tables
3896 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3898 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3899 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3900 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3904 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3906 var types = module.Compiler.BuiltinTypes;
3909 // Not strictly lifted but need to be in second group otherwise expressions like
3910 // int + null would resolve to +(object, string) instead of +(int?, int?)
3912 var string_operators = new [] {
3913 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3914 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3917 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3918 if (nullable == null)
3919 return string_operators;
3921 var bool_type = types.Bool;
3923 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3924 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3925 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3926 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3927 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3928 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3929 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3930 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3933 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3934 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3935 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3936 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3937 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3938 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3939 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3941 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3942 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3943 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3944 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3945 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3946 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3947 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3949 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3951 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3952 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3953 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3955 string_operators [0],
3956 string_operators [1]
3960 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3962 TypeSpec bool_type = types.Bool;
3965 new PredefinedEqualityOperator (types.String, bool_type),
3966 new PredefinedEqualityOperator (types.Delegate, bool_type),
3967 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3968 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3969 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3970 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3971 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3972 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3973 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3974 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3978 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3980 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3982 if (nullable == null)
3983 return new PredefinedOperator [0];
3985 var types = module.Compiler.BuiltinTypes;
3986 var bool_type = types.Bool;
3987 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3988 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3989 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3990 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3991 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3992 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3993 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3994 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3997 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3998 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3999 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4000 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4001 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4002 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4003 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4004 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4009 // 7.2.6.2 Binary numeric promotions
4011 bool DoBinaryOperatorPromotion (ResolveContext rc)
4013 TypeSpec ltype = left.Type;
4014 if (ltype.IsNullableType) {
4015 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4019 // This is numeric promotion code only
4021 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4024 TypeSpec rtype = right.Type;
4025 if (rtype.IsNullableType) {
4026 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4029 var lb = ltype.BuiltinType;
4030 var rb = rtype.BuiltinType;
4034 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4035 type = rc.BuiltinTypes.Decimal;
4036 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4037 type = rc.BuiltinTypes.Double;
4038 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4039 type = rc.BuiltinTypes.Float;
4040 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4041 type = rc.BuiltinTypes.ULong;
4043 if (IsSignedType (lb)) {
4044 expr = ConvertSignedConstant (left, type);
4048 } else if (IsSignedType (rb)) {
4049 expr = ConvertSignedConstant (right, type);
4055 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4056 type = rc.BuiltinTypes.Long;
4057 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4058 type = rc.BuiltinTypes.UInt;
4060 if (IsSignedType (lb)) {
4061 expr = ConvertSignedConstant (left, type);
4063 type = rc.BuiltinTypes.Long;
4064 } else if (IsSignedType (rb)) {
4065 expr = ConvertSignedConstant (right, type);
4067 type = rc.BuiltinTypes.Long;
4070 type = rc.BuiltinTypes.Int;
4073 if (ltype != type) {
4074 expr = PromoteExpression (rc, left, type);
4081 if (rtype != type) {
4082 expr = PromoteExpression (rc, right, type);
4092 static bool IsSignedType (BuiltinTypeSpec.Type type)
4095 case BuiltinTypeSpec.Type.Int:
4096 case BuiltinTypeSpec.Type.Short:
4097 case BuiltinTypeSpec.Type.SByte:
4098 case BuiltinTypeSpec.Type.Long:
4105 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4107 var c = expr as Constant;
4111 return c.ConvertImplicitly (type);
4114 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4116 if (expr.Type.IsNullableType) {
4117 return Convert.ImplicitConversionStandard (rc, expr,
4118 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4121 var c = expr as Constant;
4123 return c.ConvertImplicitly (type);
4125 return Convert.ImplicitNumericConversion (expr, type);
4128 protected override Expression DoResolve (ResolveContext ec)
4133 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4134 left = ((ParenthesizedExpression) left).Expr;
4135 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4139 if (left.eclass == ExprClass.Type) {
4140 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4144 left = left.Resolve (ec);
4149 right = right.Resolve (ec);
4153 Constant lc = left as Constant;
4154 Constant rc = right as Constant;
4156 // The conversion rules are ignored in enum context but why
4157 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4158 lc = EnumLiftUp (ec, lc, rc);
4160 rc = EnumLiftUp (ec, rc, lc);
4163 if (rc != null && lc != null) {
4164 int prev_e = ec.Report.Errors;
4165 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4166 if (e != null || ec.Report.Errors != prev_e)
4170 // Comparison warnings
4171 if ((oper & Operator.ComparisonMask) != 0) {
4172 if (left.Equals (right)) {
4173 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4175 CheckOutOfRangeComparison (ec, lc, right.Type);
4176 CheckOutOfRangeComparison (ec, rc, left.Type);
4179 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4180 return DoResolveDynamic (ec);
4182 return DoResolveCore (ec, left, right);
4185 Expression DoResolveDynamic (ResolveContext rc)
4188 var rt = right.Type;
4189 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4190 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4191 Error_OperatorCannotBeApplied (rc, left, right);
4198 // Special handling for logical boolean operators which require rhs not to be
4199 // evaluated based on lhs value
4201 if ((oper & Operator.LogicalMask) != 0) {
4202 Expression cond_left, cond_right, expr;
4204 args = new Arguments (2);
4206 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4207 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4209 var cond_args = new Arguments (1);
4210 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4213 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4214 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4216 left = temp.CreateReferenceExpression (rc, loc);
4217 if (oper == Operator.LogicalAnd) {
4218 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4221 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4225 args.Add (new Argument (left));
4226 args.Add (new Argument (right));
4227 cond_right = new DynamicExpressionStatement (this, args, loc);
4229 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4231 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4232 rc.Report.Error (7083, left.Location,
4233 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4234 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4238 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4239 args.Add (new Argument (right));
4240 right = new DynamicExpressionStatement (this, args, loc);
4243 // bool && dynamic => (temp = left) ? temp && right : temp;
4244 // bool || dynamic => (temp = left) ? temp : temp || right;
4246 if (oper == Operator.LogicalAnd) {
4248 cond_right = temp.CreateReferenceExpression (rc, loc);
4250 cond_left = temp.CreateReferenceExpression (rc, loc);
4254 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4257 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4260 args = new Arguments (2);
4261 args.Add (new Argument (left));
4262 args.Add (new Argument (right));
4263 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4266 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4268 Expression expr = ResolveOperator (ec);
4270 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4272 if (left == null || right == null)
4273 throw new InternalErrorException ("Invalid conversion");
4275 if (oper == Operator.BitwiseOr)
4276 CheckBitwiseOrOnSignExtended (ec);
4281 public override SLE.Expression MakeExpression (BuilderContext ctx)
4283 return MakeExpression (ctx, left, right);
4286 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4288 var le = left.MakeExpression (ctx);
4289 var re = right.MakeExpression (ctx);
4290 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4293 case Operator.Addition:
4294 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4295 case Operator.BitwiseAnd:
4296 return SLE.Expression.And (le, re);
4297 case Operator.BitwiseOr:
4298 return SLE.Expression.Or (le, re);
4299 case Operator.Division:
4300 return SLE.Expression.Divide (le, re);
4301 case Operator.Equality:
4302 return SLE.Expression.Equal (le, re);
4303 case Operator.ExclusiveOr:
4304 return SLE.Expression.ExclusiveOr (le, re);
4305 case Operator.GreaterThan:
4306 return SLE.Expression.GreaterThan (le, re);
4307 case Operator.GreaterThanOrEqual:
4308 return SLE.Expression.GreaterThanOrEqual (le, re);
4309 case Operator.Inequality:
4310 return SLE.Expression.NotEqual (le, re);
4311 case Operator.LeftShift:
4312 return SLE.Expression.LeftShift (le, re);
4313 case Operator.LessThan:
4314 return SLE.Expression.LessThan (le, re);
4315 case Operator.LessThanOrEqual:
4316 return SLE.Expression.LessThanOrEqual (le, re);
4317 case Operator.LogicalAnd:
4318 return SLE.Expression.AndAlso (le, re);
4319 case Operator.LogicalOr:
4320 return SLE.Expression.OrElse (le, re);
4321 case Operator.Modulus:
4322 return SLE.Expression.Modulo (le, re);
4323 case Operator.Multiply:
4324 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4325 case Operator.RightShift:
4326 return SLE.Expression.RightShift (le, re);
4327 case Operator.Subtraction:
4328 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4330 throw new NotImplementedException (oper.ToString ());
4335 // D operator + (D x, D y)
4336 // D operator - (D x, D y)
4338 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4340 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4342 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4343 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4348 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4349 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4359 MethodSpec method = null;
4360 Arguments args = new Arguments (2);
4361 args.Add (new Argument (left));
4362 args.Add (new Argument (right));
4364 if (oper == Operator.Addition) {
4365 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4366 } else if (oper == Operator.Subtraction) {
4367 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4371 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4373 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4374 return new ClassCast (expr, l);
4378 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4380 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4383 // bool operator == (E x, E y);
4384 // bool operator != (E x, E y);
4385 // bool operator < (E x, E y);
4386 // bool operator > (E x, E y);
4387 // bool operator <= (E x, E y);
4388 // bool operator >= (E x, E y);
4390 // E operator & (E x, E y);
4391 // E operator | (E x, E y);
4392 // E operator ^ (E x, E y);
4395 if ((oper & Operator.ComparisonMask) != 0) {
4396 type = rc.BuiltinTypes.Bool;
4402 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4408 if (ltype == rtype) {
4412 var lifted = new Nullable.LiftedBinaryOperator (this);
4414 lifted.Right = right;
4415 return lifted.Resolve (rc);
4418 if (renum && !ltype.IsNullableType) {
4419 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4424 } else if (lenum && !rtype.IsNullableType) {
4425 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4433 // Now try lifted version of predefined operator
4435 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4436 if (nullable_type != null) {
4437 if (renum && !ltype.IsNullableType) {
4438 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4440 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4443 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4446 if ((oper & Operator.BitwiseMask) != 0)
4450 if ((oper & Operator.BitwiseMask) != 0)
4451 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4453 return CreateLiftedValueTypeResult (rc, rtype);
4457 var lifted = new Nullable.LiftedBinaryOperator (this);
4459 lifted.Right = right;
4460 return lifted.Resolve (rc);
4462 } else if (lenum && !rtype.IsNullableType) {
4463 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4465 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4468 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4471 if ((oper & Operator.BitwiseMask) != 0)
4475 if ((oper & Operator.BitwiseMask) != 0)
4476 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4478 return CreateLiftedValueTypeResult (rc, ltype);
4482 var lifted = new Nullable.LiftedBinaryOperator (this);
4484 lifted.Right = expr;
4485 return lifted.Resolve (rc);
4487 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4488 Nullable.Unwrap unwrap = null;
4489 if (left.IsNull || right.IsNull) {
4490 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4491 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4493 if ((oper & Operator.RelationalMask) != 0)
4494 return CreateLiftedValueTypeResult (rc, rtype);
4496 if ((oper & Operator.BitwiseMask) != 0)
4497 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4500 return CreateLiftedValueTypeResult (rc, left.Type);
4502 // Equality operators are valid between E? and null
4504 unwrap = new Nullable.Unwrap (right);
4506 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4510 if ((oper & Operator.BitwiseMask) != 0)
4515 var lifted = new Nullable.LiftedBinaryOperator (this);
4517 lifted.Right = right;
4518 lifted.UnwrapRight = unwrap;
4519 return lifted.Resolve (rc);
4521 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4522 Nullable.Unwrap unwrap = null;
4523 if (right.IsNull || left.IsNull) {
4524 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4525 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4527 if ((oper & Operator.RelationalMask) != 0)
4528 return CreateLiftedValueTypeResult (rc, ltype);
4530 if ((oper & Operator.BitwiseMask) != 0)
4531 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4534 return CreateLiftedValueTypeResult (rc, right.Type);
4536 // Equality operators are valid between E? and null
4538 unwrap = new Nullable.Unwrap (left);
4540 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4544 if ((oper & Operator.BitwiseMask) != 0)
4549 var lifted = new Nullable.LiftedBinaryOperator (this);
4551 lifted.UnwrapLeft = unwrap;
4552 lifted.Right = expr;
4553 return lifted.Resolve (rc);
4561 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4563 TypeSpec underlying_type;
4564 if (expr.Type.IsNullableType) {
4565 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4567 underlying_type = EnumSpec.GetUnderlyingType (nt);
4569 underlying_type = nt;
4570 } else if (expr.Type.IsEnum) {
4571 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4573 underlying_type = expr.Type;
4576 switch (underlying_type.BuiltinType) {
4577 case BuiltinTypeSpec.Type.SByte:
4578 case BuiltinTypeSpec.Type.Byte:
4579 case BuiltinTypeSpec.Type.Short:
4580 case BuiltinTypeSpec.Type.UShort:
4581 underlying_type = rc.BuiltinTypes.Int;
4585 if (expr.Type.IsNullableType || liftType)
4586 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4588 if (expr.Type == underlying_type)
4591 return EmptyCast.Create (expr, underlying_type);
4594 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4597 // U operator - (E e, E f)
4598 // E operator - (E e, U x) // Internal decomposition operator
4599 // E operator - (U x, E e) // Internal decomposition operator
4601 // E operator + (E e, U x)
4602 // E operator + (U x, E e)
4611 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4617 if (!enum_type.IsNullableType) {
4618 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4620 if (oper == Operator.Subtraction)
4621 expr = ConvertEnumSubtractionResult (rc, expr);
4623 expr = ConvertEnumAdditionalResult (expr, enum_type);
4625 enum_conversion = GetEnumResultCast (expr.Type);
4630 var nullable = rc.Module.PredefinedTypes.Nullable;
4633 // Don't try nullable version when nullable type is undefined
4635 if (!nullable.IsDefined)
4638 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4641 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4643 if (oper == Operator.Subtraction)
4644 expr = ConvertEnumSubtractionResult (rc, expr);
4646 expr = ConvertEnumAdditionalResult (expr, enum_type);
4648 enum_conversion = GetEnumResultCast (expr.Type);
4654 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4656 return EmptyCast.Create (expr, enumType);
4659 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4662 // Enumeration subtraction has different result type based on
4665 TypeSpec result_type;
4666 if (left.Type == right.Type) {
4667 var c = right as EnumConstant;
4668 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4670 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4671 // E which is not what expressions E - 1 or 0 - E return
4673 result_type = left.Type;
4675 result_type = left.Type.IsNullableType ?
4676 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4677 EnumSpec.GetUnderlyingType (left.Type);
4680 if (IsEnumOrNullableEnum (left.Type)) {
4681 result_type = left.Type;
4683 result_type = right.Type;
4686 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4687 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4690 return EmptyCast.Create (expr, result_type);
4693 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4695 if (type.IsNullableType)
4696 type = Nullable.NullableInfo.GetUnderlyingType (type);
4699 type = EnumSpec.GetUnderlyingType (type);
4701 switch (type.BuiltinType) {
4702 case BuiltinTypeSpec.Type.SByte:
4703 return ConvCast.Mode.I4_I1;
4704 case BuiltinTypeSpec.Type.Byte:
4705 return ConvCast.Mode.I4_U1;
4706 case BuiltinTypeSpec.Type.Short:
4707 return ConvCast.Mode.I4_I2;
4708 case BuiltinTypeSpec.Type.UShort:
4709 return ConvCast.Mode.I4_U2;
4716 // Equality operators rules
4718 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4721 type = ec.BuiltinTypes.Bool;
4722 bool no_arg_conv = false;
4724 if (!primitives_only) {
4727 // a, Both operands are reference-type values or the value null
4728 // b, One operand is a value of type T where T is a type-parameter and
4729 // the other operand is the value null. Furthermore T does not have the
4730 // value type constraint
4732 // LAMESPEC: Very confusing details in the specification, basically any
4733 // reference like type-parameter is allowed
4735 var tparam_l = l as TypeParameterSpec;
4736 var tparam_r = r as TypeParameterSpec;
4737 if (tparam_l != null) {
4738 if (right is NullLiteral) {
4739 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4742 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4746 if (!tparam_l.IsReferenceType)
4749 l = tparam_l.GetEffectiveBase ();
4750 left = new BoxedCast (left, l);
4751 } else if (left is NullLiteral && tparam_r == null) {
4752 if (TypeSpec.IsReferenceType (r))
4755 if (r.Kind == MemberKind.InternalCompilerType)
4759 if (tparam_r != null) {
4760 if (left is NullLiteral) {
4761 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4764 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4768 if (!tparam_r.IsReferenceType)
4771 r = tparam_r.GetEffectiveBase ();
4772 right = new BoxedCast (right, r);
4773 } else if (right is NullLiteral) {
4774 if (TypeSpec.IsReferenceType (l))
4777 if (l.Kind == MemberKind.InternalCompilerType)
4782 // LAMESPEC: method groups can be compared when they convert to other side delegate
4785 if (right.eclass == ExprClass.MethodGroup) {
4786 result = Convert.ImplicitConversion (ec, right, l, loc);
4792 } else if (r.IsDelegate && l != r) {
4795 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4796 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4803 no_arg_conv = l == r && !l.IsStruct;
4808 // bool operator != (string a, string b)
4809 // bool operator == (string a, string b)
4811 // bool operator != (Delegate a, Delegate b)
4812 // bool operator == (Delegate a, Delegate b)
4814 // bool operator != (bool a, bool b)
4815 // bool operator == (bool a, bool b)
4817 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4818 // they implement an implicit conversion to any of types above. This does
4819 // not apply when both operands are of same reference type
4821 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4822 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4827 // Now try lifted version of predefined operators
4829 if (no_arg_conv && !l.IsNullableType) {
4831 // Optimizes cases which won't match
4834 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4840 // The == and != operators permit one operand to be a value of a nullable
4841 // type and the other to be the null literal, even if no predefined or user-defined
4842 // operator (in unlifted or lifted form) exists for the operation.
4844 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4845 var lifted = new Nullable.LiftedBinaryOperator (this);
4847 lifted.Right = right;
4848 return lifted.Resolve (ec);
4853 // bool operator != (object a, object b)
4854 // bool operator == (object a, object b)
4856 // An explicit reference conversion exists from the
4857 // type of either operand to the type of the other operand.
4860 // Optimize common path
4862 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4865 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4866 !Convert.ExplicitReferenceConversionExists (r, l))
4869 // Reject allowed explicit conversions like int->object
4870 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4873 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4874 ec.Report.Warning (253, 2, loc,
4875 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4876 l.GetSignatureForError ());
4878 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4879 ec.Report.Warning (252, 2, loc,
4880 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4881 r.GetSignatureForError ());
4887 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4890 // bool operator == (void* x, void* y);
4891 // bool operator != (void* x, void* y);
4892 // bool operator < (void* x, void* y);
4893 // bool operator > (void* x, void* y);
4894 // bool operator <= (void* x, void* y);
4895 // bool operator >= (void* x, void* y);
4897 if ((oper & Operator.ComparisonMask) != 0) {
4900 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4907 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4913 type = ec.BuiltinTypes.Bool;
4917 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4921 // Build-in operators method overloading
4923 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4925 PredefinedOperator best_operator = null;
4926 TypeSpec l = left.Type;
4927 TypeSpec r = right.Type;
4928 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4930 foreach (PredefinedOperator po in operators) {
4931 if ((po.OperatorsMask & oper_mask) == 0)
4934 if (primitives_only) {
4935 if (!po.IsPrimitiveApplicable (l, r))
4938 if (!po.IsApplicable (ec, left, right))
4942 if (best_operator == null) {
4944 if (primitives_only)
4950 best_operator = po.ResolveBetterOperator (ec, best_operator);
4952 if (best_operator == null) {
4953 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4954 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4961 if (best_operator == null)
4964 return best_operator.ConvertResult (ec, this);
4968 // Optimize & constant expressions with 0 value
4970 Expression OptimizeAndOperation (Expression expr)
4972 Constant rc = right as Constant;
4973 Constant lc = left as Constant;
4974 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4976 // The result is a constant with side-effect
4978 Constant side_effect = rc == null ?
4979 new SideEffectConstant (lc, right, loc) :
4980 new SideEffectConstant (rc, left, loc);
4982 return ReducedExpression.Create (side_effect, expr);
4989 // Value types can be compared with the null literal because of the lifting
4990 // language rules. However the result is always true or false.
4992 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4994 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4995 type = rc.BuiltinTypes.Bool;
4999 // FIXME: Handle side effect constants
5000 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5002 if ((Oper & Operator.EqualityMask) != 0) {
5003 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5004 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5006 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5007 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5014 // Performs user-operator overloading
5016 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5018 Expression oper_expr;
5020 var op = ConvertBinaryToUserOperator (oper);
5022 if (l.IsNullableType)
5023 l = Nullable.NullableInfo.GetUnderlyingType (l);
5025 if (r.IsNullableType)
5026 r = Nullable.NullableInfo.GetUnderlyingType (r);
5028 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5029 IList<MemberSpec> right_operators = null;
5032 right_operators = MemberCache.GetUserOperator (r, op, false);
5033 if (right_operators == null && left_operators == null)
5035 } else if (left_operators == null) {
5039 Arguments args = new Arguments (2);
5040 Argument larg = new Argument (left);
5042 Argument rarg = new Argument (right);
5046 // User-defined operator implementations always take precedence
5047 // over predefined operator implementations
5049 if (left_operators != null && right_operators != null) {
5050 left_operators = CombineUserOperators (left_operators, right_operators);
5051 } else if (right_operators != null) {
5052 left_operators = right_operators;
5055 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5056 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5058 var res = new OverloadResolver (left_operators, restr, loc);
5060 var oper_method = res.ResolveOperator (rc, ref args);
5061 if (oper_method == null) {
5063 // Logical && and || cannot be lifted
5065 if ((oper & Operator.LogicalMask) != 0)
5069 // Apply lifted user operators only for liftable types. Implicit conversion
5070 // to nullable types is not allowed
5072 if (!IsLiftedOperatorApplicable ())
5075 // TODO: Cache the result in module container
5076 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5077 if (lifted_methods == null)
5080 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5082 oper_method = res.ResolveOperator (rc, ref args);
5083 if (oper_method == null)
5086 MethodSpec best_original = null;
5087 foreach (MethodSpec ms in left_operators) {
5088 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5094 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5096 // Expression trees use lifted notation in this case
5098 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5099 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5102 var ptypes = best_original.Parameters.Types;
5104 if (left.IsNull || right.IsNull) {
5106 // The lifted operator produces a null value if one or both operands are null
5108 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5109 type = oper_method.ReturnType;
5110 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5114 // The lifted operator produces the value false if one or both operands are null for
5115 // relational operators.
5117 if ((oper & Operator.RelationalMask) != 0) {
5119 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5120 // because return type is actually bool
5122 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5125 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5126 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5130 type = oper_method.ReturnType;
5131 var lifted = new Nullable.LiftedBinaryOperator (this);
5132 lifted.UserOperator = best_original;
5134 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5135 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5138 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5139 lifted.UnwrapRight = new Nullable.Unwrap (right);
5142 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5143 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5145 return lifted.Resolve (rc);
5148 if ((oper & Operator.LogicalMask) != 0) {
5149 // TODO: CreateExpressionTree is allocated every time
5150 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5151 oper == Operator.LogicalAnd, loc).Resolve (rc);
5153 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5156 this.left = larg.Expr;
5157 this.right = rarg.Expr;
5162 bool IsLiftedOperatorApplicable ()
5164 if (left.Type.IsNullableType) {
5165 if ((oper & Operator.EqualityMask) != 0)
5166 return !right.IsNull;
5171 if (right.Type.IsNullableType) {
5172 if ((oper & Operator.EqualityMask) != 0)
5173 return !left.IsNull;
5178 if (TypeSpec.IsValueType (left.Type))
5179 return right.IsNull;
5181 if (TypeSpec.IsValueType (right.Type))
5187 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5189 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5190 if (nullable_type == null)
5194 // Lifted operators permit predefined and user-defined operators that operate
5195 // on non-nullable value types to also be used with nullable forms of those types.
5196 // Lifted operators are constructed from predefined and user-defined operators
5197 // that meet certain requirements
5199 List<MemberSpec> lifted = null;
5200 foreach (MethodSpec oper in operators) {
5202 if ((Oper & Operator.ComparisonMask) != 0) {
5204 // Result type must be of type bool for lifted comparison operators
5206 rt = oper.ReturnType;
5207 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5210 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5216 var ptypes = oper.Parameters.Types;
5217 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5221 // LAMESPEC: I am not sure why but for equality operators to be lifted
5222 // both types have to match
5224 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5228 lifted = new List<MemberSpec> ();
5231 // The lifted form is constructed by adding a single ? modifier to each operand and
5232 // result type except for comparison operators where return type is bool
5235 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5237 var parameters = ParametersCompiled.CreateFullyResolved (
5238 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5239 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5241 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5242 rt, parameters, oper.Modifiers);
5244 lifted.Add (lifted_op);
5251 // Merge two sets of user operators into one, they are mostly distinguish
5252 // except when they share base type and it contains an operator
5254 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5256 var combined = new List<MemberSpec> (left.Count + right.Count);
5257 combined.AddRange (left);
5258 foreach (var r in right) {
5260 foreach (var l in left) {
5261 if (l.DeclaringType == r.DeclaringType) {
5274 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5276 if (c is IntegralConstant || c is CharConstant) {
5278 c.ConvertExplicitly (true, type);
5279 } catch (OverflowException) {
5280 ec.Report.Warning (652, 2, loc,
5281 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5282 type.GetSignatureForError ());
5288 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5289 /// context of a conditional bool expression. This function will return
5290 /// false if it is was possible to use EmitBranchable, or true if it was.
5292 /// The expression's code is generated, and we will generate a branch to `target'
5293 /// if the resulting expression value is equal to isTrue
5295 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5297 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5298 left = left.EmitToField (ec);
5300 if ((oper & Operator.LogicalMask) == 0) {
5301 right = right.EmitToField (ec);
5306 // This is more complicated than it looks, but its just to avoid
5307 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5308 // but on top of that we want for == and != to use a special path
5309 // if we are comparing against null
5311 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5312 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5315 // put the constant on the rhs, for simplicity
5317 if (left is Constant) {
5318 Expression swap = right;
5324 // brtrue/brfalse works with native int only
5326 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5327 left.EmitBranchable (ec, target, my_on_true);
5330 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5331 // right is a boolean, and it's not 'false' => it is 'true'
5332 left.EmitBranchable (ec, target, !my_on_true);
5336 } else if (oper == Operator.LogicalAnd) {
5339 Label tests_end = ec.DefineLabel ();
5341 left.EmitBranchable (ec, tests_end, false);
5342 right.EmitBranchable (ec, target, true);
5343 ec.MarkLabel (tests_end);
5346 // This optimizes code like this
5347 // if (true && i > 4)
5349 if (!(left is Constant))
5350 left.EmitBranchable (ec, target, false);
5352 if (!(right is Constant))
5353 right.EmitBranchable (ec, target, false);
5358 } else if (oper == Operator.LogicalOr){
5360 left.EmitBranchable (ec, target, true);
5361 right.EmitBranchable (ec, target, true);
5364 Label tests_end = ec.DefineLabel ();
5365 left.EmitBranchable (ec, tests_end, true);
5366 right.EmitBranchable (ec, target, false);
5367 ec.MarkLabel (tests_end);
5372 } else if ((oper & Operator.ComparisonMask) == 0) {
5373 base.EmitBranchable (ec, target, on_true);
5380 TypeSpec t = left.Type;
5381 bool is_float = IsFloat (t);
5382 bool is_unsigned = is_float || IsUnsigned (t);
5385 case Operator.Equality:
5387 ec.Emit (OpCodes.Beq, target);
5389 ec.Emit (OpCodes.Bne_Un, target);
5392 case Operator.Inequality:
5394 ec.Emit (OpCodes.Bne_Un, target);
5396 ec.Emit (OpCodes.Beq, target);
5399 case Operator.LessThan:
5401 if (is_unsigned && !is_float)
5402 ec.Emit (OpCodes.Blt_Un, target);
5404 ec.Emit (OpCodes.Blt, target);
5407 ec.Emit (OpCodes.Bge_Un, target);
5409 ec.Emit (OpCodes.Bge, target);
5412 case Operator.GreaterThan:
5414 if (is_unsigned && !is_float)
5415 ec.Emit (OpCodes.Bgt_Un, target);
5417 ec.Emit (OpCodes.Bgt, target);
5420 ec.Emit (OpCodes.Ble_Un, target);
5422 ec.Emit (OpCodes.Ble, target);
5425 case Operator.LessThanOrEqual:
5427 if (is_unsigned && !is_float)
5428 ec.Emit (OpCodes.Ble_Un, target);
5430 ec.Emit (OpCodes.Ble, target);
5433 ec.Emit (OpCodes.Bgt_Un, target);
5435 ec.Emit (OpCodes.Bgt, target);
5439 case Operator.GreaterThanOrEqual:
5441 if (is_unsigned && !is_float)
5442 ec.Emit (OpCodes.Bge_Un, target);
5444 ec.Emit (OpCodes.Bge, target);
5447 ec.Emit (OpCodes.Blt_Un, target);
5449 ec.Emit (OpCodes.Blt, target);
5452 throw new InternalErrorException (oper.ToString ());
5456 public override void Emit (EmitContext ec)
5458 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5459 left = left.EmitToField (ec);
5461 if ((oper & Operator.LogicalMask) == 0) {
5462 right = right.EmitToField (ec);
5467 // Handle short-circuit operators differently
5470 if ((oper & Operator.LogicalMask) != 0) {
5471 Label load_result = ec.DefineLabel ();
5472 Label end = ec.DefineLabel ();
5474 bool is_or = oper == Operator.LogicalOr;
5475 left.EmitBranchable (ec, load_result, is_or);
5477 ec.Emit (OpCodes.Br_S, end);
5479 ec.MarkLabel (load_result);
5480 ec.EmitInt (is_or ? 1 : 0);
5486 // Optimize zero-based operations which cannot be optimized at expression level
5488 if (oper == Operator.Subtraction) {
5489 var lc = left as IntegralConstant;
5490 if (lc != null && lc.IsDefaultValue) {
5492 ec.Emit (OpCodes.Neg);
5497 EmitOperator (ec, left, right);
5500 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5505 EmitOperatorOpcode (ec, oper, left.Type, right);
5508 // Emit result enumerable conversion this way because it's quite complicated get it
5509 // to resolved tree because expression tree cannot see it.
5511 if (enum_conversion != 0)
5512 ConvCast.Emit (ec, enum_conversion);
5515 public override void EmitSideEffect (EmitContext ec)
5517 if ((oper & Operator.LogicalMask) != 0 ||
5518 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5519 base.EmitSideEffect (ec);
5521 left.EmitSideEffect (ec);
5522 right.EmitSideEffect (ec);
5526 public override Expression EmitToField (EmitContext ec)
5528 if ((oper & Operator.LogicalMask) == 0) {
5529 var await_expr = left as Await;
5530 if (await_expr != null && right.IsSideEffectFree) {
5531 await_expr.Statement.EmitPrologue (ec);
5532 left = await_expr.Statement.GetResultExpression (ec);
5536 await_expr = right as Await;
5537 if (await_expr != null && left.IsSideEffectFree) {
5538 await_expr.Statement.EmitPrologue (ec);
5539 right = await_expr.Statement.GetResultExpression (ec);
5544 return base.EmitToField (ec);
5547 protected override void CloneTo (CloneContext clonectx, Expression t)
5549 Binary target = (Binary) t;
5551 target.left = left.Clone (clonectx);
5552 target.right = right.Clone (clonectx);
5555 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5557 Arguments binder_args = new Arguments (4);
5559 MemberAccess sle = new MemberAccess (new MemberAccess (
5560 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5562 CSharpBinderFlags flags = 0;
5563 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5564 flags = CSharpBinderFlags.CheckedContext;
5566 if ((oper & Operator.LogicalMask) != 0)
5567 flags |= CSharpBinderFlags.BinaryOperationLogical;
5569 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5570 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5571 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5572 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5574 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5577 public override Expression CreateExpressionTree (ResolveContext ec)
5579 return CreateExpressionTree (ec, null);
5582 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5585 bool lift_arg = false;
5588 case Operator.Addition:
5589 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5590 method_name = "AddChecked";
5592 method_name = "Add";
5594 case Operator.BitwiseAnd:
5595 method_name = "And";
5597 case Operator.BitwiseOr:
5600 case Operator.Division:
5601 method_name = "Divide";
5603 case Operator.Equality:
5604 method_name = "Equal";
5607 case Operator.ExclusiveOr:
5608 method_name = "ExclusiveOr";
5610 case Operator.GreaterThan:
5611 method_name = "GreaterThan";
5614 case Operator.GreaterThanOrEqual:
5615 method_name = "GreaterThanOrEqual";
5618 case Operator.Inequality:
5619 method_name = "NotEqual";
5622 case Operator.LeftShift:
5623 method_name = "LeftShift";
5625 case Operator.LessThan:
5626 method_name = "LessThan";
5629 case Operator.LessThanOrEqual:
5630 method_name = "LessThanOrEqual";
5633 case Operator.LogicalAnd:
5634 method_name = "AndAlso";
5636 case Operator.LogicalOr:
5637 method_name = "OrElse";
5639 case Operator.Modulus:
5640 method_name = "Modulo";
5642 case Operator.Multiply:
5643 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5644 method_name = "MultiplyChecked";
5646 method_name = "Multiply";
5648 case Operator.RightShift:
5649 method_name = "RightShift";
5651 case Operator.Subtraction:
5652 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5653 method_name = "SubtractChecked";
5655 method_name = "Subtract";
5659 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5662 Arguments args = new Arguments (2);
5663 args.Add (new Argument (left.CreateExpressionTree (ec)));
5664 args.Add (new Argument (right.CreateExpressionTree (ec)));
5665 if (method != null) {
5667 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5669 args.Add (new Argument (method));
5672 return CreateExpressionFactoryCall (ec, method_name, args);
5675 public override object Accept (StructuralVisitor visitor)
5677 return visitor.Visit (this);
5683 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5684 // b, c, d... may be strings or objects.
5686 public class StringConcat : Expression
5688 Arguments arguments;
5690 StringConcat (Location loc)
5693 arguments = new Arguments (2);
5696 public override bool ContainsEmitWithAwait ()
5698 return arguments.ContainsEmitWithAwait ();
5701 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5703 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5704 throw new ArgumentException ();
5706 var s = new StringConcat (loc);
5707 s.type = rc.BuiltinTypes.String;
5708 s.eclass = ExprClass.Value;
5710 s.Append (rc, left);
5711 s.Append (rc, right);
5715 public override Expression CreateExpressionTree (ResolveContext ec)
5717 Argument arg = arguments [0];
5718 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5722 // Creates nested calls tree from an array of arguments used for IL emit
5724 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5726 Arguments concat_args = new Arguments (2);
5727 Arguments add_args = new Arguments (3);
5729 concat_args.Add (left);
5730 add_args.Add (new Argument (left_etree));
5732 concat_args.Add (arguments [pos]);
5733 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5735 var methods = GetConcatMethodCandidates ();
5736 if (methods == null)
5739 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5740 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5744 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5746 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5747 if (++pos == arguments.Count)
5750 left = new Argument (new EmptyExpression (method.ReturnType));
5751 return CreateExpressionAddCall (ec, left, expr, pos);
5754 protected override Expression DoResolve (ResolveContext ec)
5759 void Append (ResolveContext rc, Expression operand)
5764 StringConstant sc = operand as StringConstant;
5766 if (arguments.Count != 0) {
5767 Argument last_argument = arguments [arguments.Count - 1];
5768 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5769 if (last_expr_constant != null) {
5770 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5776 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5778 StringConcat concat_oper = operand as StringConcat;
5779 if (concat_oper != null) {
5780 arguments.AddRange (concat_oper.arguments);
5785 arguments.Add (new Argument (operand));
5788 IList<MemberSpec> GetConcatMethodCandidates ()
5790 return MemberCache.FindMembers (type, "Concat", true);
5793 public override void Emit (EmitContext ec)
5795 // Optimize by removing any extra null arguments, they are no-op
5796 for (int i = 0; i < arguments.Count; ++i) {
5797 if (arguments[i].Expr is NullConstant)
5798 arguments.RemoveAt (i--);
5801 var members = GetConcatMethodCandidates ();
5802 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5803 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5804 if (method != null) {
5805 var call = new CallEmitter ();
5806 call.EmitPredefined (ec, method, arguments, false);
5810 public override void FlowAnalysis (FlowAnalysisContext fc)
5812 arguments.FlowAnalysis (fc);
5815 public override SLE.Expression MakeExpression (BuilderContext ctx)
5817 if (arguments.Count != 2)
5818 throw new NotImplementedException ("arguments.Count != 2");
5820 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5821 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5826 // User-defined conditional logical operator
5828 public class ConditionalLogicalOperator : UserOperatorCall
5830 readonly bool is_and;
5831 Expression oper_expr;
5833 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5834 : base (oper, arguments, expr_tree, loc)
5836 this.is_and = is_and;
5837 eclass = ExprClass.Unresolved;
5840 protected override Expression DoResolve (ResolveContext ec)
5842 AParametersCollection pd = oper.Parameters;
5843 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5844 ec.Report.Error (217, loc,
5845 "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",
5846 oper.GetSignatureForError ());
5850 Expression left_dup = new EmptyExpression (type);
5851 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5852 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5853 if (op_true == null || op_false == null) {
5854 ec.Report.Error (218, loc,
5855 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5856 type.GetSignatureForError (), oper.GetSignatureForError ());
5860 oper_expr = is_and ? op_false : op_true;
5861 eclass = ExprClass.Value;
5865 public override void Emit (EmitContext ec)
5867 Label end_target = ec.DefineLabel ();
5870 // Emit and duplicate left argument
5872 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5873 if (right_contains_await) {
5874 arguments[0] = arguments[0].EmitToField (ec, false);
5875 arguments[0].Expr.Emit (ec);
5877 arguments[0].Expr.Emit (ec);
5878 ec.Emit (OpCodes.Dup);
5879 arguments.RemoveAt (0);
5882 oper_expr.EmitBranchable (ec, end_target, true);
5886 if (right_contains_await) {
5888 // Special handling when right expression contains await and left argument
5889 // could not be left on stack before logical branch
5891 Label skip_left_load = ec.DefineLabel ();
5892 ec.Emit (OpCodes.Br_S, skip_left_load);
5893 ec.MarkLabel (end_target);
5894 arguments[0].Expr.Emit (ec);
5895 ec.MarkLabel (skip_left_load);
5897 ec.MarkLabel (end_target);
5902 public class PointerArithmetic : Expression {
5903 Expression left, right;
5904 readonly Binary.Operator op;
5907 // We assume that `l' is always a pointer
5909 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5918 public override bool ContainsEmitWithAwait ()
5920 throw new NotImplementedException ();
5923 public override Expression CreateExpressionTree (ResolveContext ec)
5925 Error_PointerInsideExpressionTree (ec);
5929 protected override Expression DoResolve (ResolveContext ec)
5931 eclass = ExprClass.Variable;
5933 var pc = left.Type as PointerContainer;
5934 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5935 Error_VoidPointerOperation (ec);
5942 public override void Emit (EmitContext ec)
5944 TypeSpec op_type = left.Type;
5946 // It must be either array or fixed buffer
5948 if (TypeManager.HasElementType (op_type)) {
5949 element = TypeManager.GetElementType (op_type);
5951 FieldExpr fe = left as FieldExpr;
5953 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5958 int size = BuiltinTypeSpec.GetSize(element);
5959 TypeSpec rtype = right.Type;
5961 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5963 // handle (pointer - pointer)
5967 ec.Emit (OpCodes.Sub);
5971 ec.Emit (OpCodes.Sizeof, element);
5974 ec.Emit (OpCodes.Div);
5976 ec.Emit (OpCodes.Conv_I8);
5979 // handle + and - on (pointer op int)
5981 Constant left_const = left as Constant;
5982 if (left_const != null) {
5984 // Optimize ((T*)null) pointer operations
5986 if (left_const.IsDefaultValue) {
5987 left = EmptyExpression.Null;
5995 var right_const = right as Constant;
5996 if (right_const != null) {
5998 // Optimize 0-based arithmetic
6000 if (right_const.IsDefaultValue)
6004 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6006 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6008 // TODO: Should be the checks resolve context sensitive?
6009 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6010 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6016 switch (rtype.BuiltinType) {
6017 case BuiltinTypeSpec.Type.SByte:
6018 case BuiltinTypeSpec.Type.Byte:
6019 case BuiltinTypeSpec.Type.Short:
6020 case BuiltinTypeSpec.Type.UShort:
6021 ec.Emit (OpCodes.Conv_I);
6023 case BuiltinTypeSpec.Type.UInt:
6024 ec.Emit (OpCodes.Conv_U);
6028 if (right_const == null && size != 1){
6030 ec.Emit (OpCodes.Sizeof, element);
6033 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6034 ec.Emit (OpCodes.Conv_I8);
6036 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6039 if (left_const == null) {
6040 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6041 ec.Emit (OpCodes.Conv_I);
6042 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6043 ec.Emit (OpCodes.Conv_U);
6045 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6052 // A boolean-expression is an expression that yields a result
6055 public class BooleanExpression : ShimExpression
6057 public BooleanExpression (Expression expr)
6060 this.loc = expr.Location;
6063 public override Expression CreateExpressionTree (ResolveContext ec)
6065 // TODO: We should emit IsTrue (v4) instead of direct user operator
6066 // call but that would break csc compatibility
6067 return base.CreateExpressionTree (ec);
6070 protected override Expression DoResolve (ResolveContext ec)
6072 // A boolean-expression is required to be of a type
6073 // that can be implicitly converted to bool or of
6074 // a type that implements operator true
6076 expr = expr.Resolve (ec);
6080 Assign ass = expr as Assign;
6081 if (ass != null && ass.Source is Constant) {
6082 ec.Report.Warning (665, 3, loc,
6083 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6086 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6089 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6090 Arguments args = new Arguments (1);
6091 args.Add (new Argument (expr));
6092 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6095 type = ec.BuiltinTypes.Bool;
6096 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6097 if (converted != null)
6101 // If no implicit conversion to bool exists, try using `operator true'
6103 converted = GetOperatorTrue (ec, expr, loc);
6104 if (converted == null) {
6105 expr.Error_ValueCannotBeConverted (ec, type, false);
6112 public override object Accept (StructuralVisitor visitor)
6114 return visitor.Visit (this);
6118 public class BooleanExpressionFalse : Unary
6120 public BooleanExpressionFalse (Expression expr)
6121 : base (Operator.LogicalNot, expr, expr.Location)
6125 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6127 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6132 /// Implements the ternary conditional operator (?:)
6134 public class Conditional : Expression {
6135 Expression expr, true_expr, false_expr;
6137 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6140 this.true_expr = true_expr;
6141 this.false_expr = false_expr;
6147 public Expression Expr {
6153 public Expression TrueExpr {
6159 public Expression FalseExpr {
6167 public override bool ContainsEmitWithAwait ()
6169 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6172 public override Expression CreateExpressionTree (ResolveContext ec)
6174 Arguments args = new Arguments (3);
6175 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6176 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6177 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6178 return CreateExpressionFactoryCall (ec, "Condition", args);
6181 protected override Expression DoResolve (ResolveContext ec)
6183 expr = expr.Resolve (ec);
6184 true_expr = true_expr.Resolve (ec);
6185 false_expr = false_expr.Resolve (ec);
6187 if (true_expr == null || false_expr == null || expr == null)
6190 eclass = ExprClass.Value;
6191 TypeSpec true_type = true_expr.Type;
6192 TypeSpec false_type = false_expr.Type;
6196 // First, if an implicit conversion exists from true_expr
6197 // to false_expr, then the result type is of type false_expr.Type
6199 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6200 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6201 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6203 // Check if both can convert implicitly to each other's type
6207 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6208 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6210 // LAMESPEC: There seems to be hardcoded promotition to int type when
6211 // both sides are numeric constants and one side is int constant and
6212 // other side is numeric constant convertible to int.
6214 // var res = condition ? (short)1 : 1;
6216 // Type of res is int even if according to the spec the conversion is
6217 // ambiguous because 1 literal can be converted to short.
6219 if (conv_false_expr != null) {
6220 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6222 conv_false_expr = null;
6223 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6224 conv_false_expr = null;
6228 if (conv_false_expr != null) {
6229 ec.Report.Error (172, true_expr.Location,
6230 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6231 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6236 if (true_expr.Type != type)
6237 true_expr = EmptyCast.Create (true_expr, type);
6238 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6241 if (false_type != InternalType.ErrorType) {
6242 ec.Report.Error (173, true_expr.Location,
6243 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6244 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6250 Constant c = expr as Constant;
6252 bool is_false = c.IsDefaultValue;
6255 // Don't issue the warning for constant expressions
6257 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6258 // CSC: Missing warning
6259 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6262 return ReducedExpression.Create (
6263 is_false ? false_expr : true_expr, this,
6264 false_expr is Constant && true_expr is Constant).Resolve (ec);
6270 public override void Emit (EmitContext ec)
6272 Label false_target = ec.DefineLabel ();
6273 Label end_target = ec.DefineLabel ();
6275 expr.EmitBranchable (ec, false_target, false);
6276 true_expr.Emit (ec);
6279 // Verifier doesn't support interface merging. When there are two types on
6280 // the stack without common type hint and the common type is an interface.
6281 // Use temporary local to give verifier hint on what type to unify the stack
6283 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6284 var temp = ec.GetTemporaryLocal (type);
6285 ec.Emit (OpCodes.Stloc, temp);
6286 ec.Emit (OpCodes.Ldloc, temp);
6287 ec.FreeTemporaryLocal (temp, type);
6290 ec.Emit (OpCodes.Br, end_target);
6291 ec.MarkLabel (false_target);
6292 false_expr.Emit (ec);
6293 ec.MarkLabel (end_target);
6296 public override void FlowAnalysis (FlowAnalysisContext fc)
6298 expr.FlowAnalysisConditional (fc);
6299 var expr_true = fc.DefiniteAssignmentOnTrue;
6300 var expr_false = fc.DefiniteAssignmentOnFalse;
6302 fc.BranchDefiniteAssignment (expr_true);
6303 true_expr.FlowAnalysis (fc);
6304 var true_fc = fc.DefiniteAssignment;
6306 fc.BranchDefiniteAssignment (expr_false);
6307 false_expr.FlowAnalysis (fc);
6309 fc.DefiniteAssignment &= true_fc;
6312 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6314 expr.FlowAnalysisConditional (fc);
6315 var expr_true = fc.DefiniteAssignmentOnTrue;
6316 var expr_false = fc.DefiniteAssignmentOnFalse;
6318 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6319 true_expr.FlowAnalysisConditional (fc);
6320 var true_fc = fc.DefiniteAssignment;
6321 var true_da_true = fc.DefiniteAssignmentOnTrue;
6322 var true_da_false = fc.DefiniteAssignmentOnFalse;
6324 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6325 false_expr.FlowAnalysisConditional (fc);
6327 fc.DefiniteAssignment &= true_fc;
6328 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6329 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6332 protected override void CloneTo (CloneContext clonectx, Expression t)
6334 Conditional target = (Conditional) t;
6336 target.expr = expr.Clone (clonectx);
6337 target.true_expr = true_expr.Clone (clonectx);
6338 target.false_expr = false_expr.Clone (clonectx);
6342 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6344 LocalTemporary temp;
6347 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6348 public abstract void SetHasAddressTaken ();
6350 public abstract bool IsLockedByStatement { get; set; }
6352 public abstract bool IsFixed { get; }
6353 public abstract bool IsRef { get; }
6354 public abstract string Name { get; }
6357 // Variable IL data, it has to be protected to encapsulate hoisted variables
6359 protected abstract ILocalVariable Variable { get; }
6362 // Variable flow-analysis data
6364 public abstract VariableInfo VariableInfo { get; }
6367 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6369 HoistedVariable hv = GetHoistedVariable (ec);
6371 hv.AddressOf (ec, mode);
6375 Variable.EmitAddressOf (ec);
6378 public override bool ContainsEmitWithAwait ()
6383 public override Expression CreateExpressionTree (ResolveContext ec)
6385 HoistedVariable hv = GetHoistedVariable (ec);
6387 return hv.CreateExpressionTree ();
6389 Arguments arg = new Arguments (1);
6390 arg.Add (new Argument (this));
6391 return CreateExpressionFactoryCall (ec, "Constant", arg);
6394 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6396 if (IsLockedByStatement) {
6397 rc.Report.Warning (728, 2, loc,
6398 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6405 public override void Emit (EmitContext ec)
6410 public override void EmitSideEffect (EmitContext ec)
6416 // This method is used by parameters that are references, that are
6417 // being passed as references: we only want to pass the pointer (that
6418 // is already stored in the parameter, not the address of the pointer,
6419 // and not the value of the variable).
6421 public void EmitLoad (EmitContext ec)
6426 public void Emit (EmitContext ec, bool leave_copy)
6428 HoistedVariable hv = GetHoistedVariable (ec);
6430 hv.Emit (ec, leave_copy);
6438 // If we are a reference, we loaded on the stack a pointer
6439 // Now lets load the real value
6441 ec.EmitLoadFromPtr (type);
6445 ec.Emit (OpCodes.Dup);
6448 temp = new LocalTemporary (Type);
6454 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6455 bool prepare_for_load)
6457 HoistedVariable hv = GetHoistedVariable (ec);
6459 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6463 New n_source = source as New;
6464 if (n_source != null) {
6465 if (!n_source.Emit (ec, this)) {
6469 ec.EmitLoadFromPtr (type);
6481 ec.Emit (OpCodes.Dup);
6483 temp = new LocalTemporary (Type);
6489 ec.EmitStoreFromPtr (type);
6491 Variable.EmitAssign (ec);
6499 public override Expression EmitToField (EmitContext ec)
6501 HoistedVariable hv = GetHoistedVariable (ec);
6503 return hv.EmitToField (ec);
6506 return base.EmitToField (ec);
6509 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6511 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6514 public HoistedVariable GetHoistedVariable (EmitContext ec)
6516 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6519 public override string GetSignatureForError ()
6524 public bool IsHoisted {
6525 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6530 // Resolved reference to a local variable
6532 public class LocalVariableReference : VariableReference
6534 public LocalVariable local_info;
6536 public LocalVariableReference (LocalVariable li, Location l)
6538 this.local_info = li;
6542 public override VariableInfo VariableInfo {
6543 get { return local_info.VariableInfo; }
6546 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6548 return local_info.HoistedVariant;
6554 // A local variable is always fixed
6556 public override bool IsFixed {
6562 public override bool IsLockedByStatement {
6564 return local_info.IsLocked;
6567 local_info.IsLocked = value;
6571 public override bool IsRef {
6572 get { return false; }
6575 public override string Name {
6576 get { return local_info.Name; }
6581 public override void FlowAnalysis (FlowAnalysisContext fc)
6583 VariableInfo variable_info = VariableInfo;
6584 if (variable_info == null)
6587 if (fc.IsDefinitelyAssigned (variable_info))
6590 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6591 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6594 public override void SetHasAddressTaken ()
6596 local_info.SetHasAddressTaken ();
6599 void DoResolveBase (ResolveContext ec)
6601 eclass = ExprClass.Variable;
6602 type = local_info.Type;
6605 // If we are referencing a variable from the external block
6606 // flag it for capturing
6608 if (ec.MustCaptureVariable (local_info)) {
6609 if (local_info.AddressTaken) {
6610 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6611 } else if (local_info.IsFixed) {
6612 ec.Report.Error (1764, loc,
6613 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6614 GetSignatureForError ());
6617 if (ec.IsVariableCapturingRequired) {
6618 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6619 storey.CaptureLocalVariable (ec, local_info);
6624 protected override Expression DoResolve (ResolveContext ec)
6626 local_info.SetIsUsed ();
6630 if (local_info.Type == InternalType.VarOutType) {
6631 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6632 GetSignatureForError ());
6634 type = InternalType.ErrorType;
6640 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6643 // Don't be too pedantic when variable is used as out param or for some broken code
6644 // which uses property/indexer access to run some initialization
6646 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6647 local_info.SetIsUsed ();
6649 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6650 if (rhs == EmptyExpression.LValueMemberAccess) {
6651 // CS1654 already reported
6655 if (rhs == EmptyExpression.OutAccess) {
6656 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6657 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6658 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6659 } else if (rhs == EmptyExpression.UnaryAddress) {
6660 code = 459; msg = "Cannot take the address of {1} `{0}'";
6662 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6664 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6668 if (eclass == ExprClass.Unresolved)
6671 return base.DoResolveLValue (ec, rhs);
6674 public override int GetHashCode ()
6676 return local_info.GetHashCode ();
6679 public override bool Equals (object obj)
6681 LocalVariableReference lvr = obj as LocalVariableReference;
6685 return local_info == lvr.local_info;
6688 protected override ILocalVariable Variable {
6689 get { return local_info; }
6692 public override string ToString ()
6694 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6697 protected override void CloneTo (CloneContext clonectx, Expression t)
6704 /// This represents a reference to a parameter in the intermediate
6707 public class ParameterReference : VariableReference
6709 protected ParametersBlock.ParameterInfo pi;
6711 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6719 public override bool IsLockedByStatement {
6724 pi.IsLocked = value;
6728 public override bool IsRef {
6729 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6732 bool HasOutModifier {
6733 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6736 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6738 return pi.Parameter.HoistedVariant;
6742 // A ref or out parameter is classified as a moveable variable, even
6743 // if the argument given for the parameter is a fixed variable
6745 public override bool IsFixed {
6746 get { return !IsRef; }
6749 public override string Name {
6750 get { return Parameter.Name; }
6753 public Parameter Parameter {
6754 get { return pi.Parameter; }
6757 public override VariableInfo VariableInfo {
6758 get { return pi.VariableInfo; }
6761 protected override ILocalVariable Variable {
6762 get { return Parameter; }
6767 public override void AddressOf (EmitContext ec, AddressOp mode)
6770 // ParameterReferences might already be a reference
6777 base.AddressOf (ec, mode);
6780 public override void SetHasAddressTaken ()
6782 Parameter.HasAddressTaken = true;
6785 bool DoResolveBase (ResolveContext ec)
6787 if (eclass != ExprClass.Unresolved)
6790 type = pi.ParameterType;
6791 eclass = ExprClass.Variable;
6794 // If we are referencing a parameter from the external block
6795 // flag it for capturing
6797 if (ec.MustCaptureVariable (pi)) {
6798 if (Parameter.HasAddressTaken)
6799 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6802 ec.Report.Error (1628, loc,
6803 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6804 Name, ec.CurrentAnonymousMethod.ContainerType);
6807 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6808 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6809 storey.CaptureParameter (ec, pi, this);
6816 public override int GetHashCode ()
6818 return Name.GetHashCode ();
6821 public override bool Equals (object obj)
6823 ParameterReference pr = obj as ParameterReference;
6827 return Name == pr.Name;
6830 protected override void CloneTo (CloneContext clonectx, Expression target)
6836 public override Expression CreateExpressionTree (ResolveContext ec)
6838 HoistedVariable hv = GetHoistedVariable (ec);
6840 return hv.CreateExpressionTree ();
6842 return Parameter.ExpressionTreeVariableReference ();
6845 protected override Expression DoResolve (ResolveContext ec)
6847 if (!DoResolveBase (ec))
6853 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6855 if (!DoResolveBase (ec))
6858 if (Parameter.HoistedVariant != null)
6859 Parameter.HoistedVariant.IsAssigned = true;
6861 return base.DoResolveLValue (ec, right_side);
6864 public override void FlowAnalysis (FlowAnalysisContext fc)
6866 VariableInfo variable_info = VariableInfo;
6867 if (variable_info == null)
6870 if (fc.IsDefinitelyAssigned (variable_info))
6873 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6874 fc.SetVariableAssigned (variable_info);
6879 /// Invocation of methods or delegates.
6881 public class Invocation : ExpressionStatement
6883 public class Predefined : Invocation
6885 public Predefined (MethodGroupExpr expr, Arguments arguments)
6886 : base (expr, arguments)
6891 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6893 mg.BestCandidate.CheckObsoleteness (rc, loc);
6899 protected Arguments arguments;
6900 protected Expression expr;
6901 protected MethodGroupExpr mg;
6902 bool conditional_access_receiver;
6904 public Invocation (Expression expr, Arguments arguments)
6907 this.arguments = arguments;
6909 loc = expr.Location;
6914 public Arguments Arguments {
6920 public Expression Exp {
6926 public MethodGroupExpr MethodGroup {
6932 public override Location StartLocation {
6934 return expr.StartLocation;
6940 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6942 if (MethodGroup == null)
6945 var candidate = MethodGroup.BestCandidate;
6946 if (candidate == null || !(candidate.IsStatic || Exp is This))
6949 var args_count = arguments == null ? 0 : arguments.Count;
6950 if (args_count != body.Parameters.Count)
6953 var lambda_parameters = body.Block.Parameters.FixedParameters;
6954 for (int i = 0; i < args_count; ++i) {
6955 var pr = arguments[i].Expr as ParameterReference;
6959 if (lambda_parameters[i] != pr.Parameter)
6962 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6966 var emg = MethodGroup as ExtensionMethodGroupExpr;
6968 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6969 if (candidate.IsGeneric) {
6970 var targs = new TypeExpression [candidate.Arity];
6971 for (int i = 0; i < targs.Length; ++i) {
6972 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6975 mg.SetTypeArguments (null, new TypeArguments (targs));
6984 protected override void CloneTo (CloneContext clonectx, Expression t)
6986 Invocation target = (Invocation) t;
6988 if (arguments != null)
6989 target.arguments = arguments.Clone (clonectx);
6991 target.expr = expr.Clone (clonectx);
6994 public override bool ContainsEmitWithAwait ()
6996 if (arguments != null && arguments.ContainsEmitWithAwait ())
6999 return mg.ContainsEmitWithAwait ();
7002 public override Expression CreateExpressionTree (ResolveContext ec)
7004 Expression instance = mg.IsInstance ?
7005 mg.InstanceExpression.CreateExpressionTree (ec) :
7006 new NullLiteral (loc);
7008 var args = Arguments.CreateForExpressionTree (ec, arguments,
7010 mg.CreateExpressionTree (ec));
7012 return CreateExpressionFactoryCall (ec, "Call", args);
7015 void ResolveConditionalAccessReceiver (ResolveContext rc)
7017 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7018 conditional_access_receiver = true;
7022 protected override Expression DoResolve (ResolveContext rc)
7024 ResolveConditionalAccessReceiver (rc);
7025 return DoResolveInvocation (rc);
7028 Expression DoResolveInvocation (ResolveContext ec)
7030 Expression member_expr;
7031 var atn = expr as ATypeNameExpression;
7033 var flags = default (ResolveContext.FlagsHandle);
7034 if (conditional_access_receiver)
7035 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7038 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7039 if (member_expr != null) {
7040 var name_of = member_expr as NameOf;
7041 if (name_of != null) {
7042 return name_of.ResolveOverload (ec, arguments);
7045 member_expr = member_expr.Resolve (ec);
7048 member_expr = expr.Resolve (ec);
7051 if (conditional_access_receiver)
7054 if (member_expr == null)
7058 // Next, evaluate all the expressions in the argument list
7060 bool dynamic_arg = false;
7061 if (arguments != null) {
7062 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7063 arguments.Resolve (ec, out dynamic_arg);
7067 TypeSpec expr_type = member_expr.Type;
7068 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7069 return DoResolveDynamic (ec, member_expr);
7071 mg = member_expr as MethodGroupExpr;
7072 Expression invoke = null;
7075 if (expr_type != null && expr_type.IsDelegate) {
7076 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7077 invoke = invoke.Resolve (ec);
7078 if (invoke == null || !dynamic_arg)
7081 if (member_expr is RuntimeValueExpression) {
7082 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7083 member_expr.Type.GetSignatureForError ());
7087 MemberExpr me = member_expr as MemberExpr;
7089 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7093 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7094 member_expr.GetSignatureForError ());
7099 if (invoke == null) {
7100 mg = DoResolveOverload (ec);
7106 return DoResolveDynamic (ec, member_expr);
7108 var method = mg.BestCandidate;
7109 type = mg.BestCandidateReturnType;
7110 if (conditional_access_receiver)
7111 type = LiftMemberType (ec, type);
7113 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7115 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7117 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7121 IsSpecialMethodInvocation (ec, method, loc);
7123 eclass = ExprClass.Value;
7127 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7130 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7132 args = dmb.Arguments;
7133 if (arguments != null)
7134 args.AddRange (arguments);
7135 } else if (mg == null) {
7136 if (arguments == null)
7137 args = new Arguments (1);
7141 args.Insert (0, new Argument (memberExpr));
7145 ec.Report.Error (1971, loc,
7146 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7151 if (arguments == null)
7152 args = new Arguments (1);
7156 MemberAccess ma = expr as MemberAccess;
7158 var inst = mg.InstanceExpression;
7159 var left_type = inst as TypeExpr;
7160 if (left_type != null) {
7161 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7162 } else if (inst != null) {
7164 // Any value type has to be pass as by-ref to get back the same
7165 // instance on which the member was called
7167 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7168 Argument.AType.Ref : Argument.AType.None;
7169 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7171 } else { // is SimpleName
7173 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7175 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7180 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7183 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7185 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7188 public override void FlowAnalysis (FlowAnalysisContext fc)
7190 if (mg.IsConditionallyExcluded)
7193 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7195 mg.FlowAnalysis (fc);
7197 if (arguments != null)
7198 arguments.FlowAnalysis (fc);
7200 if (conditional_access_receiver)
7201 fc.DefiniteAssignment = da;
7204 public override string GetSignatureForError ()
7206 return mg.GetSignatureForError ();
7209 public override bool HasConditionalAccess ()
7211 return expr.HasConditionalAccess ();
7215 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7216 // or the type dynamic, then the member is invocable
7218 public static bool IsMemberInvocable (MemberSpec member)
7220 switch (member.Kind) {
7221 case MemberKind.Event:
7223 case MemberKind.Field:
7224 case MemberKind.Property:
7225 var m = member as IInterfaceMemberSpec;
7226 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7232 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7234 if (!method.IsReservedMethod)
7237 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7240 ec.Report.SymbolRelatedToPreviousError (method);
7241 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7242 method.GetSignatureForError ());
7247 public override void Emit (EmitContext ec)
7249 if (mg.IsConditionallyExcluded)
7252 if (conditional_access_receiver)
7253 mg.EmitCall (ec, arguments, type, false);
7255 mg.EmitCall (ec, arguments, false);
7258 public override void EmitStatement (EmitContext ec)
7260 if (mg.IsConditionallyExcluded)
7263 if (conditional_access_receiver)
7264 mg.EmitCall (ec, arguments, type, true);
7266 mg.EmitCall (ec, arguments, true);
7269 public override SLE.Expression MakeExpression (BuilderContext ctx)
7271 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7274 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7277 throw new NotSupportedException ();
7279 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7280 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7284 public override object Accept (StructuralVisitor visitor)
7286 return visitor.Visit (this);
7291 // Implements simple new expression
7293 public class New : ExpressionStatement, IMemoryLocation
7295 protected Arguments arguments;
7298 // During bootstrap, it contains the RequestedType,
7299 // but if `type' is not null, it *might* contain a NewDelegate
7300 // (because of field multi-initialization)
7302 protected Expression RequestedType;
7304 protected MethodSpec method;
7306 public New (Expression requested_type, Arguments arguments, Location l)
7308 RequestedType = requested_type;
7309 this.arguments = arguments;
7314 public Arguments Arguments {
7321 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7323 public bool IsGeneratedStructConstructor {
7325 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7329 public Expression TypeExpression {
7331 return RequestedType;
7338 /// Converts complex core type syntax like 'new int ()' to simple constant
7340 public static Constant Constantify (TypeSpec t, Location loc)
7342 switch (t.BuiltinType) {
7343 case BuiltinTypeSpec.Type.Int:
7344 return new IntConstant (t, 0, loc);
7345 case BuiltinTypeSpec.Type.UInt:
7346 return new UIntConstant (t, 0, loc);
7347 case BuiltinTypeSpec.Type.Long:
7348 return new LongConstant (t, 0, loc);
7349 case BuiltinTypeSpec.Type.ULong:
7350 return new ULongConstant (t, 0, loc);
7351 case BuiltinTypeSpec.Type.Float:
7352 return new FloatConstant (t, 0, loc);
7353 case BuiltinTypeSpec.Type.Double:
7354 return new DoubleConstant (t, 0, loc);
7355 case BuiltinTypeSpec.Type.Short:
7356 return new ShortConstant (t, 0, loc);
7357 case BuiltinTypeSpec.Type.UShort:
7358 return new UShortConstant (t, 0, loc);
7359 case BuiltinTypeSpec.Type.SByte:
7360 return new SByteConstant (t, 0, loc);
7361 case BuiltinTypeSpec.Type.Byte:
7362 return new ByteConstant (t, 0, loc);
7363 case BuiltinTypeSpec.Type.Char:
7364 return new CharConstant (t, '\0', loc);
7365 case BuiltinTypeSpec.Type.Bool:
7366 return new BoolConstant (t, false, loc);
7367 case BuiltinTypeSpec.Type.Decimal:
7368 return new DecimalConstant (t, 0, loc);
7372 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7374 if (t.IsNullableType)
7375 return Nullable.LiftedNull.Create (t, loc);
7380 public override bool ContainsEmitWithAwait ()
7382 return arguments != null && arguments.ContainsEmitWithAwait ();
7386 // Checks whether the type is an interface that has the
7387 // [ComImport, CoClass] attributes and must be treated
7390 public Expression CheckComImport (ResolveContext ec)
7392 if (!type.IsInterface)
7396 // Turn the call into:
7397 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7399 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7400 if (real_class == null)
7403 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7404 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7405 return cast.Resolve (ec);
7408 public override Expression CreateExpressionTree (ResolveContext ec)
7411 if (method == null) {
7412 args = new Arguments (1);
7413 args.Add (new Argument (new TypeOf (type, loc)));
7415 args = Arguments.CreateForExpressionTree (ec,
7416 arguments, new TypeOfMethod (method, loc));
7419 return CreateExpressionFactoryCall (ec, "New", args);
7422 protected override Expression DoResolve (ResolveContext ec)
7424 type = RequestedType.ResolveAsType (ec);
7428 eclass = ExprClass.Value;
7430 if (type.IsPointer) {
7431 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7432 type.GetSignatureForError ());
7436 if (arguments == null) {
7437 Constant c = Constantify (type, RequestedType.Location);
7439 return ReducedExpression.Create (c, this);
7442 if (type.IsDelegate) {
7443 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7446 var tparam = type as TypeParameterSpec;
7447 if (tparam != null) {
7449 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7450 // where type parameter constraint is inflated to struct
7452 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7453 ec.Report.Error (304, loc,
7454 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7455 type.GetSignatureForError ());
7458 if ((arguments != null) && (arguments.Count != 0)) {
7459 ec.Report.Error (417, loc,
7460 "`{0}': cannot provide arguments when creating an instance of a variable type",
7461 type.GetSignatureForError ());
7467 if (type.IsStatic) {
7468 ec.Report.SymbolRelatedToPreviousError (type);
7469 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7473 if (type.IsInterface || type.IsAbstract){
7474 if (!TypeManager.IsGenericType (type)) {
7475 RequestedType = CheckComImport (ec);
7476 if (RequestedType != null)
7477 return RequestedType;
7480 ec.Report.SymbolRelatedToPreviousError (type);
7481 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7486 if (arguments != null) {
7487 arguments.Resolve (ec, out dynamic);
7492 method = ConstructorLookup (ec, type, ref arguments, loc);
7495 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7496 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7502 void DoEmitTypeParameter (EmitContext ec)
7504 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7508 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7509 ec.Emit (OpCodes.Call, ctor_factory);
7513 // This Emit can be invoked in two contexts:
7514 // * As a mechanism that will leave a value on the stack (new object)
7515 // * As one that wont (init struct)
7517 // If we are dealing with a ValueType, we have a few
7518 // situations to deal with:
7520 // * The target is a ValueType, and we have been provided
7521 // the instance (this is easy, we are being assigned).
7523 // * The target of New is being passed as an argument,
7524 // to a boxing operation or a function that takes a
7527 // In this case, we need to create a temporary variable
7528 // that is the argument of New.
7530 // Returns whether a value is left on the stack
7532 // *** Implementation note ***
7534 // To benefit from this optimization, each assignable expression
7535 // has to manually cast to New and call this Emit.
7537 // TODO: It's worth to implement it for arrays and fields
7539 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7541 bool is_value_type = type.IsStructOrEnum;
7542 VariableReference vr = target as VariableReference;
7544 if (target != null && is_value_type && (vr != null || method == null)) {
7545 target.AddressOf (ec, AddressOp.Store);
7546 } else if (vr != null && vr.IsRef) {
7550 if (arguments != null) {
7551 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7552 arguments = arguments.Emit (ec, false, true);
7554 arguments.Emit (ec);
7557 if (is_value_type) {
7558 if (method == null) {
7559 ec.Emit (OpCodes.Initobj, type);
7564 ec.MarkCallEntry (loc);
7565 ec.Emit (OpCodes.Call, method);
7570 if (type is TypeParameterSpec) {
7571 DoEmitTypeParameter (ec);
7575 ec.MarkCallEntry (loc);
7576 ec.Emit (OpCodes.Newobj, method);
7580 public override void Emit (EmitContext ec)
7582 LocalTemporary v = null;
7583 if (method == null && type.IsStructOrEnum) {
7584 // TODO: Use temporary variable from pool
7585 v = new LocalTemporary (type);
7592 public override void EmitStatement (EmitContext ec)
7594 LocalTemporary v = null;
7595 if (method == null && TypeSpec.IsValueType (type)) {
7596 // TODO: Use temporary variable from pool
7597 v = new LocalTemporary (type);
7601 ec.Emit (OpCodes.Pop);
7604 public override void FlowAnalysis (FlowAnalysisContext fc)
7606 if (arguments != null)
7607 arguments.FlowAnalysis (fc);
7610 public void AddressOf (EmitContext ec, AddressOp mode)
7612 EmitAddressOf (ec, mode);
7615 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7617 LocalTemporary value_target = new LocalTemporary (type);
7619 if (type is TypeParameterSpec) {
7620 DoEmitTypeParameter (ec);
7621 value_target.Store (ec);
7622 value_target.AddressOf (ec, mode);
7623 return value_target;
7626 value_target.AddressOf (ec, AddressOp.Store);
7628 if (method == null) {
7629 ec.Emit (OpCodes.Initobj, type);
7631 if (arguments != null)
7632 arguments.Emit (ec);
7634 ec.Emit (OpCodes.Call, method);
7637 value_target.AddressOf (ec, mode);
7638 return value_target;
7641 protected override void CloneTo (CloneContext clonectx, Expression t)
7643 New target = (New) t;
7645 target.RequestedType = RequestedType.Clone (clonectx);
7646 if (arguments != null){
7647 target.arguments = arguments.Clone (clonectx);
7651 public override SLE.Expression MakeExpression (BuilderContext ctx)
7654 return base.MakeExpression (ctx);
7656 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7660 public override object Accept (StructuralVisitor visitor)
7662 return visitor.Visit (this);
7667 // Array initializer expression, the expression is allowed in
7668 // variable or field initialization only which makes it tricky as
7669 // the type has to be infered based on the context either from field
7670 // type or variable type (think of multiple declarators)
7672 public class ArrayInitializer : Expression
7674 List<Expression> elements;
7675 BlockVariable variable;
7677 public ArrayInitializer (List<Expression> init, Location loc)
7683 public ArrayInitializer (int count, Location loc)
7684 : this (new List<Expression> (count), loc)
7688 public ArrayInitializer (Location loc)
7696 get { return elements.Count; }
7699 public List<Expression> Elements {
7705 public Expression this [int index] {
7707 return elements [index];
7711 public BlockVariable VariableDeclaration {
7722 public void Add (Expression expr)
7724 elements.Add (expr);
7727 public override bool ContainsEmitWithAwait ()
7729 throw new NotSupportedException ();
7732 public override Expression CreateExpressionTree (ResolveContext ec)
7734 throw new NotSupportedException ("ET");
7737 protected override void CloneTo (CloneContext clonectx, Expression t)
7739 var target = (ArrayInitializer) t;
7741 target.elements = new List<Expression> (elements.Count);
7742 foreach (var element in elements)
7743 target.elements.Add (element.Clone (clonectx));
7746 protected override Expression DoResolve (ResolveContext rc)
7748 var current_field = rc.CurrentMemberDefinition as FieldBase;
7749 TypeExpression type;
7750 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7751 type = new TypeExpression (current_field.MemberType, current_field.Location);
7752 } else if (variable != null) {
7753 if (variable.TypeExpression is VarExpr) {
7754 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7755 return EmptyExpression.Null;
7758 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7760 throw new NotImplementedException ("Unexpected array initializer context");
7763 return new ArrayCreation (type, this).Resolve (rc);
7766 public override void Emit (EmitContext ec)
7768 throw new InternalErrorException ("Missing Resolve call");
7771 public override void FlowAnalysis (FlowAnalysisContext fc)
7773 throw new InternalErrorException ("Missing Resolve call");
7776 public override object Accept (StructuralVisitor visitor)
7778 return visitor.Visit (this);
7783 /// 14.5.10.2: Represents an array creation expression.
7787 /// There are two possible scenarios here: one is an array creation
7788 /// expression that specifies the dimensions and optionally the
7789 /// initialization data and the other which does not need dimensions
7790 /// specified but where initialization data is mandatory.
7792 public class ArrayCreation : Expression
7794 FullNamedExpression requested_base_type;
7795 ArrayInitializer initializers;
7798 // The list of Argument types.
7799 // This is used to construct the `newarray' or constructor signature
7801 protected List<Expression> arguments;
7803 protected TypeSpec array_element_type;
7805 protected int dimensions;
7806 protected readonly ComposedTypeSpecifier rank;
7807 Expression first_emit;
7808 LocalTemporary first_emit_temp;
7810 protected List<Expression> array_data;
7812 Dictionary<int, int> bounds;
7815 // The number of constants in array initializers
7816 int const_initializers_count;
7817 bool only_constant_initializers;
7819 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7820 : this (requested_base_type, rank, initializers, l)
7822 arguments = new List<Expression> (exprs);
7823 num_arguments = arguments.Count;
7827 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7829 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7831 this.requested_base_type = requested_base_type;
7833 this.initializers = initializers;
7837 num_arguments = rank.Dimension;
7841 // For compiler generated single dimensional arrays only
7843 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7844 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7849 // For expressions like int[] foo = { 1, 2, 3 };
7851 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7852 : this (requested_base_type, null, initializers, initializers.Location)
7856 public ComposedTypeSpecifier Rank {
7862 public FullNamedExpression TypeExpression {
7864 return this.requested_base_type;
7868 public ArrayInitializer Initializers {
7870 return this.initializers;
7874 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7876 if (initializers != null && bounds == null) {
7878 // We use this to store all the data values in the order in which we
7879 // will need to store them in the byte blob later
7881 array_data = new List<Expression> (probe.Count);
7882 bounds = new Dictionary<int, int> ();
7885 if (specified_dims) {
7886 Expression a = arguments [idx];
7891 a = ConvertExpressionToArrayIndex (ec, a);
7897 if (initializers != null) {
7898 Constant c = a as Constant;
7899 if (c == null && a is ArrayIndexCast)
7900 c = ((ArrayIndexCast) a).Child as Constant;
7903 ec.Report.Error (150, a.Location, "A constant value is expected");
7909 value = System.Convert.ToInt32 (c.GetValue ());
7911 ec.Report.Error (150, a.Location, "A constant value is expected");
7915 // TODO: probe.Count does not fit ulong in
7916 if (value != probe.Count) {
7917 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7921 bounds[idx] = value;
7925 if (initializers == null)
7928 for (int i = 0; i < probe.Count; ++i) {
7930 if (o is ArrayInitializer) {
7931 var sub_probe = o as ArrayInitializer;
7932 if (idx + 1 >= dimensions){
7933 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7937 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7938 if (!bounds.ContainsKey(idx + 1))
7939 bounds[idx + 1] = sub_probe.Count;
7941 if (bounds[idx + 1] != sub_probe.Count) {
7942 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7946 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7949 } else if (child_bounds > 1) {
7950 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7952 Expression element = ResolveArrayElement (ec, o);
7953 if (element == null)
7956 // Initializers with the default values can be ignored
7957 Constant c = element as Constant;
7959 if (!c.IsDefaultInitializer (array_element_type)) {
7960 ++const_initializers_count;
7963 only_constant_initializers = false;
7966 array_data.Add (element);
7973 public override bool ContainsEmitWithAwait ()
7975 foreach (var arg in arguments) {
7976 if (arg.ContainsEmitWithAwait ())
7980 return InitializersContainAwait ();
7983 public override Expression CreateExpressionTree (ResolveContext ec)
7987 if (array_data == null) {
7988 args = new Arguments (arguments.Count + 1);
7989 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7990 foreach (Expression a in arguments)
7991 args.Add (new Argument (a.CreateExpressionTree (ec)));
7993 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7996 if (dimensions > 1) {
7997 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8001 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8002 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8003 if (array_data != null) {
8004 for (int i = 0; i < array_data.Count; ++i) {
8005 Expression e = array_data [i];
8006 args.Add (new Argument (e.CreateExpressionTree (ec)));
8010 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8013 void UpdateIndices (ResolveContext rc)
8016 for (var probe = initializers; probe != null;) {
8017 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8019 bounds[i++] = probe.Count;
8021 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8022 probe = (ArrayInitializer) probe[0];
8023 } else if (dimensions > i) {
8031 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8033 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8036 public override void FlowAnalysis (FlowAnalysisContext fc)
8038 foreach (var arg in arguments)
8039 arg.FlowAnalysis (fc);
8041 if (array_data != null) {
8042 foreach (var ad in array_data)
8043 ad.FlowAnalysis (fc);
8047 bool InitializersContainAwait ()
8049 if (array_data == null)
8052 foreach (var expr in array_data) {
8053 if (expr.ContainsEmitWithAwait ())
8060 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8062 element = element.Resolve (ec);
8063 if (element == null)
8066 if (element is CompoundAssign.TargetExpression) {
8067 if (first_emit != null)
8068 throw new InternalErrorException ("Can only handle one mutator at a time");
8069 first_emit = element;
8070 element = first_emit_temp = new LocalTemporary (element.Type);
8073 return Convert.ImplicitConversionRequired (
8074 ec, element, array_element_type, loc);
8077 protected bool ResolveInitializers (ResolveContext ec)
8080 only_constant_initializers = true;
8083 if (arguments != null) {
8085 for (int i = 0; i < arguments.Count; ++i) {
8086 res &= CheckIndices (ec, initializers, i, true, dimensions);
8087 if (initializers != null)
8094 arguments = new List<Expression> ();
8096 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8105 // Resolved the type of the array
8107 bool ResolveArrayType (ResolveContext ec)
8112 FullNamedExpression array_type_expr;
8113 if (num_arguments > 0) {
8114 array_type_expr = new ComposedCast (requested_base_type, rank);
8116 array_type_expr = requested_base_type;
8119 type = array_type_expr.ResolveAsType (ec);
8120 if (array_type_expr == null)
8123 var ac = type as ArrayContainer;
8125 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8129 array_element_type = ac.Element;
8130 dimensions = ac.Rank;
8135 protected override Expression DoResolve (ResolveContext ec)
8140 if (!ResolveArrayType (ec))
8144 // validate the initializers and fill in any missing bits
8146 if (!ResolveInitializers (ec))
8149 eclass = ExprClass.Value;
8153 byte [] MakeByteBlob ()
8158 int count = array_data.Count;
8160 TypeSpec element_type = array_element_type;
8161 if (element_type.IsEnum)
8162 element_type = EnumSpec.GetUnderlyingType (element_type);
8164 factor = BuiltinTypeSpec.GetSize (element_type);
8166 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8168 data = new byte [(count * factor + 3) & ~3];
8171 for (int i = 0; i < count; ++i) {
8172 var c = array_data[i] as Constant;
8178 object v = c.GetValue ();
8180 switch (element_type.BuiltinType) {
8181 case BuiltinTypeSpec.Type.Long:
8182 long lval = (long) v;
8184 for (int j = 0; j < factor; ++j) {
8185 data[idx + j] = (byte) (lval & 0xFF);
8189 case BuiltinTypeSpec.Type.ULong:
8190 ulong ulval = (ulong) v;
8192 for (int j = 0; j < factor; ++j) {
8193 data[idx + j] = (byte) (ulval & 0xFF);
8194 ulval = (ulval >> 8);
8197 case BuiltinTypeSpec.Type.Float:
8198 var fval = SingleConverter.SingleToInt32Bits((float) v);
8200 data[idx] = (byte) (fval & 0xff);
8201 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8202 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8203 data[idx + 3] = (byte) (fval >> 24);
8205 case BuiltinTypeSpec.Type.Double:
8206 element = BitConverter.GetBytes ((double) v);
8208 for (int j = 0; j < factor; ++j)
8209 data[idx + j] = element[j];
8211 // FIXME: Handle the ARM float format.
8212 if (!BitConverter.IsLittleEndian)
8213 System.Array.Reverse (data, idx, 8);
8215 case BuiltinTypeSpec.Type.Char:
8216 int chval = (int) ((char) v);
8218 data[idx] = (byte) (chval & 0xff);
8219 data[idx + 1] = (byte) (chval >> 8);
8221 case BuiltinTypeSpec.Type.Short:
8222 int sval = (int) ((short) v);
8224 data[idx] = (byte) (sval & 0xff);
8225 data[idx + 1] = (byte) (sval >> 8);
8227 case BuiltinTypeSpec.Type.UShort:
8228 int usval = (int) ((ushort) v);
8230 data[idx] = (byte) (usval & 0xff);
8231 data[idx + 1] = (byte) (usval >> 8);
8233 case BuiltinTypeSpec.Type.Int:
8236 data[idx] = (byte) (val & 0xff);
8237 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8238 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8239 data[idx + 3] = (byte) (val >> 24);
8241 case BuiltinTypeSpec.Type.UInt:
8242 uint uval = (uint) v;
8244 data[idx] = (byte) (uval & 0xff);
8245 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8246 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8247 data[idx + 3] = (byte) (uval >> 24);
8249 case BuiltinTypeSpec.Type.SByte:
8250 data[idx] = (byte) (sbyte) v;
8252 case BuiltinTypeSpec.Type.Byte:
8253 data[idx] = (byte) v;
8255 case BuiltinTypeSpec.Type.Bool:
8256 data[idx] = (byte) ((bool) v ? 1 : 0);
8258 case BuiltinTypeSpec.Type.Decimal:
8259 int[] bits = Decimal.GetBits ((decimal) v);
8262 // FIXME: For some reason, this doesn't work on the MS runtime.
8263 int[] nbits = new int[4];
8269 for (int j = 0; j < 4; j++) {
8270 data[p++] = (byte) (nbits[j] & 0xff);
8271 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8272 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8273 data[p++] = (byte) (nbits[j] >> 24);
8277 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8286 public override SLE.Expression MakeExpression (BuilderContext ctx)
8289 return base.MakeExpression (ctx);
8291 var initializers = new SLE.Expression [array_data.Count];
8292 for (var i = 0; i < initializers.Length; i++) {
8293 if (array_data [i] == null)
8294 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8296 initializers [i] = array_data [i].MakeExpression (ctx);
8299 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8304 // Emits the initializers for the array
8306 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8308 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8313 // First, the static data
8315 byte [] data = MakeByteBlob ();
8316 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8318 if (stackArray == null) {
8319 ec.Emit (OpCodes.Dup);
8321 stackArray.Emit (ec);
8324 ec.Emit (OpCodes.Ldtoken, fb);
8325 ec.Emit (OpCodes.Call, m);
8330 // Emits pieces of the array that can not be computed at compile
8331 // time (variables and string locations).
8333 // This always expect the top value on the stack to be the array
8335 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8337 int dims = bounds.Count;
8338 var current_pos = new int [dims];
8340 for (int i = 0; i < array_data.Count; i++){
8342 Expression e = array_data [i];
8343 var c = e as Constant;
8345 // Constant can be initialized via StaticInitializer
8346 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8350 if (stackArray != null) {
8351 if (e.ContainsEmitWithAwait ()) {
8352 e = e.EmitToField (ec);
8355 stackArray.EmitLoad (ec);
8357 ec.Emit (OpCodes.Dup);
8360 for (int idx = 0; idx < dims; idx++)
8361 ec.EmitInt (current_pos [idx]);
8364 // If we are dealing with a struct, get the
8365 // address of it, so we can store it.
8367 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8368 ec.Emit (OpCodes.Ldelema, etype);
8372 ec.EmitArrayStore ((ArrayContainer) type);
8378 for (int j = dims - 1; j >= 0; j--){
8380 if (current_pos [j] < bounds [j])
8382 current_pos [j] = 0;
8386 if (stackArray != null)
8387 stackArray.PrepareCleanup (ec);
8390 public override void Emit (EmitContext ec)
8392 var await_field = EmitToFieldSource (ec);
8393 if (await_field != null)
8394 await_field.Emit (ec);
8397 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8399 if (first_emit != null) {
8400 first_emit.Emit (ec);
8401 first_emit_temp.Store (ec);
8404 StackFieldExpr await_stack_field;
8405 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8406 await_stack_field = ec.GetTemporaryField (type);
8409 await_stack_field = null;
8412 EmitExpressionsList (ec, arguments);
8414 ec.EmitArrayNew ((ArrayContainer) type);
8416 if (initializers == null)
8417 return await_stack_field;
8419 if (await_stack_field != null)
8420 await_stack_field.EmitAssignFromStack (ec);
8424 // Emit static initializer for arrays which contain more than 2 items and
8425 // the static initializer will initialize at least 25% of array values or there
8426 // is more than 10 items to be initialized
8428 // NOTE: const_initializers_count does not contain default constant values.
8430 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8431 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8432 EmitStaticInitializers (ec, await_stack_field);
8434 if (!only_constant_initializers)
8435 EmitDynamicInitializers (ec, false, await_stack_field);
8439 EmitDynamicInitializers (ec, true, await_stack_field);
8442 if (first_emit_temp != null)
8443 first_emit_temp.Release (ec);
8445 return await_stack_field;
8448 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8450 // no multi dimensional or jagged arrays
8451 if (arguments.Count != 1 || array_element_type.IsArray) {
8452 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8456 // No array covariance, except for array -> object
8457 if (type != targetType) {
8458 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8459 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8463 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8464 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8469 // Single dimensional array of 0 size
8470 if (array_data == null) {
8471 IntConstant ic = arguments[0] as IntConstant;
8472 if (ic == null || !ic.IsDefaultValue) {
8473 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8481 enc.Encode (array_data.Count);
8482 foreach (var element in array_data) {
8483 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8487 protected override void CloneTo (CloneContext clonectx, Expression t)
8489 ArrayCreation target = (ArrayCreation) t;
8491 if (requested_base_type != null)
8492 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8494 if (arguments != null){
8495 target.arguments = new List<Expression> (arguments.Count);
8496 foreach (Expression e in arguments)
8497 target.arguments.Add (e.Clone (clonectx));
8500 if (initializers != null)
8501 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8504 public override object Accept (StructuralVisitor visitor)
8506 return visitor.Visit (this);
8511 // Represents an implicitly typed array epxression
8513 class ImplicitlyTypedArrayCreation : ArrayCreation
8515 TypeInferenceContext best_type_inference;
8517 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8518 : base (null, rank, initializers, loc)
8522 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8523 : base (null, initializers, loc)
8527 protected override Expression DoResolve (ResolveContext ec)
8532 dimensions = rank.Dimension;
8534 best_type_inference = new TypeInferenceContext ();
8536 if (!ResolveInitializers (ec))
8539 best_type_inference.FixAllTypes (ec);
8540 array_element_type = best_type_inference.InferredTypeArguments[0];
8541 best_type_inference = null;
8543 if (array_element_type == null ||
8544 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8545 arguments.Count != rank.Dimension) {
8546 ec.Report.Error (826, loc,
8547 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8552 // At this point we found common base type for all initializer elements
8553 // but we have to be sure that all static initializer elements are of
8556 UnifyInitializerElement (ec);
8558 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8559 eclass = ExprClass.Value;
8564 // Converts static initializer only
8566 void UnifyInitializerElement (ResolveContext ec)
8568 for (int i = 0; i < array_data.Count; ++i) {
8569 Expression e = array_data[i];
8571 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8575 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8577 element = element.Resolve (ec);
8578 if (element != null)
8579 best_type_inference.AddCommonTypeBound (element.Type);
8585 sealed class CompilerGeneratedThis : This
8587 public CompilerGeneratedThis (TypeSpec type, Location loc)
8593 protected override Expression DoResolve (ResolveContext rc)
8595 eclass = ExprClass.Variable;
8597 var block = rc.CurrentBlock;
8598 if (block != null) {
8599 var top = block.ParametersBlock.TopBlock;
8600 if (top.ThisVariable != null)
8601 variable_info = top.ThisVariable.VariableInfo;
8608 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8610 return DoResolve (rc);
8613 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8620 /// Represents the `this' construct
8623 public class This : VariableReference
8625 sealed class ThisVariable : ILocalVariable
8627 public static readonly ILocalVariable Instance = new ThisVariable ();
8629 public void Emit (EmitContext ec)
8634 public void EmitAssign (EmitContext ec)
8636 throw new InvalidOperationException ();
8639 public void EmitAddressOf (EmitContext ec)
8645 protected VariableInfo variable_info;
8647 public This (Location loc)
8654 public override string Name {
8655 get { return "this"; }
8658 public override bool IsLockedByStatement {
8666 public override bool IsRef {
8667 get { return type.IsStruct; }
8670 public override bool IsSideEffectFree {
8676 protected override ILocalVariable Variable {
8677 get { return ThisVariable.Instance; }
8680 public override VariableInfo VariableInfo {
8681 get { return variable_info; }
8684 public override bool IsFixed {
8685 get { return false; }
8690 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8693 // It's null for all cases when we don't need to check `this'
8694 // definitive assignment
8696 if (variable_info == null)
8699 if (fc.IsDefinitelyAssigned (variable_info))
8702 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8705 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8707 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8708 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8709 } else if (ec.CurrentAnonymousMethod != null) {
8710 ec.Report.Error (1673, loc,
8711 "Anonymous methods inside structs cannot access instance members of `this'. " +
8712 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8714 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8718 public override void FlowAnalysis (FlowAnalysisContext fc)
8720 CheckStructThisDefiniteAssignment (fc);
8723 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8728 AnonymousMethodStorey storey = ae.Storey;
8729 return storey != null ? storey.HoistedThis : null;
8732 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8734 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8737 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8740 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8746 public virtual void ResolveBase (ResolveContext ec)
8748 eclass = ExprClass.Variable;
8749 type = ec.CurrentType;
8751 if (!IsThisAvailable (ec, false)) {
8752 Error_ThisNotAvailable (ec);
8756 var block = ec.CurrentBlock;
8757 if (block != null) {
8758 var top = block.ParametersBlock.TopBlock;
8759 if (top.ThisVariable != null)
8760 variable_info = top.ThisVariable.VariableInfo;
8762 AnonymousExpression am = ec.CurrentAnonymousMethod;
8763 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8765 // Hoisted this is almost like hoisted variable but not exactly. When
8766 // there is no variable hoisted we can simply emit an instance method
8767 // without lifting this into a storey. Unfotunatelly this complicates
8768 // things in other cases because we don't know where this will be hoisted
8769 // until top-level block is fully resolved
8771 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8772 am.SetHasThisAccess ();
8777 protected override Expression DoResolve (ResolveContext ec)
8783 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8785 if (eclass == ExprClass.Unresolved)
8789 if (right_side == EmptyExpression.UnaryAddress)
8790 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8791 else if (right_side == EmptyExpression.OutAccess)
8792 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8794 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8800 public override int GetHashCode()
8802 throw new NotImplementedException ();
8805 public override bool Equals (object obj)
8807 This t = obj as This;
8814 protected override void CloneTo (CloneContext clonectx, Expression t)
8819 public override void SetHasAddressTaken ()
8824 public override object Accept (StructuralVisitor visitor)
8826 return visitor.Visit (this);
8831 /// Represents the `__arglist' construct
8833 public class ArglistAccess : Expression
8835 public ArglistAccess (Location loc)
8840 protected override void CloneTo (CloneContext clonectx, Expression target)
8845 public override bool ContainsEmitWithAwait ()
8850 public override Expression CreateExpressionTree (ResolveContext ec)
8852 throw new NotSupportedException ("ET");
8855 protected override Expression DoResolve (ResolveContext ec)
8857 eclass = ExprClass.Variable;
8858 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8860 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8861 ec.Report.Error (190, loc,
8862 "The __arglist construct is valid only within a variable argument method");
8868 public override void Emit (EmitContext ec)
8870 ec.Emit (OpCodes.Arglist);
8873 public override object Accept (StructuralVisitor visitor)
8875 return visitor.Visit (this);
8880 /// Represents the `__arglist (....)' construct
8882 public class Arglist : Expression
8884 Arguments arguments;
8886 public Arglist (Location loc)
8891 public Arglist (Arguments args, Location l)
8897 public Arguments Arguments {
8903 public MetaType[] ArgumentTypes {
8905 if (arguments == null)
8906 return MetaType.EmptyTypes;
8908 var retval = new MetaType[arguments.Count];
8909 for (int i = 0; i < retval.Length; i++)
8910 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8916 public override bool ContainsEmitWithAwait ()
8918 throw new NotImplementedException ();
8921 public override Expression CreateExpressionTree (ResolveContext ec)
8923 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8927 protected override Expression DoResolve (ResolveContext ec)
8929 eclass = ExprClass.Variable;
8930 type = InternalType.Arglist;
8931 if (arguments != null) {
8932 bool dynamic; // Can be ignored as there is always only 1 overload
8933 arguments.Resolve (ec, out dynamic);
8939 public override void Emit (EmitContext ec)
8941 if (arguments != null)
8942 arguments.Emit (ec);
8945 protected override void CloneTo (CloneContext clonectx, Expression t)
8947 Arglist target = (Arglist) t;
8949 if (arguments != null)
8950 target.arguments = arguments.Clone (clonectx);
8953 public override object Accept (StructuralVisitor visitor)
8955 return visitor.Visit (this);
8959 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8961 FullNamedExpression texpr;
8963 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8970 public FullNamedExpression TypeExpression {
8976 public override bool ContainsEmitWithAwait ()
8981 public void AddressOf (EmitContext ec, AddressOp mode)
8984 ec.Emit (OpCodes.Refanyval, type);
8987 protected override Expression DoResolve (ResolveContext rc)
8989 expr = expr.Resolve (rc);
8990 type = texpr.ResolveAsType (rc);
8991 if (expr == null || type == null)
8994 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8995 eclass = ExprClass.Variable;
8999 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9001 return DoResolve (rc);
9004 public override void Emit (EmitContext ec)
9007 ec.Emit (OpCodes.Refanyval, type);
9008 ec.EmitLoadFromPtr (type);
9011 public void Emit (EmitContext ec, bool leave_copy)
9013 throw new NotImplementedException ();
9016 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9019 ec.Emit (OpCodes.Refanyval, type);
9022 LocalTemporary temporary = null;
9024 ec.Emit (OpCodes.Dup);
9025 temporary = new LocalTemporary (source.Type);
9026 temporary.Store (ec);
9029 ec.EmitStoreFromPtr (type);
9031 if (temporary != null) {
9032 temporary.Emit (ec);
9033 temporary.Release (ec);
9037 public override object Accept (StructuralVisitor visitor)
9039 return visitor.Visit (this);
9043 public class RefTypeExpr : ShimExpression
9045 public RefTypeExpr (Expression expr, Location loc)
9051 protected override Expression DoResolve (ResolveContext rc)
9053 expr = expr.Resolve (rc);
9057 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9061 type = rc.BuiltinTypes.Type;
9062 eclass = ExprClass.Value;
9066 public override void Emit (EmitContext ec)
9069 ec.Emit (OpCodes.Refanytype);
9070 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9072 ec.Emit (OpCodes.Call, m);
9075 public override object Accept (StructuralVisitor visitor)
9077 return visitor.Visit (this);
9081 public class MakeRefExpr : ShimExpression
9083 public MakeRefExpr (Expression expr, Location loc)
9089 public override bool ContainsEmitWithAwait ()
9091 throw new NotImplementedException ();
9094 protected override Expression DoResolve (ResolveContext rc)
9096 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9097 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9098 eclass = ExprClass.Value;
9102 public override void Emit (EmitContext ec)
9104 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9105 ec.Emit (OpCodes.Mkrefany, expr.Type);
9108 public override object Accept (StructuralVisitor visitor)
9110 return visitor.Visit (this);
9115 /// Implements the typeof operator
9117 public class TypeOf : Expression {
9118 FullNamedExpression QueriedType;
9121 public TypeOf (FullNamedExpression queried_type, Location l)
9123 QueriedType = queried_type;
9128 // Use this constructor for any compiler generated typeof expression
9130 public TypeOf (TypeSpec type, Location loc)
9132 this.typearg = type;
9138 public override bool IsSideEffectFree {
9144 public TypeSpec TypeArgument {
9150 public FullNamedExpression TypeExpression {
9159 protected override void CloneTo (CloneContext clonectx, Expression t)
9161 TypeOf target = (TypeOf) t;
9162 if (QueriedType != null)
9163 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9166 public override bool ContainsEmitWithAwait ()
9171 public override Expression CreateExpressionTree (ResolveContext ec)
9173 Arguments args = new Arguments (2);
9174 args.Add (new Argument (this));
9175 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9176 return CreateExpressionFactoryCall (ec, "Constant", args);
9179 protected override Expression DoResolve (ResolveContext ec)
9181 if (eclass != ExprClass.Unresolved)
9184 if (typearg == null) {
9186 // Pointer types are allowed without explicit unsafe, they are just tokens
9188 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9189 typearg = QueriedType.ResolveAsType (ec, true);
9192 if (typearg == null)
9195 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9196 ec.Report.Error (1962, QueriedType.Location,
9197 "The typeof operator cannot be used on the dynamic type");
9201 type = ec.BuiltinTypes.Type;
9203 // Even though what is returned is a type object, it's treated as a value by the compiler.
9204 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9205 eclass = ExprClass.Value;
9209 static bool ContainsDynamicType (TypeSpec type)
9211 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9214 var element_container = type as ElementTypeSpec;
9215 if (element_container != null)
9216 return ContainsDynamicType (element_container.Element);
9218 foreach (var t in type.TypeArguments) {
9219 if (ContainsDynamicType (t)) {
9227 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9229 // Target type is not System.Type therefore must be object
9230 // and we need to use different encoding sequence
9231 if (targetType != type)
9234 if (typearg is InflatedTypeSpec) {
9237 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9238 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9239 typearg.GetSignatureForError ());
9243 gt = gt.DeclaringType;
9244 } while (gt != null);
9247 if (ContainsDynamicType (typearg)) {
9248 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9252 enc.EncodeTypeName (typearg);
9255 public override void Emit (EmitContext ec)
9257 ec.Emit (OpCodes.Ldtoken, typearg);
9258 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9260 ec.Emit (OpCodes.Call, m);
9263 public override object Accept (StructuralVisitor visitor)
9265 return visitor.Visit (this);
9269 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9271 public TypeOfMethod (MethodSpec method, Location loc)
9272 : base (method, loc)
9276 protected override Expression DoResolve (ResolveContext ec)
9278 if (member.IsConstructor) {
9279 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9281 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9287 return base.DoResolve (ec);
9290 public override void Emit (EmitContext ec)
9292 ec.Emit (OpCodes.Ldtoken, member);
9295 ec.Emit (OpCodes.Castclass, type);
9298 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9300 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9303 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9305 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9309 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9311 protected readonly T member;
9313 protected TypeOfMember (T member, Location loc)
9315 this.member = member;
9319 public override bool IsSideEffectFree {
9325 public override bool ContainsEmitWithAwait ()
9330 public override Expression CreateExpressionTree (ResolveContext ec)
9332 Arguments args = new Arguments (2);
9333 args.Add (new Argument (this));
9334 args.Add (new Argument (new TypeOf (type, loc)));
9335 return CreateExpressionFactoryCall (ec, "Constant", args);
9338 protected override Expression DoResolve (ResolveContext ec)
9340 eclass = ExprClass.Value;
9344 public override void Emit (EmitContext ec)
9346 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9347 PredefinedMember<MethodSpec> p;
9349 p = GetTypeFromHandleGeneric (ec);
9350 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9352 p = GetTypeFromHandle (ec);
9355 var mi = p.Resolve (loc);
9357 ec.Emit (OpCodes.Call, mi);
9360 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9361 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9364 sealed class TypeOfField : TypeOfMember<FieldSpec>
9366 public TypeOfField (FieldSpec field, Location loc)
9371 protected override Expression DoResolve (ResolveContext ec)
9373 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9377 return base.DoResolve (ec);
9380 public override void Emit (EmitContext ec)
9382 ec.Emit (OpCodes.Ldtoken, member);
9386 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9388 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9391 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9393 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9398 /// Implements the sizeof expression
9400 public class SizeOf : Expression {
9401 readonly Expression texpr;
9402 TypeSpec type_queried;
9404 public SizeOf (Expression queried_type, Location l)
9406 this.texpr = queried_type;
9410 public override bool IsSideEffectFree {
9416 public Expression TypeExpression {
9422 public override bool ContainsEmitWithAwait ()
9427 public override Expression CreateExpressionTree (ResolveContext ec)
9429 Error_PointerInsideExpressionTree (ec);
9433 protected override Expression DoResolve (ResolveContext ec)
9435 type_queried = texpr.ResolveAsType (ec);
9436 if (type_queried == null)
9439 if (type_queried.IsEnum)
9440 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9442 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9444 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9447 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9452 ec.Report.Error (233, loc,
9453 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9454 type_queried.GetSignatureForError ());
9457 type = ec.BuiltinTypes.Int;
9458 eclass = ExprClass.Value;
9462 public override void Emit (EmitContext ec)
9464 ec.Emit (OpCodes.Sizeof, type_queried);
9467 protected override void CloneTo (CloneContext clonectx, Expression t)
9471 public override object Accept (StructuralVisitor visitor)
9473 return visitor.Visit (this);
9478 /// Implements the qualified-alias-member (::) expression.
9480 public class QualifiedAliasMember : MemberAccess
9482 readonly string alias;
9483 public static readonly string GlobalAlias = "global";
9485 public QualifiedAliasMember (string alias, string identifier, Location l)
9486 : base (null, identifier, l)
9491 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9492 : base (null, identifier, targs, l)
9497 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9498 : base (null, identifier, arity, l)
9503 public string Alias {
9509 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9511 if (alias == GlobalAlias)
9512 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9514 int errors = mc.Module.Compiler.Report.Errors;
9515 var expr = mc.LookupNamespaceAlias (alias);
9517 if (errors == mc.Module.Compiler.Report.Errors)
9518 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9526 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9528 expr = CreateExpressionFromAlias (mc);
9532 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9535 protected override Expression DoResolve (ResolveContext rc)
9537 return ResolveAsTypeOrNamespace (rc, false);
9540 public override string GetSignatureForError ()
9543 if (targs != null) {
9544 name = Name + "<" + targs.GetSignatureForError () + ">";
9547 return alias + "::" + name;
9550 public override bool HasConditionalAccess ()
9555 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9557 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9558 rc.Module.Compiler.Report.Error (687, loc,
9559 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9560 GetSignatureForError ());
9565 return DoResolve (rc);
9568 protected override void CloneTo (CloneContext clonectx, Expression t)
9573 public override object Accept (StructuralVisitor visitor)
9575 return visitor.Visit (this);
9580 /// Implements the member access expression
9582 public class MemberAccess : ATypeNameExpression
9584 protected Expression expr;
9586 public MemberAccess (Expression expr, string id)
9587 : base (id, expr.Location)
9592 public MemberAccess (Expression expr, string identifier, Location loc)
9593 : base (identifier, loc)
9598 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9599 : base (identifier, args, loc)
9604 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9605 : base (identifier, arity, loc)
9610 public Expression LeftExpression {
9616 public override Location StartLocation {
9618 return expr == null ? loc : expr.StartLocation;
9622 protected override Expression DoResolve (ResolveContext rc)
9624 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9626 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9631 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9633 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9635 if (e is TypeExpr) {
9636 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9641 e = e.ResolveLValue (rc, rhs);
9646 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9648 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9649 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9651 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9654 public override bool HasConditionalAccess ()
9656 return LeftExpression.HasConditionalAccess ();
9659 public static bool IsValidDotExpression (TypeSpec type)
9661 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9662 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9664 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9667 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9669 var sn = expr as SimpleName;
9670 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9673 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9676 // Resolve expression which does have type set as we need expression type
9677 // with disable flow analysis as we don't know whether left side expression
9678 // is used as variable or type
9680 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9681 expr = expr.Resolve (rc);
9682 } else if (expr is TypeParameterExpr) {
9683 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9687 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9688 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9689 expr = expr.Resolve (rc, flags);
9692 expr = expr.Resolve (rc, flags);
9699 var ns = expr as NamespaceExpression;
9701 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9703 if (retval == null) {
9704 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9709 if (HasTypeArguments)
9710 return new GenericTypeExpr (retval.Type, targs, loc);
9712 targs.Resolve (rc, false);
9719 TypeSpec expr_type = expr.Type;
9720 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9721 me = expr as MemberExpr;
9723 me.ResolveInstanceExpression (rc, null);
9725 Arguments args = new Arguments (1);
9726 args.Add (new Argument (expr));
9727 return new DynamicMemberBinder (Name, args, loc);
9730 var cma = this as ConditionalMemberAccess;
9732 if (!IsNullPropagatingValid (expr.Type)) {
9733 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9737 if (expr_type.IsNullableType) {
9738 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9739 expr_type = expr.Type;
9743 if (!IsValidDotExpression (expr_type)) {
9744 Error_OperatorCannotBeApplied (rc, expr_type);
9748 var lookup_arity = Arity;
9749 bool errorMode = false;
9750 Expression member_lookup;
9752 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9753 if (member_lookup == null) {
9755 // Try to look for extension method when member lookup failed
9757 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9758 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9759 if (methods != null) {
9760 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9761 if (HasTypeArguments) {
9762 if (!targs.Resolve (rc, false))
9765 emg.SetTypeArguments (rc, targs);
9769 emg.ConditionalAccess = true;
9771 // TODO: it should really skip the checks bellow
9772 return emg.Resolve (rc);
9778 if (member_lookup == null) {
9779 var dep = expr_type.GetMissingDependencies ();
9781 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9782 } else if (expr is TypeExpr) {
9783 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9785 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9791 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9792 // Leave it to overload resolution to report correct error
9793 } else if (!(member_lookup is TypeExpr)) {
9794 // TODO: rc.SymbolRelatedToPreviousError
9795 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9800 if (member_lookup != null)
9804 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9808 TypeExpr texpr = member_lookup as TypeExpr;
9809 if (texpr != null) {
9810 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9811 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9812 Name, texpr.GetSignatureForError ());
9815 if (!texpr.Type.IsAccessible (rc)) {
9816 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9817 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9821 if (HasTypeArguments) {
9822 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9825 return member_lookup;
9828 me = member_lookup as MemberExpr;
9830 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9835 me.ConditionalAccess = true;
9838 me = me.ResolveMemberAccess (rc, expr, sn);
9841 if (!targs.Resolve (rc, false))
9844 me.SetTypeArguments (rc, targs);
9850 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9852 FullNamedExpression fexpr = expr as FullNamedExpression;
9853 if (fexpr == null) {
9854 expr.ResolveAsType (rc);
9858 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9860 if (expr_resolved == null)
9863 var ns = expr_resolved as NamespaceExpression;
9865 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9867 if (retval == null) {
9868 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9869 } else if (Arity > 0) {
9870 if (HasTypeArguments) {
9871 retval = new GenericTypeExpr (retval.Type, targs, loc);
9872 if (retval.ResolveAsType (rc) == null)
9875 targs.Resolve (rc, allowUnboundTypeArguments);
9877 retval = new GenericOpenTypeExpr (retval.Type, loc);
9884 var tnew_expr = expr_resolved.ResolveAsType (rc);
9885 if (tnew_expr == null)
9888 TypeSpec expr_type = tnew_expr;
9889 if (TypeManager.IsGenericParameter (expr_type)) {
9890 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9891 tnew_expr.GetSignatureForError ());
9895 var qam = this as QualifiedAliasMember;
9897 rc.Module.Compiler.Report.Error (431, loc,
9898 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9903 TypeSpec nested = null;
9904 while (expr_type != null) {
9905 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9906 if (nested == null) {
9907 if (expr_type == tnew_expr) {
9908 Error_IdentifierNotFound (rc, expr_type);
9912 expr_type = tnew_expr;
9913 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9914 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9918 if (nested.IsAccessible (rc))
9922 // Keep looking after inaccessible candidate but only if
9923 // we are not in same context as the definition itself
9925 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9928 expr_type = expr_type.BaseType;
9933 if (HasTypeArguments) {
9934 texpr = new GenericTypeExpr (nested, targs, loc);
9936 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9938 texpr = new GenericOpenTypeExpr (nested, loc);
9940 } else if (expr_resolved is GenericOpenTypeExpr) {
9941 texpr = new GenericOpenTypeExpr (nested, loc);
9943 texpr = new TypeExpression (nested, loc);
9946 if (texpr.ResolveAsType (rc) == null)
9952 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9954 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9956 if (nested != null) {
9957 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9961 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9962 if (any_other_member != null) {
9963 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9967 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9968 Name, expr_type.GetSignatureForError ());
9971 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9973 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9976 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9978 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9979 ec.Report.SymbolRelatedToPreviousError (type);
9981 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9983 // a using directive or an assembly reference
9985 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9987 missing = "an assembly reference";
9990 ec.Report.Error (1061, loc,
9991 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9992 type.GetSignatureForError (), name, missing);
9996 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9999 public override string GetSignatureForError ()
10001 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10004 protected override void CloneTo (CloneContext clonectx, Expression t)
10006 MemberAccess target = (MemberAccess) t;
10008 target.expr = expr.Clone (clonectx);
10011 public override object Accept (StructuralVisitor visitor)
10013 return visitor.Visit (this);
10017 public class ConditionalMemberAccess : MemberAccess
10019 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10020 : base (expr, identifier, args, loc)
10024 public override bool HasConditionalAccess ()
10031 /// Implements checked expressions
10033 public class CheckedExpr : Expression {
10035 public Expression Expr;
10037 public CheckedExpr (Expression e, Location l)
10043 public override bool ContainsEmitWithAwait ()
10045 return Expr.ContainsEmitWithAwait ();
10048 public override Expression CreateExpressionTree (ResolveContext ec)
10050 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10051 return Expr.CreateExpressionTree (ec);
10054 protected override Expression DoResolve (ResolveContext ec)
10056 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10057 Expr = Expr.Resolve (ec);
10062 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10065 eclass = Expr.eclass;
10070 public override void Emit (EmitContext ec)
10072 using (ec.With (EmitContext.Options.CheckedScope, true))
10076 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10078 using (ec.With (EmitContext.Options.CheckedScope, true))
10079 Expr.EmitBranchable (ec, target, on_true);
10082 public override void FlowAnalysis (FlowAnalysisContext fc)
10084 Expr.FlowAnalysis (fc);
10087 public override SLE.Expression MakeExpression (BuilderContext ctx)
10089 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10090 return Expr.MakeExpression (ctx);
10094 protected override void CloneTo (CloneContext clonectx, Expression t)
10096 CheckedExpr target = (CheckedExpr) t;
10098 target.Expr = Expr.Clone (clonectx);
10101 public override object Accept (StructuralVisitor visitor)
10103 return visitor.Visit (this);
10108 /// Implements the unchecked expression
10110 public class UnCheckedExpr : Expression {
10112 public Expression Expr;
10114 public UnCheckedExpr (Expression e, Location l)
10120 public override bool ContainsEmitWithAwait ()
10122 return Expr.ContainsEmitWithAwait ();
10125 public override Expression CreateExpressionTree (ResolveContext ec)
10127 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10128 return Expr.CreateExpressionTree (ec);
10131 protected override Expression DoResolve (ResolveContext ec)
10133 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10134 Expr = Expr.Resolve (ec);
10139 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10142 eclass = Expr.eclass;
10147 public override void Emit (EmitContext ec)
10149 using (ec.With (EmitContext.Options.CheckedScope, false))
10153 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10155 using (ec.With (EmitContext.Options.CheckedScope, false))
10156 Expr.EmitBranchable (ec, target, on_true);
10159 public override void FlowAnalysis (FlowAnalysisContext fc)
10161 Expr.FlowAnalysis (fc);
10164 protected override void CloneTo (CloneContext clonectx, Expression t)
10166 UnCheckedExpr target = (UnCheckedExpr) t;
10168 target.Expr = Expr.Clone (clonectx);
10171 public override object Accept (StructuralVisitor visitor)
10173 return visitor.Visit (this);
10178 /// An Element Access expression.
10180 /// During semantic analysis these are transformed into
10181 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10183 public class ElementAccess : Expression
10185 public Arguments Arguments;
10186 public Expression Expr;
10187 bool conditional_access_receiver;
10189 public ElementAccess (Expression e, Arguments args, Location loc)
10193 this.Arguments = args;
10196 public bool ConditionalAccess { get; set; }
10198 public override Location StartLocation {
10200 return Expr.StartLocation;
10204 public override bool ContainsEmitWithAwait ()
10206 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10210 // We perform some simple tests, and then to "split" the emit and store
10211 // code we create an instance of a different class, and return that.
10213 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10215 if (conditionalAccessReceiver)
10216 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10218 Expr = Expr.Resolve (ec);
10220 if (conditionalAccessReceiver)
10221 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10228 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10229 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10233 if (type.IsArray) {
10234 var aa = new ArrayAccess (this, loc) {
10235 ConditionalAccess = ConditionalAccess,
10238 if (conditionalAccessReceiver)
10239 aa.SetConditionalAccessReceiver ();
10244 if (type.IsPointer)
10245 return Expr.MakePointerAccess (ec, type, Arguments);
10247 FieldExpr fe = Expr as FieldExpr;
10249 var ff = fe.Spec as FixedFieldSpec;
10251 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10255 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10256 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10257 var indexer = new IndexerExpr (indexers, type, this) {
10258 ConditionalAccess = ConditionalAccess
10261 if (conditionalAccessReceiver)
10262 indexer.SetConditionalAccessReceiver ();
10267 Error_CannotApplyIndexing (ec, type, loc);
10272 public override Expression CreateExpressionTree (ResolveContext ec)
10274 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10275 Expr.CreateExpressionTree (ec));
10277 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10280 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10282 if (type != InternalType.ErrorType) {
10283 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10284 type.GetSignatureForError ());
10288 public override bool HasConditionalAccess ()
10290 return ConditionalAccess || Expr.HasConditionalAccess ();
10293 void ResolveConditionalAccessReceiver (ResolveContext rc)
10295 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10296 conditional_access_receiver = true;
10300 protected override Expression DoResolve (ResolveContext rc)
10302 ResolveConditionalAccessReceiver (rc);
10304 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10308 return expr.Resolve (rc);
10311 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10313 var res = CreateAccessExpression (ec, false);
10317 return res.ResolveLValue (ec, rhs);
10320 public override void Emit (EmitContext ec)
10322 throw new Exception ("Should never be reached");
10325 public override void FlowAnalysis (FlowAnalysisContext fc)
10327 Expr.FlowAnalysis (fc);
10329 Arguments.FlowAnalysis (fc);
10332 public override string GetSignatureForError ()
10334 return Expr.GetSignatureForError ();
10337 protected override void CloneTo (CloneContext clonectx, Expression t)
10339 ElementAccess target = (ElementAccess) t;
10341 target.Expr = Expr.Clone (clonectx);
10342 if (Arguments != null)
10343 target.Arguments = Arguments.Clone (clonectx);
10346 public override object Accept (StructuralVisitor visitor)
10348 return visitor.Visit (this);
10353 /// Implements array access
10355 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10357 // Points to our "data" repository
10361 LocalTemporary temp;
10363 bool? has_await_args;
10364 bool conditional_access_receiver;
10366 public ArrayAccess (ElementAccess ea_data, Location l)
10372 public bool ConditionalAccess { get; set; }
10374 public void AddressOf (EmitContext ec, AddressOp mode)
10376 var ac = (ArrayContainer) ea.Expr.Type;
10378 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10379 LoadInstanceAndArguments (ec, false, true);
10382 LoadInstanceAndArguments (ec, false, false);
10384 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10385 ec.Emit (OpCodes.Readonly);
10387 ec.EmitArrayAddress (ac);
10390 public override Expression CreateExpressionTree (ResolveContext ec)
10392 if (ConditionalAccess)
10393 Error_NullShortCircuitInsideExpressionTree (ec);
10395 return ea.CreateExpressionTree (ec);
10398 public override bool ContainsEmitWithAwait ()
10400 return ea.ContainsEmitWithAwait ();
10403 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10405 if (HasConditionalAccess ())
10406 Error_NullPropagatingLValue (ec);
10408 return DoResolve (ec);
10411 protected override Expression DoResolve (ResolveContext ec)
10413 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10415 ea.Arguments.Resolve (ec, out dynamic);
10417 var ac = ea.Expr.Type as ArrayContainer;
10418 int rank = ea.Arguments.Count;
10419 if (ac.Rank != rank) {
10420 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10421 rank.ToString (), ac.Rank.ToString ());
10426 if (type.IsPointer && !ec.IsUnsafe) {
10427 UnsafeError (ec, ea.Location);
10430 if (conditional_access_receiver)
10431 type = LiftMemberType (ec, type);
10433 foreach (Argument a in ea.Arguments) {
10434 var na = a as NamedArgument;
10436 ElementAccess.Error_NamedArgument (na, ec.Report);
10438 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10441 eclass = ExprClass.Variable;
10446 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10448 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10451 public override void FlowAnalysis (FlowAnalysisContext fc)
10453 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10455 ea.FlowAnalysis (fc);
10457 if (conditional_access_receiver)
10458 fc.DefiniteAssignment = da;
10461 public override bool HasConditionalAccess ()
10463 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10467 // Load the array arguments into the stack.
10469 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10471 if (prepareAwait) {
10472 ea.Expr = ea.Expr.EmitToField (ec);
10474 var ie = new InstanceEmitter (ea.Expr, false);
10475 ie.Emit (ec, ConditionalAccess);
10477 if (duplicateArguments) {
10478 ec.Emit (OpCodes.Dup);
10480 var copy = new LocalTemporary (ea.Expr.Type);
10486 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10487 if (dup_args != null)
10488 ea.Arguments = dup_args;
10491 public void Emit (EmitContext ec, bool leave_copy)
10494 ec.EmitLoadFromPtr (type);
10496 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10497 LoadInstanceAndArguments (ec, false, true);
10500 if (conditional_access_receiver)
10501 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10503 var ac = (ArrayContainer) ea.Expr.Type;
10504 LoadInstanceAndArguments (ec, false, false);
10505 ec.EmitArrayLoad (ac);
10507 if (conditional_access_receiver)
10508 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10512 ec.Emit (OpCodes.Dup);
10513 temp = new LocalTemporary (this.type);
10518 public override void Emit (EmitContext ec)
10523 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10525 var ac = (ArrayContainer) ea.Expr.Type;
10526 TypeSpec t = source.Type;
10528 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10531 // When we are dealing with a struct, get the address of it to avoid value copy
10532 // Same cannot be done for reference type because array covariance and the
10533 // check in ldelema requires to specify the type of array element stored at the index
10535 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10536 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10538 if (has_await_args.Value) {
10539 if (source.ContainsEmitWithAwait ()) {
10540 source = source.EmitToField (ec);
10541 isCompound = false;
10545 LoadInstanceAndArguments (ec, isCompound, false);
10550 ec.EmitArrayAddress (ac);
10553 ec.Emit (OpCodes.Dup);
10557 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10559 if (has_await_args.Value) {
10560 if (source.ContainsEmitWithAwait ())
10561 source = source.EmitToField (ec);
10563 LoadInstanceAndArguments (ec, false, false);
10570 var lt = ea.Expr as LocalTemporary;
10576 ec.Emit (OpCodes.Dup);
10577 temp = new LocalTemporary (this.type);
10582 ec.EmitStoreFromPtr (t);
10584 ec.EmitArrayStore (ac);
10587 if (temp != null) {
10593 public override Expression EmitToField (EmitContext ec)
10596 // Have to be specialized for arrays to get access to
10597 // underlying element. Instead of another result copy we
10598 // need direct access to element
10602 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10604 ea.Expr = ea.Expr.EmitToField (ec);
10605 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10609 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10611 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10614 public override SLE.Expression MakeExpression (BuilderContext ctx)
10616 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10619 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10621 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10622 return Arguments.MakeExpression (ea.Arguments, ctx);
10626 public void SetConditionalAccessReceiver ()
10628 conditional_access_receiver = true;
10633 // Indexer access expression
10635 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10637 IList<MemberSpec> indexers;
10638 Arguments arguments;
10639 TypeSpec queried_type;
10641 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10642 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10646 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10649 this.indexers = indexers;
10650 this.queried_type = queriedType;
10651 this.InstanceExpression = instance;
10652 this.arguments = args;
10657 protected override Arguments Arguments {
10666 protected override TypeSpec DeclaringType {
10668 return best_candidate.DeclaringType;
10672 public override bool IsInstance {
10678 public override bool IsStatic {
10684 public override string KindName {
10685 get { return "indexer"; }
10688 public override string Name {
10696 public override bool ContainsEmitWithAwait ()
10698 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10701 public override Expression CreateExpressionTree (ResolveContext ec)
10703 if (ConditionalAccess) {
10704 Error_NullShortCircuitInsideExpressionTree (ec);
10707 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10708 InstanceExpression.CreateExpressionTree (ec),
10709 new TypeOfMethod (Getter, loc));
10711 return CreateExpressionFactoryCall (ec, "Call", args);
10714 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10716 LocalTemporary await_source_arg = null;
10719 emitting_compound_assignment = true;
10720 if (source is DynamicExpressionStatement) {
10725 emitting_compound_assignment = false;
10727 if (has_await_arguments) {
10728 await_source_arg = new LocalTemporary (Type);
10729 await_source_arg.Store (ec);
10731 arguments.Add (new Argument (await_source_arg));
10734 temp = await_source_arg;
10737 has_await_arguments = false;
10742 ec.Emit (OpCodes.Dup);
10743 temp = new LocalTemporary (Type);
10749 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10750 source = source.EmitToField (ec);
10752 temp = new LocalTemporary (Type);
10759 arguments.Add (new Argument (source));
10762 var call = new CallEmitter ();
10763 call.InstanceExpression = InstanceExpression;
10764 if (arguments == null)
10765 call.InstanceExpressionOnStack = true;
10767 call.Emit (ec, Setter, arguments, loc);
10769 if (temp != null) {
10772 } else if (leave_copy) {
10776 if (await_source_arg != null) {
10777 await_source_arg.Release (ec);
10781 public override void FlowAnalysis (FlowAnalysisContext fc)
10783 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10785 base.FlowAnalysis (fc);
10786 arguments.FlowAnalysis (fc);
10788 if (conditional_access_receiver)
10789 fc.DefiniteAssignment = da;
10792 public override string GetSignatureForError ()
10794 return best_candidate.GetSignatureForError ();
10797 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10800 throw new NotSupportedException ();
10802 var value = new[] { source.MakeExpression (ctx) };
10803 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10804 return SLE.Expression.Block (
10805 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10810 public override SLE.Expression MakeExpression (BuilderContext ctx)
10813 return base.MakeExpression (ctx);
10815 var args = Arguments.MakeExpression (arguments, ctx);
10816 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10820 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10822 if (best_candidate != null)
10825 eclass = ExprClass.IndexerAccess;
10828 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10829 arguments.Resolve (rc, out dynamic);
10832 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10835 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10836 res.BaseMembersProvider = this;
10837 res.InstanceQualifier = this;
10839 // TODO: Do I need 2 argument sets?
10840 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10841 if (best_candidate != null)
10842 type = res.BestCandidateReturnType;
10843 else if (!res.BestCandidateIsDynamic)
10848 // It has dynamic arguments
10851 Arguments args = new Arguments (arguments.Count + 1);
10853 rc.Report.Error (1972, loc,
10854 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10856 args.Add (new Argument (InstanceExpression));
10858 args.AddRange (arguments);
10860 best_candidate = null;
10861 return new DynamicIndexBinder (args, loc);
10865 // Try to avoid resolving left expression again
10867 if (right_side != null)
10868 ResolveInstanceExpression (rc, right_side);
10873 protected override void CloneTo (CloneContext clonectx, Expression t)
10875 IndexerExpr target = (IndexerExpr) t;
10877 if (arguments != null)
10878 target.arguments = arguments.Clone (clonectx);
10881 public void SetConditionalAccessReceiver ()
10883 conditional_access_receiver = true;
10886 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10888 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10891 #region IBaseMembersProvider Members
10893 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10895 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10898 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10900 if (queried_type == member.DeclaringType)
10903 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10904 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10907 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10916 // A base access expression
10918 public class BaseThis : This
10920 public BaseThis (Location loc)
10925 public BaseThis (TypeSpec type, Location loc)
10929 eclass = ExprClass.Variable;
10934 public override string Name {
10942 public override Expression CreateExpressionTree (ResolveContext ec)
10944 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10945 return base.CreateExpressionTree (ec);
10948 public override void Emit (EmitContext ec)
10952 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10953 var context_type = ec.CurrentType;
10954 ec.Emit (OpCodes.Ldobj, context_type);
10955 ec.Emit (OpCodes.Box, context_type);
10959 protected override void Error_ThisNotAvailable (ResolveContext ec)
10962 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10964 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10968 public override void ResolveBase (ResolveContext ec)
10970 base.ResolveBase (ec);
10971 type = ec.CurrentType.BaseType;
10974 public override object Accept (StructuralVisitor visitor)
10976 return visitor.Visit (this);
10981 /// This class exists solely to pass the Type around and to be a dummy
10982 /// that can be passed to the conversion functions (this is used by
10983 /// foreach implementation to typecast the object return value from
10984 /// get_Current into the proper type. All code has been generated and
10985 /// we only care about the side effect conversions to be performed
10987 /// This is also now used as a placeholder where a no-action expression
10988 /// is needed (the `New' class).
10990 public class EmptyExpression : Expression
10992 sealed class OutAccessExpression : EmptyExpression
10994 public OutAccessExpression (TypeSpec t)
10999 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11001 rc.Report.Error (206, right_side.Location,
11002 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11008 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11009 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11010 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11011 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11012 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11013 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11014 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11015 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11017 public EmptyExpression (TypeSpec t)
11020 eclass = ExprClass.Value;
11021 loc = Location.Null;
11024 protected override void CloneTo (CloneContext clonectx, Expression target)
11028 public override bool ContainsEmitWithAwait ()
11033 public override Expression CreateExpressionTree (ResolveContext ec)
11035 throw new NotSupportedException ("ET");
11038 protected override Expression DoResolve (ResolveContext ec)
11043 public override void Emit (EmitContext ec)
11045 // nothing, as we only exist to not do anything.
11048 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11052 public override void EmitSideEffect (EmitContext ec)
11056 public override object Accept (StructuralVisitor visitor)
11058 return visitor.Visit (this);
11062 sealed class EmptyAwaitExpression : EmptyExpression
11064 public EmptyAwaitExpression (TypeSpec type)
11069 public override bool ContainsEmitWithAwait ()
11076 // Empty statement expression
11078 public sealed class EmptyExpressionStatement : ExpressionStatement
11080 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11082 private EmptyExpressionStatement ()
11084 loc = Location.Null;
11087 public override bool ContainsEmitWithAwait ()
11092 public override Expression CreateExpressionTree (ResolveContext ec)
11097 public override void EmitStatement (EmitContext ec)
11102 protected override Expression DoResolve (ResolveContext ec)
11104 eclass = ExprClass.Value;
11105 type = ec.BuiltinTypes.Object;
11109 public override void Emit (EmitContext ec)
11114 public override object Accept (StructuralVisitor visitor)
11116 return visitor.Visit (this);
11120 public class ErrorExpression : EmptyExpression
11122 public static readonly ErrorExpression Instance = new ErrorExpression ();
11124 private ErrorExpression ()
11125 : base (InternalType.ErrorType)
11129 public override Expression CreateExpressionTree (ResolveContext ec)
11134 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11139 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11143 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11147 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11151 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11155 public override object Accept (StructuralVisitor visitor)
11157 return visitor.Visit (this);
11161 public class UserCast : Expression {
11165 public UserCast (MethodSpec method, Expression source, Location l)
11167 if (source == null)
11168 throw new ArgumentNullException ("source");
11170 this.method = method;
11171 this.source = source;
11172 type = method.ReturnType;
11176 public Expression Source {
11185 public override bool ContainsEmitWithAwait ()
11187 return source.ContainsEmitWithAwait ();
11190 public override Expression CreateExpressionTree (ResolveContext ec)
11192 Arguments args = new Arguments (3);
11193 args.Add (new Argument (source.CreateExpressionTree (ec)));
11194 args.Add (new Argument (new TypeOf (type, loc)));
11195 args.Add (new Argument (new TypeOfMethod (method, loc)));
11196 return CreateExpressionFactoryCall (ec, "Convert", args);
11199 protected override Expression DoResolve (ResolveContext ec)
11201 method.CheckObsoleteness (ec, source.Location);
11203 eclass = ExprClass.Value;
11207 public override void Emit (EmitContext ec)
11210 ec.MarkCallEntry (loc);
11211 ec.Emit (OpCodes.Call, method);
11214 public override void FlowAnalysis (FlowAnalysisContext fc)
11216 source.FlowAnalysis (fc);
11219 public override string GetSignatureForError ()
11221 return TypeManager.CSharpSignature (method);
11224 public override SLE.Expression MakeExpression (BuilderContext ctx)
11227 return base.MakeExpression (ctx);
11229 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11235 // Holds additional type specifiers like ?, *, []
11237 public class ComposedTypeSpecifier
11239 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11241 public readonly int Dimension;
11242 public readonly Location Location;
11244 public ComposedTypeSpecifier (int specifier, Location loc)
11246 this.Dimension = specifier;
11247 this.Location = loc;
11251 public bool IsNullable {
11253 return Dimension == -1;
11257 public bool IsPointer {
11259 return Dimension == -2;
11263 public ComposedTypeSpecifier Next { get; set; }
11267 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11269 return new ComposedTypeSpecifier (dimension, loc);
11272 public static ComposedTypeSpecifier CreateNullable (Location loc)
11274 return new ComposedTypeSpecifier (-1, loc);
11277 public static ComposedTypeSpecifier CreatePointer (Location loc)
11279 return new ComposedTypeSpecifier (-2, loc);
11282 public string GetSignatureForError ()
11287 ArrayContainer.GetPostfixSignature (Dimension);
11289 return Next != null ? s + Next.GetSignatureForError () : s;
11294 // This class is used to "construct" the type during a typecast
11295 // operation. Since the Type.GetType class in .NET can parse
11296 // the type specification, we just use this to construct the type
11297 // one bit at a time.
11299 public class ComposedCast : TypeExpr {
11300 FullNamedExpression left;
11301 ComposedTypeSpecifier spec;
11303 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11306 throw new ArgumentNullException ("spec");
11310 this.loc = left.Location;
11313 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11315 type = left.ResolveAsType (ec);
11319 eclass = ExprClass.Type;
11321 var single_spec = spec;
11323 if (single_spec.IsNullable) {
11324 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11328 single_spec = single_spec.Next;
11329 } else if (single_spec.IsPointer) {
11331 // Declared fields cannot have unmanaged check done before all types are defined
11333 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11336 if (!ec.IsUnsafe) {
11337 UnsafeError (ec.Module.Compiler.Report, loc);
11341 type = PointerContainer.MakeType (ec.Module, type);
11342 single_spec = single_spec.Next;
11343 } while (single_spec != null && single_spec.IsPointer);
11346 if (single_spec != null && single_spec.Dimension > 0) {
11347 if (type.IsSpecialRuntimeType) {
11348 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11349 } else if (type.IsStatic) {
11350 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11351 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11352 type.GetSignatureForError ());
11354 MakeArray (ec.Module, single_spec);
11361 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11363 if (spec.Next != null)
11364 MakeArray (module, spec.Next);
11366 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11369 public override string GetSignatureForError ()
11371 return left.GetSignatureForError () + spec.GetSignatureForError ();
11374 public override object Accept (StructuralVisitor visitor)
11376 return visitor.Visit (this);
11380 class FixedBufferPtr : Expression
11382 readonly Expression array;
11384 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11386 this.type = array_type;
11387 this.array = array;
11391 public override bool ContainsEmitWithAwait ()
11393 throw new NotImplementedException ();
11396 public override Expression CreateExpressionTree (ResolveContext ec)
11398 Error_PointerInsideExpressionTree (ec);
11402 public override void Emit(EmitContext ec)
11407 protected override Expression DoResolve (ResolveContext ec)
11409 type = PointerContainer.MakeType (ec.Module, type);
11410 eclass = ExprClass.Value;
11417 // This class is used to represent the address of an array, used
11418 // only by the Fixed statement, this generates "&a [0]" construct
11419 // for fixed (char *pa = a)
11421 class ArrayPtr : FixedBufferPtr
11423 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11424 base (array, array_type, l)
11428 public override void Emit (EmitContext ec)
11433 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11438 // Encapsulates a conversion rules required for array indexes
11440 public class ArrayIndexCast : TypeCast
11442 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11443 : base (expr, returnType)
11445 if (expr.Type == returnType) // int -> int
11446 throw new ArgumentException ("unnecessary array index conversion");
11449 public override Expression CreateExpressionTree (ResolveContext ec)
11451 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11452 return base.CreateExpressionTree (ec);
11456 public override void Emit (EmitContext ec)
11460 switch (child.Type.BuiltinType) {
11461 case BuiltinTypeSpec.Type.UInt:
11462 ec.Emit (OpCodes.Conv_U);
11464 case BuiltinTypeSpec.Type.Long:
11465 ec.Emit (OpCodes.Conv_Ovf_I);
11467 case BuiltinTypeSpec.Type.ULong:
11468 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11471 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11477 // Implements the `stackalloc' keyword
11479 public class StackAlloc : Expression {
11484 public StackAlloc (Expression type, Expression count, Location l)
11487 this.count = count;
11491 public Expression TypeExpression {
11497 public Expression CountExpression {
11503 public override bool ContainsEmitWithAwait ()
11508 public override Expression CreateExpressionTree (ResolveContext ec)
11510 throw new NotSupportedException ("ET");
11513 protected override Expression DoResolve (ResolveContext ec)
11515 count = count.Resolve (ec);
11519 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11520 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11525 Constant c = count as Constant;
11526 if (c != null && c.IsNegative) {
11527 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11530 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11531 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11534 otype = texpr.ResolveAsType (ec);
11538 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11541 type = PointerContainer.MakeType (ec.Module, otype);
11542 eclass = ExprClass.Value;
11547 public override void Emit (EmitContext ec)
11549 int size = BuiltinTypeSpec.GetSize (otype);
11554 ec.Emit (OpCodes.Sizeof, otype);
11558 ec.Emit (OpCodes.Mul_Ovf_Un);
11559 ec.Emit (OpCodes.Localloc);
11562 protected override void CloneTo (CloneContext clonectx, Expression t)
11564 StackAlloc target = (StackAlloc) t;
11565 target.count = count.Clone (clonectx);
11566 target.texpr = texpr.Clone (clonectx);
11569 public override object Accept (StructuralVisitor visitor)
11571 return visitor.Visit (this);
11576 // An object initializer expression
11578 public class ElementInitializer : Assign
11580 public readonly string Name;
11582 public ElementInitializer (string name, Expression initializer, Location loc)
11583 : base (null, initializer, loc)
11588 public bool IsDictionaryInitializer {
11590 return Name == null;
11594 protected override void CloneTo (CloneContext clonectx, Expression t)
11596 ElementInitializer target = (ElementInitializer) t;
11597 target.source = source.Clone (clonectx);
11600 public override Expression CreateExpressionTree (ResolveContext ec)
11602 Arguments args = new Arguments (2);
11603 FieldExpr fe = target as FieldExpr;
11605 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11607 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11610 Expression arg_expr;
11611 var cinit = source as CollectionOrObjectInitializers;
11612 if (cinit == null) {
11614 arg_expr = source.CreateExpressionTree (ec);
11616 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11617 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11620 args.Add (new Argument (arg_expr));
11621 return CreateExpressionFactoryCall (ec, mname, args);
11624 protected override Expression DoResolve (ResolveContext ec)
11626 if (source == null)
11627 return EmptyExpressionStatement.Instance;
11629 if (!ResolveElement (ec))
11632 if (source is CollectionOrObjectInitializers) {
11633 target = target.Resolve (ec);
11634 if (target == null)
11637 Expression previous = ec.CurrentInitializerVariable;
11638 ec.CurrentInitializerVariable = target;
11639 source = source.Resolve (ec);
11640 ec.CurrentInitializerVariable = previous;
11641 if (source == null)
11644 eclass = source.eclass;
11645 type = source.Type;
11650 return base.DoResolve (ec);
11653 public override void EmitStatement (EmitContext ec)
11655 if (source is CollectionOrObjectInitializers)
11658 base.EmitStatement (ec);
11661 protected virtual bool ResolveElement (ResolveContext rc)
11663 var t = rc.CurrentInitializerVariable.Type;
11664 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11665 Arguments args = new Arguments (1);
11666 args.Add (new Argument (rc.CurrentInitializerVariable));
11667 target = new DynamicMemberBinder (Name, args, loc);
11670 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11671 if (member == null) {
11672 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11674 if (member != null) {
11675 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11676 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11681 if (member == null) {
11682 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11686 var me = member as MemberExpr;
11687 if (me is EventExpr) {
11688 me = me.ResolveMemberAccess (rc, null, null);
11689 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11690 rc.Report.Error (1913, loc,
11691 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11692 member.GetSignatureForError ());
11698 rc.Report.Error (1914, loc,
11699 "Static field or property `{0}' cannot be assigned in an object initializer",
11700 me.GetSignatureForError ());
11704 me.InstanceExpression = rc.CurrentInitializerVariable;
11712 // A collection initializer expression
11714 class CollectionElementInitializer : Invocation
11716 public class ElementInitializerArgument : Argument
11718 public ElementInitializerArgument (Expression e)
11724 sealed class AddMemberAccess : MemberAccess
11726 public AddMemberAccess (Expression expr, Location loc)
11727 : base (expr, "Add", loc)
11731 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11733 if (TypeManager.HasElementType (type))
11736 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11740 public CollectionElementInitializer (Expression argument)
11741 : base (null, new Arguments (1))
11743 base.arguments.Add (new ElementInitializerArgument (argument));
11744 this.loc = argument.Location;
11747 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11748 : base (null, new Arguments (arguments.Count))
11750 foreach (Expression e in arguments)
11751 base.arguments.Add (new ElementInitializerArgument (e));
11756 public CollectionElementInitializer (Location loc)
11757 : base (null, null)
11762 public override Expression CreateExpressionTree (ResolveContext ec)
11764 Arguments args = new Arguments (2);
11765 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11767 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11768 foreach (Argument a in arguments) {
11769 if (a.ArgType == Argument.AType.ExtensionType) {
11770 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11773 expr_initializers.Add (a.CreateExpressionTree (ec));
11776 args.Add (new Argument (new ArrayCreation (
11777 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11778 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11781 protected override void CloneTo (CloneContext clonectx, Expression t)
11783 CollectionElementInitializer target = (CollectionElementInitializer) t;
11784 if (arguments != null)
11785 target.arguments = arguments.Clone (clonectx);
11788 protected override Expression DoResolve (ResolveContext ec)
11790 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11792 return base.DoResolve (ec);
11796 class DictionaryElementInitializer : ElementInitializer
11798 readonly Arguments args;
11800 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11801 : base (null, initializer, loc)
11803 this.args = arguments;
11806 public override Expression CreateExpressionTree (ResolveContext ec)
11808 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11812 protected override bool ResolveElement (ResolveContext rc)
11814 var init = rc.CurrentInitializerVariable;
11815 var type = init.Type;
11817 if (type.IsArray) {
11818 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11822 if (type.IsPointer) {
11823 target = init.MakePointerAccess (rc, type, args);
11827 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11828 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11829 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11833 target = new IndexerExpr (indexers, type, init, args, loc);
11839 // A block of object or collection initializers
11841 public class CollectionOrObjectInitializers : ExpressionStatement
11843 IList<Expression> initializers;
11844 bool is_collection_initialization;
11846 public CollectionOrObjectInitializers (Location loc)
11847 : this (new Expression[0], loc)
11851 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11853 this.initializers = initializers;
11857 public IList<Expression> Initializers {
11859 return initializers;
11863 public bool IsEmpty {
11865 return initializers.Count == 0;
11869 public bool IsCollectionInitializer {
11871 return is_collection_initialization;
11875 protected override void CloneTo (CloneContext clonectx, Expression target)
11877 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11879 t.initializers = new List<Expression> (initializers.Count);
11880 foreach (var e in initializers)
11881 t.initializers.Add (e.Clone (clonectx));
11884 public override bool ContainsEmitWithAwait ()
11886 foreach (var e in initializers) {
11887 if (e.ContainsEmitWithAwait ())
11894 public override Expression CreateExpressionTree (ResolveContext ec)
11896 return CreateExpressionTree (ec, false);
11899 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11901 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11902 foreach (Expression e in initializers) {
11903 Expression expr = e.CreateExpressionTree (ec);
11905 expr_initializers.Add (expr);
11909 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11911 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11914 protected override Expression DoResolve (ResolveContext ec)
11916 List<string> element_names = null;
11917 for (int i = 0; i < initializers.Count; ++i) {
11918 Expression initializer = initializers [i];
11919 ElementInitializer element_initializer = initializer as ElementInitializer;
11922 if (element_initializer != null) {
11923 element_names = new List<string> (initializers.Count);
11924 if (!element_initializer.IsDictionaryInitializer)
11925 element_names.Add (element_initializer.Name);
11926 } else if (initializer is CompletingExpression) {
11927 initializer.Resolve (ec);
11928 throw new InternalErrorException ("This line should never be reached");
11930 var t = ec.CurrentInitializerVariable.Type;
11931 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11932 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11933 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11934 "object initializer because type `{1}' does not implement `{2}' interface",
11935 ec.CurrentInitializerVariable.GetSignatureForError (),
11936 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11937 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11940 is_collection_initialization = true;
11943 if (is_collection_initialization != (element_initializer == null)) {
11944 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11945 is_collection_initialization ? "collection initializer" : "object initializer");
11949 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11950 if (element_names.Contains (element_initializer.Name)) {
11951 ec.Report.Error (1912, element_initializer.Location,
11952 "An object initializer includes more than one member `{0}' initialization",
11953 element_initializer.Name);
11955 element_names.Add (element_initializer.Name);
11960 Expression e = initializer.Resolve (ec);
11961 if (e == EmptyExpressionStatement.Instance)
11962 initializers.RemoveAt (i--);
11964 initializers [i] = e;
11967 type = ec.CurrentInitializerVariable.Type;
11968 if (is_collection_initialization) {
11969 if (TypeManager.HasElementType (type)) {
11970 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11971 type.GetSignatureForError ());
11975 eclass = ExprClass.Variable;
11979 public override void Emit (EmitContext ec)
11981 EmitStatement (ec);
11984 public override void EmitStatement (EmitContext ec)
11986 foreach (ExpressionStatement e in initializers) {
11987 // TODO: need location region
11988 ec.Mark (e.Location);
11989 e.EmitStatement (ec);
11993 public override void FlowAnalysis (FlowAnalysisContext fc)
11995 foreach (var initializer in initializers) {
11996 if (initializer != null)
11997 initializer.FlowAnalysis (fc);
12003 // New expression with element/object initializers
12005 public class NewInitialize : New
12008 // This class serves as a proxy for variable initializer target instances.
12009 // A real variable is assigned later when we resolve left side of an
12012 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12014 NewInitialize new_instance;
12016 public InitializerTargetExpression (NewInitialize newInstance)
12018 this.type = newInstance.type;
12019 this.loc = newInstance.loc;
12020 this.eclass = newInstance.eclass;
12021 this.new_instance = newInstance;
12024 public override bool ContainsEmitWithAwait ()
12029 public override Expression CreateExpressionTree (ResolveContext ec)
12031 // Should not be reached
12032 throw new NotSupportedException ("ET");
12035 protected override Expression DoResolve (ResolveContext ec)
12040 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12045 public override void Emit (EmitContext ec)
12047 Expression e = (Expression) new_instance.instance;
12051 public override Expression EmitToField (EmitContext ec)
12053 return (Expression) new_instance.instance;
12056 #region IMemoryLocation Members
12058 public void AddressOf (EmitContext ec, AddressOp mode)
12060 new_instance.instance.AddressOf (ec, mode);
12066 CollectionOrObjectInitializers initializers;
12067 IMemoryLocation instance;
12068 DynamicExpressionStatement dynamic;
12070 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12071 : base (requested_type, arguments, l)
12073 this.initializers = initializers;
12076 public CollectionOrObjectInitializers Initializers {
12078 return initializers;
12082 protected override void CloneTo (CloneContext clonectx, Expression t)
12084 base.CloneTo (clonectx, t);
12086 NewInitialize target = (NewInitialize) t;
12087 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12090 public override bool ContainsEmitWithAwait ()
12092 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12095 public override Expression CreateExpressionTree (ResolveContext ec)
12097 Arguments args = new Arguments (2);
12098 args.Add (new Argument (base.CreateExpressionTree (ec)));
12099 if (!initializers.IsEmpty)
12100 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12102 return CreateExpressionFactoryCall (ec,
12103 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12107 protected override Expression DoResolve (ResolveContext ec)
12109 Expression e = base.DoResolve (ec);
12113 if (type.IsDelegate) {
12114 ec.Report.Error (1958, Initializers.Location,
12115 "Object and collection initializers cannot be used to instantiate a delegate");
12118 Expression previous = ec.CurrentInitializerVariable;
12119 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12120 initializers.Resolve (ec);
12121 ec.CurrentInitializerVariable = previous;
12123 dynamic = e as DynamicExpressionStatement;
12124 if (dynamic != null)
12130 public override void Emit (EmitContext ec)
12132 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12133 var fe = ec.GetTemporaryField (type);
12135 if (!Emit (ec, fe))
12144 public override bool Emit (EmitContext ec, IMemoryLocation target)
12147 // Expression is initialized into temporary target then moved
12148 // to real one for atomicity
12150 IMemoryLocation temp_target = target;
12152 LocalTemporary temp = null;
12153 bool by_ref = false;
12154 if (!initializers.IsEmpty) {
12155 temp_target = target as LocalTemporary;
12156 if (temp_target == null)
12157 temp_target = target as StackFieldExpr;
12159 if (temp_target == null) {
12160 var vr = target as VariableReference;
12161 if (vr != null && vr.IsRef) {
12167 if (temp_target == null)
12168 temp_target = temp = new LocalTemporary (type);
12171 bool left_on_stack;
12172 if (dynamic != null) {
12174 left_on_stack = true;
12176 left_on_stack = base.Emit (ec, temp_target);
12179 if (initializers.IsEmpty)
12180 return left_on_stack;
12182 StackFieldExpr sf = null;
12184 // Move a new instance (reference-type) to local temporary variable
12185 if (left_on_stack) {
12187 temp_target = temp = new LocalTemporary (type);
12193 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12195 throw new NotImplementedException ();
12197 sf = ec.GetTemporaryField (type);
12198 sf.EmitAssign (ec, temp, false, false);
12201 left_on_stack = false;
12205 instance = temp_target;
12207 initializers.Emit (ec);
12209 ((Expression)temp_target).Emit (ec);
12215 sf.IsAvailableForReuse = true;
12220 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12222 instance = base.EmitAddressOf (ec, Mode);
12224 if (!initializers.IsEmpty)
12225 initializers.Emit (ec);
12230 public override void FlowAnalysis (FlowAnalysisContext fc)
12232 base.FlowAnalysis (fc);
12233 initializers.FlowAnalysis (fc);
12236 public override object Accept (StructuralVisitor visitor)
12238 return visitor.Visit (this);
12242 public class NewAnonymousType : New
12244 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12246 List<AnonymousTypeParameter> parameters;
12247 readonly TypeContainer parent;
12248 AnonymousTypeClass anonymous_type;
12250 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12251 : base (null, null, loc)
12253 this.parameters = parameters;
12254 this.parent = parent;
12257 public List<AnonymousTypeParameter> Parameters {
12259 return this.parameters;
12263 protected override void CloneTo (CloneContext clonectx, Expression target)
12265 if (parameters == null)
12268 NewAnonymousType t = (NewAnonymousType) target;
12269 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12270 foreach (AnonymousTypeParameter atp in parameters)
12271 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12274 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12276 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12280 type = AnonymousTypeClass.Create (parent, parameters, loc);
12284 int errors = ec.Report.Errors;
12285 type.CreateContainer ();
12286 type.DefineContainer ();
12288 if ((ec.Report.Errors - errors) == 0) {
12289 parent.Module.AddAnonymousType (type);
12290 type.PrepareEmit ();
12296 public override Expression CreateExpressionTree (ResolveContext ec)
12298 if (parameters == null)
12299 return base.CreateExpressionTree (ec);
12301 var init = new ArrayInitializer (parameters.Count, loc);
12302 foreach (var m in anonymous_type.Members) {
12303 var p = m as Property;
12305 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12308 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12309 foreach (Argument a in arguments)
12310 ctor_args.Add (a.CreateExpressionTree (ec));
12312 Arguments args = new Arguments (3);
12313 args.Add (new Argument (new TypeOfMethod (method, loc)));
12314 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12315 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12317 return CreateExpressionFactoryCall (ec, "New", args);
12320 protected override Expression DoResolve (ResolveContext ec)
12322 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12323 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12327 if (parameters == null) {
12328 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12329 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12330 return base.DoResolve (ec);
12333 bool error = false;
12334 arguments = new Arguments (parameters.Count);
12335 var t_args = new TypeSpec [parameters.Count];
12336 for (int i = 0; i < parameters.Count; ++i) {
12337 Expression e = parameters [i].Resolve (ec);
12343 arguments.Add (new Argument (e));
12344 t_args [i] = e.Type;
12350 anonymous_type = CreateAnonymousType (ec, parameters);
12351 if (anonymous_type == null)
12354 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12355 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12356 eclass = ExprClass.Value;
12360 public override object Accept (StructuralVisitor visitor)
12362 return visitor.Visit (this);
12366 public class AnonymousTypeParameter : ShimExpression
12368 public readonly string Name;
12370 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12371 : base (initializer)
12377 public AnonymousTypeParameter (Parameter parameter)
12378 : base (new SimpleName (parameter.Name, parameter.Location))
12380 this.Name = parameter.Name;
12381 this.loc = parameter.Location;
12384 public override bool Equals (object o)
12386 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12387 return other != null && Name == other.Name;
12390 public override int GetHashCode ()
12392 return Name.GetHashCode ();
12395 protected override Expression DoResolve (ResolveContext ec)
12397 Expression e = expr.Resolve (ec);
12401 if (e.eclass == ExprClass.MethodGroup) {
12402 Error_InvalidInitializer (ec, e.ExprClassName);
12407 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12408 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12415 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12417 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12418 Name, initializer);
12422 public class CatchFilterExpression : BooleanExpression
12424 public CatchFilterExpression (Expression expr, Location loc)
12431 public class InterpolatedString : Expression
12433 readonly StringLiteral start, end;
12434 List<Expression> interpolations;
12435 Arguments arguments;
12437 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12439 this.start = start;
12441 this.interpolations = interpolations;
12442 loc = start.Location;
12445 protected override void CloneTo (CloneContext clonectx, Expression t)
12447 InterpolatedString target = (InterpolatedString) t;
12449 if (interpolations != null) {
12450 target.interpolations = new List<Expression> ();
12451 foreach (var interpolation in interpolations) {
12452 target.interpolations.Add (interpolation.Clone (clonectx));
12457 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12459 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12460 if (factory == null)
12463 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12464 var res = new Invocation (ma, arguments).Resolve (rc);
12465 if (res != null && res.Type != type)
12466 res = Convert.ExplicitConversion (rc, res, type, loc);
12471 public override bool ContainsEmitWithAwait ()
12473 if (interpolations == null)
12476 foreach (var expr in interpolations) {
12477 if (expr.ContainsEmitWithAwait ())
12484 public override Expression CreateExpressionTree (ResolveContext rc)
12486 var best = ResolveBestFormatOverload (rc);
12490 Expression instance = new NullLiteral (loc);
12491 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12492 return CreateExpressionFactoryCall (rc, "Call", args);
12495 protected override Expression DoResolve (ResolveContext rc)
12499 if (interpolations == null) {
12501 arguments = new Arguments (1);
12503 for (int i = 0; i < interpolations.Count; i += 2) {
12504 var ipi = (InterpolatedStringInsert)interpolations [i];
12508 arguments = new Arguments (interpolations.Count);
12510 var sb = new StringBuilder (start.Value);
12511 for (int i = 0; i < interpolations.Count; ++i) {
12513 sb.Append ('{').Append (i / 2);
12514 var isi = (InterpolatedStringInsert)interpolations [i];
12515 if (isi.Alignment != null) {
12517 var value = isi.ResolveAligment (rc);
12519 sb.Append (value.Value);
12522 if (isi.Format != null) {
12524 sb.Append (isi.Format);
12528 arguments.Add (new Argument (interpolations [i]));
12530 sb.Append (((StringLiteral)interpolations [i]).Value);
12534 sb.Append (end.Value);
12535 str = sb.ToString ();
12538 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12540 eclass = ExprClass.Value;
12541 type = rc.BuiltinTypes.String;
12545 public override void Emit (EmitContext ec)
12547 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12548 if (interpolations == null) {
12549 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12550 if (str != start.Value)
12551 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12558 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12562 var ca = new CallEmitter ();
12563 ca.Emit (ec, best, arguments, loc);
12566 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12568 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12569 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12570 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12574 public class InterpolatedStringInsert : CompositeExpression
12576 public InterpolatedStringInsert (Expression expr)
12581 public Expression Alignment { get; set; }
12582 public string Format { get; set; }
12584 protected override void CloneTo (CloneContext clonectx, Expression t)
12586 var target = (InterpolatedStringInsert)t;
12587 target.expr = expr.Clone (clonectx);
12588 if (Alignment != null)
12589 target.Alignment = Alignment.Clone (clonectx);
12592 protected override Expression DoResolve (ResolveContext rc)
12594 var expr = base.DoResolve (rc);
12599 // For better error reporting, assumes the built-in implementation uses object
12602 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12605 public int? ResolveAligment (ResolveContext rc)
12607 var c = Alignment.ResolveLabelConstant (rc);
12611 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12615 var value = (int) c.GetValueAsLong ();
12616 if (value > 32767 || value < -32767) {
12617 rc.Report.Warning (8094, 1, Alignment.Location,
12618 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");