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 if (right_const == null) {
6017 switch (rtype.BuiltinType) {
6018 case BuiltinTypeSpec.Type.SByte:
6019 case BuiltinTypeSpec.Type.Byte:
6020 case BuiltinTypeSpec.Type.Short:
6021 case BuiltinTypeSpec.Type.UShort:
6022 case BuiltinTypeSpec.Type.Int:
6023 ec.Emit (OpCodes.Conv_I);
6025 case BuiltinTypeSpec.Type.UInt:
6026 ec.Emit (OpCodes.Conv_U);
6031 if (right_const == null && size != 1){
6033 ec.Emit (OpCodes.Sizeof, element);
6036 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6037 ec.Emit (OpCodes.Conv_I8);
6039 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6042 if (left_const == null) {
6043 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6044 ec.Emit (OpCodes.Conv_I);
6045 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6046 ec.Emit (OpCodes.Conv_U);
6048 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6055 // A boolean-expression is an expression that yields a result
6058 public class BooleanExpression : ShimExpression
6060 public BooleanExpression (Expression expr)
6063 this.loc = expr.Location;
6066 public override Expression CreateExpressionTree (ResolveContext ec)
6068 // TODO: We should emit IsTrue (v4) instead of direct user operator
6069 // call but that would break csc compatibility
6070 return base.CreateExpressionTree (ec);
6073 protected override Expression DoResolve (ResolveContext ec)
6075 // A boolean-expression is required to be of a type
6076 // that can be implicitly converted to bool or of
6077 // a type that implements operator true
6079 expr = expr.Resolve (ec);
6083 Assign ass = expr as Assign;
6084 if (ass != null && ass.Source is Constant) {
6085 ec.Report.Warning (665, 3, loc,
6086 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6089 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6092 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6093 Arguments args = new Arguments (1);
6094 args.Add (new Argument (expr));
6095 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6098 type = ec.BuiltinTypes.Bool;
6099 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6100 if (converted != null)
6104 // If no implicit conversion to bool exists, try using `operator true'
6106 converted = GetOperatorTrue (ec, expr, loc);
6107 if (converted == null) {
6108 expr.Error_ValueCannotBeConverted (ec, type, false);
6115 public override object Accept (StructuralVisitor visitor)
6117 return visitor.Visit (this);
6121 public class BooleanExpressionFalse : Unary
6123 public BooleanExpressionFalse (Expression expr)
6124 : base (Operator.LogicalNot, expr, expr.Location)
6128 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6130 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6135 /// Implements the ternary conditional operator (?:)
6137 public class Conditional : Expression {
6138 Expression expr, true_expr, false_expr;
6140 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6143 this.true_expr = true_expr;
6144 this.false_expr = false_expr;
6150 public Expression Expr {
6156 public Expression TrueExpr {
6162 public Expression FalseExpr {
6170 public override bool ContainsEmitWithAwait ()
6172 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6175 public override Expression CreateExpressionTree (ResolveContext ec)
6177 Arguments args = new Arguments (3);
6178 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6179 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6180 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6181 return CreateExpressionFactoryCall (ec, "Condition", args);
6184 protected override Expression DoResolve (ResolveContext ec)
6186 expr = expr.Resolve (ec);
6187 true_expr = true_expr.Resolve (ec);
6188 false_expr = false_expr.Resolve (ec);
6190 if (true_expr == null || false_expr == null || expr == null)
6193 eclass = ExprClass.Value;
6194 TypeSpec true_type = true_expr.Type;
6195 TypeSpec false_type = false_expr.Type;
6199 // First, if an implicit conversion exists from true_expr
6200 // to false_expr, then the result type is of type false_expr.Type
6202 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6203 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6204 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6206 // Check if both can convert implicitly to each other's type
6210 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6211 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6213 // LAMESPEC: There seems to be hardcoded promotition to int type when
6214 // both sides are numeric constants and one side is int constant and
6215 // other side is numeric constant convertible to int.
6217 // var res = condition ? (short)1 : 1;
6219 // Type of res is int even if according to the spec the conversion is
6220 // ambiguous because 1 literal can be converted to short.
6222 if (conv_false_expr != null) {
6223 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6225 conv_false_expr = null;
6226 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6227 conv_false_expr = null;
6231 if (conv_false_expr != null) {
6232 ec.Report.Error (172, true_expr.Location,
6233 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6234 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6239 if (true_expr.Type != type)
6240 true_expr = EmptyCast.Create (true_expr, type);
6241 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6244 if (false_type != InternalType.ErrorType) {
6245 ec.Report.Error (173, true_expr.Location,
6246 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6247 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6253 Constant c = expr as Constant;
6255 bool is_false = c.IsDefaultValue;
6258 // Don't issue the warning for constant expressions
6260 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6261 // CSC: Missing warning
6262 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6265 return ReducedExpression.Create (
6266 is_false ? false_expr : true_expr, this,
6267 false_expr is Constant && true_expr is Constant).Resolve (ec);
6273 public override void Emit (EmitContext ec)
6275 Label false_target = ec.DefineLabel ();
6276 Label end_target = ec.DefineLabel ();
6278 expr.EmitBranchable (ec, false_target, false);
6279 true_expr.Emit (ec);
6282 // Verifier doesn't support interface merging. When there are two types on
6283 // the stack without common type hint and the common type is an interface.
6284 // Use temporary local to give verifier hint on what type to unify the stack
6286 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6287 var temp = ec.GetTemporaryLocal (type);
6288 ec.Emit (OpCodes.Stloc, temp);
6289 ec.Emit (OpCodes.Ldloc, temp);
6290 ec.FreeTemporaryLocal (temp, type);
6293 ec.Emit (OpCodes.Br, end_target);
6294 ec.MarkLabel (false_target);
6295 false_expr.Emit (ec);
6296 ec.MarkLabel (end_target);
6299 public override void FlowAnalysis (FlowAnalysisContext fc)
6301 expr.FlowAnalysisConditional (fc);
6302 var expr_true = fc.DefiniteAssignmentOnTrue;
6303 var expr_false = fc.DefiniteAssignmentOnFalse;
6305 fc.BranchDefiniteAssignment (expr_true);
6306 true_expr.FlowAnalysis (fc);
6307 var true_fc = fc.DefiniteAssignment;
6309 fc.BranchDefiniteAssignment (expr_false);
6310 false_expr.FlowAnalysis (fc);
6312 fc.DefiniteAssignment &= true_fc;
6315 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6317 expr.FlowAnalysisConditional (fc);
6318 var expr_true = fc.DefiniteAssignmentOnTrue;
6319 var expr_false = fc.DefiniteAssignmentOnFalse;
6321 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6322 true_expr.FlowAnalysisConditional (fc);
6323 var true_fc = fc.DefiniteAssignment;
6324 var true_da_true = fc.DefiniteAssignmentOnTrue;
6325 var true_da_false = fc.DefiniteAssignmentOnFalse;
6327 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6328 false_expr.FlowAnalysisConditional (fc);
6330 fc.DefiniteAssignment &= true_fc;
6331 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6332 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6335 protected override void CloneTo (CloneContext clonectx, Expression t)
6337 Conditional target = (Conditional) t;
6339 target.expr = expr.Clone (clonectx);
6340 target.true_expr = true_expr.Clone (clonectx);
6341 target.false_expr = false_expr.Clone (clonectx);
6345 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6347 LocalTemporary temp;
6350 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6351 public abstract void SetHasAddressTaken ();
6353 public abstract bool IsLockedByStatement { get; set; }
6355 public abstract bool IsFixed { get; }
6356 public abstract bool IsRef { get; }
6357 public abstract string Name { get; }
6360 // Variable IL data, it has to be protected to encapsulate hoisted variables
6362 protected abstract ILocalVariable Variable { get; }
6365 // Variable flow-analysis data
6367 public abstract VariableInfo VariableInfo { get; }
6370 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6372 HoistedVariable hv = GetHoistedVariable (ec);
6374 hv.AddressOf (ec, mode);
6378 Variable.EmitAddressOf (ec);
6381 public override bool ContainsEmitWithAwait ()
6386 public override Expression CreateExpressionTree (ResolveContext ec)
6388 HoistedVariable hv = GetHoistedVariable (ec);
6390 return hv.CreateExpressionTree ();
6392 Arguments arg = new Arguments (1);
6393 arg.Add (new Argument (this));
6394 return CreateExpressionFactoryCall (ec, "Constant", arg);
6397 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6399 if (IsLockedByStatement) {
6400 rc.Report.Warning (728, 2, loc,
6401 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6408 public override void Emit (EmitContext ec)
6413 public override void EmitSideEffect (EmitContext ec)
6419 // This method is used by parameters that are references, that are
6420 // being passed as references: we only want to pass the pointer (that
6421 // is already stored in the parameter, not the address of the pointer,
6422 // and not the value of the variable).
6424 public void EmitLoad (EmitContext ec)
6429 public void Emit (EmitContext ec, bool leave_copy)
6431 HoistedVariable hv = GetHoistedVariable (ec);
6433 hv.Emit (ec, leave_copy);
6441 // If we are a reference, we loaded on the stack a pointer
6442 // Now lets load the real value
6444 ec.EmitLoadFromPtr (type);
6448 ec.Emit (OpCodes.Dup);
6451 temp = new LocalTemporary (Type);
6457 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6458 bool prepare_for_load)
6460 HoistedVariable hv = GetHoistedVariable (ec);
6462 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6466 New n_source = source as New;
6467 if (n_source != null) {
6468 if (!n_source.Emit (ec, this)) {
6472 ec.EmitLoadFromPtr (type);
6484 ec.Emit (OpCodes.Dup);
6486 temp = new LocalTemporary (Type);
6492 ec.EmitStoreFromPtr (type);
6494 Variable.EmitAssign (ec);
6502 public override Expression EmitToField (EmitContext ec)
6504 HoistedVariable hv = GetHoistedVariable (ec);
6506 return hv.EmitToField (ec);
6509 return base.EmitToField (ec);
6512 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6514 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6517 public HoistedVariable GetHoistedVariable (EmitContext ec)
6519 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6522 public override string GetSignatureForError ()
6527 public bool IsHoisted {
6528 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6533 // Resolved reference to a local variable
6535 public class LocalVariableReference : VariableReference
6537 public LocalVariable local_info;
6539 public LocalVariableReference (LocalVariable li, Location l)
6541 this.local_info = li;
6545 public override VariableInfo VariableInfo {
6546 get { return local_info.VariableInfo; }
6549 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6551 return local_info.HoistedVariant;
6557 // A local variable is always fixed
6559 public override bool IsFixed {
6565 public override bool IsLockedByStatement {
6567 return local_info.IsLocked;
6570 local_info.IsLocked = value;
6574 public override bool IsRef {
6575 get { return false; }
6578 public override string Name {
6579 get { return local_info.Name; }
6584 public override void FlowAnalysis (FlowAnalysisContext fc)
6586 VariableInfo variable_info = VariableInfo;
6587 if (variable_info == null)
6590 if (fc.IsDefinitelyAssigned (variable_info))
6593 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6594 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6597 public override void SetHasAddressTaken ()
6599 local_info.SetHasAddressTaken ();
6602 void DoResolveBase (ResolveContext ec)
6604 eclass = ExprClass.Variable;
6605 type = local_info.Type;
6608 // If we are referencing a variable from the external block
6609 // flag it for capturing
6611 if (ec.MustCaptureVariable (local_info)) {
6612 if (local_info.AddressTaken) {
6613 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6614 } else if (local_info.IsFixed) {
6615 ec.Report.Error (1764, loc,
6616 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6617 GetSignatureForError ());
6620 if (ec.IsVariableCapturingRequired) {
6621 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6622 storey.CaptureLocalVariable (ec, local_info);
6627 protected override Expression DoResolve (ResolveContext ec)
6629 local_info.SetIsUsed ();
6633 if (local_info.Type == InternalType.VarOutType) {
6634 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6635 GetSignatureForError ());
6637 type = InternalType.ErrorType;
6643 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6646 // Don't be too pedantic when variable is used as out param or for some broken code
6647 // which uses property/indexer access to run some initialization
6649 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6650 local_info.SetIsUsed ();
6652 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6653 if (rhs == EmptyExpression.LValueMemberAccess) {
6654 // CS1654 already reported
6658 if (rhs == EmptyExpression.OutAccess) {
6659 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6660 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6661 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6662 } else if (rhs == EmptyExpression.UnaryAddress) {
6663 code = 459; msg = "Cannot take the address of {1} `{0}'";
6665 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6667 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6671 if (eclass == ExprClass.Unresolved)
6674 return base.DoResolveLValue (ec, rhs);
6677 public override int GetHashCode ()
6679 return local_info.GetHashCode ();
6682 public override bool Equals (object obj)
6684 LocalVariableReference lvr = obj as LocalVariableReference;
6688 return local_info == lvr.local_info;
6691 protected override ILocalVariable Variable {
6692 get { return local_info; }
6695 public override string ToString ()
6697 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6700 protected override void CloneTo (CloneContext clonectx, Expression t)
6707 /// This represents a reference to a parameter in the intermediate
6710 public class ParameterReference : VariableReference
6712 protected ParametersBlock.ParameterInfo pi;
6714 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6722 public override bool IsLockedByStatement {
6727 pi.IsLocked = value;
6731 public override bool IsRef {
6732 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6735 bool HasOutModifier {
6736 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6739 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6741 return pi.Parameter.HoistedVariant;
6745 // A ref or out parameter is classified as a moveable variable, even
6746 // if the argument given for the parameter is a fixed variable
6748 public override bool IsFixed {
6749 get { return !IsRef; }
6752 public override string Name {
6753 get { return Parameter.Name; }
6756 public Parameter Parameter {
6757 get { return pi.Parameter; }
6760 public override VariableInfo VariableInfo {
6761 get { return pi.VariableInfo; }
6764 protected override ILocalVariable Variable {
6765 get { return Parameter; }
6770 public override void AddressOf (EmitContext ec, AddressOp mode)
6773 // ParameterReferences might already be a reference
6780 base.AddressOf (ec, mode);
6783 public override void SetHasAddressTaken ()
6785 Parameter.HasAddressTaken = true;
6788 bool DoResolveBase (ResolveContext ec)
6790 if (eclass != ExprClass.Unresolved)
6793 type = pi.ParameterType;
6794 eclass = ExprClass.Variable;
6797 // If we are referencing a parameter from the external block
6798 // flag it for capturing
6800 if (ec.MustCaptureVariable (pi)) {
6801 if (Parameter.HasAddressTaken)
6802 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6805 ec.Report.Error (1628, loc,
6806 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6807 Name, ec.CurrentAnonymousMethod.ContainerType);
6810 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6811 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6812 storey.CaptureParameter (ec, pi, this);
6819 public override int GetHashCode ()
6821 return Name.GetHashCode ();
6824 public override bool Equals (object obj)
6826 ParameterReference pr = obj as ParameterReference;
6830 return Name == pr.Name;
6833 protected override void CloneTo (CloneContext clonectx, Expression target)
6839 public override Expression CreateExpressionTree (ResolveContext ec)
6841 HoistedVariable hv = GetHoistedVariable (ec);
6843 return hv.CreateExpressionTree ();
6845 return Parameter.ExpressionTreeVariableReference ();
6848 protected override Expression DoResolve (ResolveContext ec)
6850 if (!DoResolveBase (ec))
6856 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6858 if (!DoResolveBase (ec))
6861 if (Parameter.HoistedVariant != null)
6862 Parameter.HoistedVariant.IsAssigned = true;
6864 return base.DoResolveLValue (ec, right_side);
6867 public override void FlowAnalysis (FlowAnalysisContext fc)
6869 VariableInfo variable_info = VariableInfo;
6870 if (variable_info == null)
6873 if (fc.IsDefinitelyAssigned (variable_info))
6876 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6877 fc.SetVariableAssigned (variable_info);
6882 /// Invocation of methods or delegates.
6884 public class Invocation : ExpressionStatement
6886 public class Predefined : Invocation
6888 public Predefined (MethodGroupExpr expr, Arguments arguments)
6889 : base (expr, arguments)
6894 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6896 mg.BestCandidate.CheckObsoleteness (rc, loc);
6902 protected Arguments arguments;
6903 protected Expression expr;
6904 protected MethodGroupExpr mg;
6905 bool conditional_access_receiver;
6907 public Invocation (Expression expr, Arguments arguments)
6910 this.arguments = arguments;
6912 loc = expr.Location;
6917 public Arguments Arguments {
6923 public Expression Exp {
6929 public MethodGroupExpr MethodGroup {
6935 public override Location StartLocation {
6937 return expr.StartLocation;
6943 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6945 if (MethodGroup == null)
6948 var candidate = MethodGroup.BestCandidate;
6949 if (candidate == null || !(candidate.IsStatic || Exp is This))
6952 var args_count = arguments == null ? 0 : arguments.Count;
6953 if (args_count != body.Parameters.Count)
6956 var lambda_parameters = body.Block.Parameters.FixedParameters;
6957 for (int i = 0; i < args_count; ++i) {
6958 var pr = arguments[i].Expr as ParameterReference;
6962 if (lambda_parameters[i] != pr.Parameter)
6965 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6969 var emg = MethodGroup as ExtensionMethodGroupExpr;
6971 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6972 if (candidate.IsGeneric) {
6973 var targs = new TypeExpression [candidate.Arity];
6974 for (int i = 0; i < targs.Length; ++i) {
6975 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6978 mg.SetTypeArguments (null, new TypeArguments (targs));
6987 protected override void CloneTo (CloneContext clonectx, Expression t)
6989 Invocation target = (Invocation) t;
6991 if (arguments != null)
6992 target.arguments = arguments.Clone (clonectx);
6994 target.expr = expr.Clone (clonectx);
6997 public override bool ContainsEmitWithAwait ()
6999 if (arguments != null && arguments.ContainsEmitWithAwait ())
7002 return mg.ContainsEmitWithAwait ();
7005 public override Expression CreateExpressionTree (ResolveContext ec)
7007 Expression instance = mg.IsInstance ?
7008 mg.InstanceExpression.CreateExpressionTree (ec) :
7009 new NullLiteral (loc);
7011 var args = Arguments.CreateForExpressionTree (ec, arguments,
7013 mg.CreateExpressionTree (ec));
7015 return CreateExpressionFactoryCall (ec, "Call", args);
7018 void ResolveConditionalAccessReceiver (ResolveContext rc)
7020 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7021 conditional_access_receiver = true;
7025 protected override Expression DoResolve (ResolveContext rc)
7027 ResolveConditionalAccessReceiver (rc);
7028 return DoResolveInvocation (rc);
7031 Expression DoResolveInvocation (ResolveContext ec)
7033 Expression member_expr;
7034 var atn = expr as ATypeNameExpression;
7036 var flags = default (ResolveContext.FlagsHandle);
7037 if (conditional_access_receiver)
7038 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7041 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7042 if (member_expr != null) {
7043 var name_of = member_expr as NameOf;
7044 if (name_of != null) {
7045 return name_of.ResolveOverload (ec, arguments);
7048 member_expr = member_expr.Resolve (ec);
7051 member_expr = expr.Resolve (ec);
7054 if (conditional_access_receiver)
7057 if (member_expr == null)
7061 // Next, evaluate all the expressions in the argument list
7063 bool dynamic_arg = false;
7064 if (arguments != null) {
7065 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7066 arguments.Resolve (ec, out dynamic_arg);
7070 TypeSpec expr_type = member_expr.Type;
7071 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7072 return DoResolveDynamic (ec, member_expr);
7074 mg = member_expr as MethodGroupExpr;
7075 Expression invoke = null;
7078 if (expr_type != null && expr_type.IsDelegate) {
7079 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7080 invoke = invoke.Resolve (ec);
7081 if (invoke == null || !dynamic_arg)
7084 if (member_expr is RuntimeValueExpression) {
7085 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7086 member_expr.Type.GetSignatureForError ());
7090 MemberExpr me = member_expr as MemberExpr;
7092 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7096 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7097 member_expr.GetSignatureForError ());
7102 if (invoke == null) {
7103 mg = DoResolveOverload (ec);
7109 return DoResolveDynamic (ec, member_expr);
7111 var method = mg.BestCandidate;
7112 type = mg.BestCandidateReturnType;
7113 if (conditional_access_receiver)
7114 type = LiftMemberType (ec, type);
7116 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7118 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7120 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7124 IsSpecialMethodInvocation (ec, method, loc);
7126 eclass = ExprClass.Value;
7130 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7133 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7135 args = dmb.Arguments;
7136 if (arguments != null)
7137 args.AddRange (arguments);
7138 } else if (mg == null) {
7139 if (arguments == null)
7140 args = new Arguments (1);
7144 args.Insert (0, new Argument (memberExpr));
7148 ec.Report.Error (1971, loc,
7149 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7154 if (arguments == null)
7155 args = new Arguments (1);
7159 MemberAccess ma = expr as MemberAccess;
7161 var inst = mg.InstanceExpression;
7162 var left_type = inst as TypeExpr;
7163 if (left_type != null) {
7164 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7165 } else if (inst != null) {
7167 // Any value type has to be pass as by-ref to get back the same
7168 // instance on which the member was called
7170 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7171 Argument.AType.Ref : Argument.AType.None;
7172 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7174 } else { // is SimpleName
7176 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7178 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7183 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7186 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7188 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7191 public override void FlowAnalysis (FlowAnalysisContext fc)
7193 if (mg.IsConditionallyExcluded)
7196 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7198 mg.FlowAnalysis (fc);
7200 if (arguments != null)
7201 arguments.FlowAnalysis (fc);
7203 if (conditional_access_receiver)
7204 fc.DefiniteAssignment = da;
7207 public override string GetSignatureForError ()
7209 return mg.GetSignatureForError ();
7212 public override bool HasConditionalAccess ()
7214 return expr.HasConditionalAccess ();
7218 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7219 // or the type dynamic, then the member is invocable
7221 public static bool IsMemberInvocable (MemberSpec member)
7223 switch (member.Kind) {
7224 case MemberKind.Event:
7226 case MemberKind.Field:
7227 case MemberKind.Property:
7228 var m = member as IInterfaceMemberSpec;
7229 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7235 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7237 if (!method.IsReservedMethod)
7240 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7243 ec.Report.SymbolRelatedToPreviousError (method);
7244 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7245 method.GetSignatureForError ());
7250 public override void Emit (EmitContext ec)
7252 if (mg.IsConditionallyExcluded)
7255 if (conditional_access_receiver)
7256 mg.EmitCall (ec, arguments, type, false);
7258 mg.EmitCall (ec, arguments, false);
7261 public override void EmitStatement (EmitContext ec)
7263 if (mg.IsConditionallyExcluded)
7266 if (conditional_access_receiver)
7267 mg.EmitCall (ec, arguments, type, true);
7269 mg.EmitCall (ec, arguments, true);
7272 public override SLE.Expression MakeExpression (BuilderContext ctx)
7274 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7277 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7280 throw new NotSupportedException ();
7282 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7283 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7287 public override object Accept (StructuralVisitor visitor)
7289 return visitor.Visit (this);
7294 // Implements simple new expression
7296 public class New : ExpressionStatement, IMemoryLocation
7298 protected Arguments arguments;
7301 // During bootstrap, it contains the RequestedType,
7302 // but if `type' is not null, it *might* contain a NewDelegate
7303 // (because of field multi-initialization)
7305 protected Expression RequestedType;
7307 protected MethodSpec method;
7309 public New (Expression requested_type, Arguments arguments, Location l)
7311 RequestedType = requested_type;
7312 this.arguments = arguments;
7317 public Arguments Arguments {
7324 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7326 public bool IsGeneratedStructConstructor {
7328 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7332 public Expression TypeExpression {
7334 return RequestedType;
7341 /// Converts complex core type syntax like 'new int ()' to simple constant
7343 public static Constant Constantify (TypeSpec t, Location loc)
7345 switch (t.BuiltinType) {
7346 case BuiltinTypeSpec.Type.Int:
7347 return new IntConstant (t, 0, loc);
7348 case BuiltinTypeSpec.Type.UInt:
7349 return new UIntConstant (t, 0, loc);
7350 case BuiltinTypeSpec.Type.Long:
7351 return new LongConstant (t, 0, loc);
7352 case BuiltinTypeSpec.Type.ULong:
7353 return new ULongConstant (t, 0, loc);
7354 case BuiltinTypeSpec.Type.Float:
7355 return new FloatConstant (t, 0, loc);
7356 case BuiltinTypeSpec.Type.Double:
7357 return new DoubleConstant (t, 0, loc);
7358 case BuiltinTypeSpec.Type.Short:
7359 return new ShortConstant (t, 0, loc);
7360 case BuiltinTypeSpec.Type.UShort:
7361 return new UShortConstant (t, 0, loc);
7362 case BuiltinTypeSpec.Type.SByte:
7363 return new SByteConstant (t, 0, loc);
7364 case BuiltinTypeSpec.Type.Byte:
7365 return new ByteConstant (t, 0, loc);
7366 case BuiltinTypeSpec.Type.Char:
7367 return new CharConstant (t, '\0', loc);
7368 case BuiltinTypeSpec.Type.Bool:
7369 return new BoolConstant (t, false, loc);
7370 case BuiltinTypeSpec.Type.Decimal:
7371 return new DecimalConstant (t, 0, loc);
7375 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7377 if (t.IsNullableType)
7378 return Nullable.LiftedNull.Create (t, loc);
7383 public override bool ContainsEmitWithAwait ()
7385 return arguments != null && arguments.ContainsEmitWithAwait ();
7389 // Checks whether the type is an interface that has the
7390 // [ComImport, CoClass] attributes and must be treated
7393 public Expression CheckComImport (ResolveContext ec)
7395 if (!type.IsInterface)
7399 // Turn the call into:
7400 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7402 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7403 if (real_class == null)
7406 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7407 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7408 return cast.Resolve (ec);
7411 public override Expression CreateExpressionTree (ResolveContext ec)
7414 if (method == null) {
7415 args = new Arguments (1);
7416 args.Add (new Argument (new TypeOf (type, loc)));
7418 args = Arguments.CreateForExpressionTree (ec,
7419 arguments, new TypeOfMethod (method, loc));
7422 return CreateExpressionFactoryCall (ec, "New", args);
7425 protected override Expression DoResolve (ResolveContext ec)
7427 type = RequestedType.ResolveAsType (ec);
7431 eclass = ExprClass.Value;
7433 if (type.IsPointer) {
7434 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7435 type.GetSignatureForError ());
7439 if (arguments == null) {
7440 Constant c = Constantify (type, RequestedType.Location);
7442 return ReducedExpression.Create (c, this);
7445 if (type.IsDelegate) {
7446 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7449 var tparam = type as TypeParameterSpec;
7450 if (tparam != null) {
7452 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7453 // where type parameter constraint is inflated to struct
7455 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7456 ec.Report.Error (304, loc,
7457 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7458 type.GetSignatureForError ());
7461 if ((arguments != null) && (arguments.Count != 0)) {
7462 ec.Report.Error (417, loc,
7463 "`{0}': cannot provide arguments when creating an instance of a variable type",
7464 type.GetSignatureForError ());
7470 if (type.IsStatic) {
7471 ec.Report.SymbolRelatedToPreviousError (type);
7472 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7476 if (type.IsInterface || type.IsAbstract){
7477 if (!TypeManager.IsGenericType (type)) {
7478 RequestedType = CheckComImport (ec);
7479 if (RequestedType != null)
7480 return RequestedType;
7483 ec.Report.SymbolRelatedToPreviousError (type);
7484 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7489 if (arguments != null) {
7490 arguments.Resolve (ec, out dynamic);
7495 method = ConstructorLookup (ec, type, ref arguments, loc);
7498 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7499 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7505 void DoEmitTypeParameter (EmitContext ec)
7507 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7511 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7512 ec.Emit (OpCodes.Call, ctor_factory);
7516 // This Emit can be invoked in two contexts:
7517 // * As a mechanism that will leave a value on the stack (new object)
7518 // * As one that wont (init struct)
7520 // If we are dealing with a ValueType, we have a few
7521 // situations to deal with:
7523 // * The target is a ValueType, and we have been provided
7524 // the instance (this is easy, we are being assigned).
7526 // * The target of New is being passed as an argument,
7527 // to a boxing operation or a function that takes a
7530 // In this case, we need to create a temporary variable
7531 // that is the argument of New.
7533 // Returns whether a value is left on the stack
7535 // *** Implementation note ***
7537 // To benefit from this optimization, each assignable expression
7538 // has to manually cast to New and call this Emit.
7540 // TODO: It's worth to implement it for arrays and fields
7542 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7544 bool is_value_type = type.IsStructOrEnum;
7545 VariableReference vr = target as VariableReference;
7547 if (target != null && is_value_type && (vr != null || method == null)) {
7548 target.AddressOf (ec, AddressOp.Store);
7549 } else if (vr != null && vr.IsRef) {
7553 if (arguments != null) {
7554 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7555 arguments = arguments.Emit (ec, false, true);
7557 arguments.Emit (ec);
7560 if (is_value_type) {
7561 if (method == null) {
7562 ec.Emit (OpCodes.Initobj, type);
7567 ec.MarkCallEntry (loc);
7568 ec.Emit (OpCodes.Call, method);
7573 if (type is TypeParameterSpec) {
7574 DoEmitTypeParameter (ec);
7578 ec.MarkCallEntry (loc);
7579 ec.Emit (OpCodes.Newobj, method);
7583 public override void Emit (EmitContext ec)
7585 LocalTemporary v = null;
7586 if (method == null && type.IsStructOrEnum) {
7587 // TODO: Use temporary variable from pool
7588 v = new LocalTemporary (type);
7595 public override void EmitStatement (EmitContext ec)
7597 LocalTemporary v = null;
7598 if (method == null && TypeSpec.IsValueType (type)) {
7599 // TODO: Use temporary variable from pool
7600 v = new LocalTemporary (type);
7604 ec.Emit (OpCodes.Pop);
7607 public override void FlowAnalysis (FlowAnalysisContext fc)
7609 if (arguments != null)
7610 arguments.FlowAnalysis (fc);
7613 public void AddressOf (EmitContext ec, AddressOp mode)
7615 EmitAddressOf (ec, mode);
7618 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7620 LocalTemporary value_target = new LocalTemporary (type);
7622 if (type is TypeParameterSpec) {
7623 DoEmitTypeParameter (ec);
7624 value_target.Store (ec);
7625 value_target.AddressOf (ec, mode);
7626 return value_target;
7629 value_target.AddressOf (ec, AddressOp.Store);
7631 if (method == null) {
7632 ec.Emit (OpCodes.Initobj, type);
7634 if (arguments != null)
7635 arguments.Emit (ec);
7637 ec.Emit (OpCodes.Call, method);
7640 value_target.AddressOf (ec, mode);
7641 return value_target;
7644 protected override void CloneTo (CloneContext clonectx, Expression t)
7646 New target = (New) t;
7648 target.RequestedType = RequestedType.Clone (clonectx);
7649 if (arguments != null){
7650 target.arguments = arguments.Clone (clonectx);
7654 public override SLE.Expression MakeExpression (BuilderContext ctx)
7657 return base.MakeExpression (ctx);
7659 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7663 public override object Accept (StructuralVisitor visitor)
7665 return visitor.Visit (this);
7670 // Array initializer expression, the expression is allowed in
7671 // variable or field initialization only which makes it tricky as
7672 // the type has to be infered based on the context either from field
7673 // type or variable type (think of multiple declarators)
7675 public class ArrayInitializer : Expression
7677 List<Expression> elements;
7678 BlockVariable variable;
7680 public ArrayInitializer (List<Expression> init, Location loc)
7686 public ArrayInitializer (int count, Location loc)
7687 : this (new List<Expression> (count), loc)
7691 public ArrayInitializer (Location loc)
7699 get { return elements.Count; }
7702 public List<Expression> Elements {
7708 public Expression this [int index] {
7710 return elements [index];
7714 public BlockVariable VariableDeclaration {
7725 public void Add (Expression expr)
7727 elements.Add (expr);
7730 public override bool ContainsEmitWithAwait ()
7732 throw new NotSupportedException ();
7735 public override Expression CreateExpressionTree (ResolveContext ec)
7737 throw new NotSupportedException ("ET");
7740 protected override void CloneTo (CloneContext clonectx, Expression t)
7742 var target = (ArrayInitializer) t;
7744 target.elements = new List<Expression> (elements.Count);
7745 foreach (var element in elements)
7746 target.elements.Add (element.Clone (clonectx));
7749 protected override Expression DoResolve (ResolveContext rc)
7751 var current_field = rc.CurrentMemberDefinition as FieldBase;
7752 TypeExpression type;
7753 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7754 type = new TypeExpression (current_field.MemberType, current_field.Location);
7755 } else if (variable != null) {
7756 if (variable.TypeExpression is VarExpr) {
7757 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7758 return EmptyExpression.Null;
7761 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7763 throw new NotImplementedException ("Unexpected array initializer context");
7766 return new ArrayCreation (type, this).Resolve (rc);
7769 public override void Emit (EmitContext ec)
7771 throw new InternalErrorException ("Missing Resolve call");
7774 public override void FlowAnalysis (FlowAnalysisContext fc)
7776 throw new InternalErrorException ("Missing Resolve call");
7779 public override object Accept (StructuralVisitor visitor)
7781 return visitor.Visit (this);
7786 /// 14.5.10.2: Represents an array creation expression.
7790 /// There are two possible scenarios here: one is an array creation
7791 /// expression that specifies the dimensions and optionally the
7792 /// initialization data and the other which does not need dimensions
7793 /// specified but where initialization data is mandatory.
7795 public class ArrayCreation : Expression
7797 FullNamedExpression requested_base_type;
7798 ArrayInitializer initializers;
7801 // The list of Argument types.
7802 // This is used to construct the `newarray' or constructor signature
7804 protected List<Expression> arguments;
7806 protected TypeSpec array_element_type;
7808 protected int dimensions;
7809 protected readonly ComposedTypeSpecifier rank;
7810 Expression first_emit;
7811 LocalTemporary first_emit_temp;
7813 protected List<Expression> array_data;
7815 Dictionary<int, int> bounds;
7818 // The number of constants in array initializers
7819 int const_initializers_count;
7820 bool only_constant_initializers;
7822 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7823 : this (requested_base_type, rank, initializers, l)
7825 arguments = new List<Expression> (exprs);
7826 num_arguments = arguments.Count;
7830 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7832 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7834 this.requested_base_type = requested_base_type;
7836 this.initializers = initializers;
7840 num_arguments = rank.Dimension;
7844 // For compiler generated single dimensional arrays only
7846 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7847 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7852 // For expressions like int[] foo = { 1, 2, 3 };
7854 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7855 : this (requested_base_type, null, initializers, initializers.Location)
7859 public ComposedTypeSpecifier Rank {
7865 public FullNamedExpression TypeExpression {
7867 return this.requested_base_type;
7871 public ArrayInitializer Initializers {
7873 return this.initializers;
7877 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7879 if (initializers != null && bounds == null) {
7881 // We use this to store all the data values in the order in which we
7882 // will need to store them in the byte blob later
7884 array_data = new List<Expression> (probe.Count);
7885 bounds = new Dictionary<int, int> ();
7888 if (specified_dims) {
7889 Expression a = arguments [idx];
7894 a = ConvertExpressionToArrayIndex (ec, a);
7900 if (initializers != null) {
7901 Constant c = a as Constant;
7902 if (c == null && a is ArrayIndexCast)
7903 c = ((ArrayIndexCast) a).Child as Constant;
7906 ec.Report.Error (150, a.Location, "A constant value is expected");
7912 value = System.Convert.ToInt32 (c.GetValue ());
7914 ec.Report.Error (150, a.Location, "A constant value is expected");
7918 // TODO: probe.Count does not fit ulong in
7919 if (value != probe.Count) {
7920 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7924 bounds[idx] = value;
7928 if (initializers == null)
7931 for (int i = 0; i < probe.Count; ++i) {
7933 if (o is ArrayInitializer) {
7934 var sub_probe = o as ArrayInitializer;
7935 if (idx + 1 >= dimensions){
7936 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7940 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7941 if (!bounds.ContainsKey(idx + 1))
7942 bounds[idx + 1] = sub_probe.Count;
7944 if (bounds[idx + 1] != sub_probe.Count) {
7945 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7949 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7952 } else if (child_bounds > 1) {
7953 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7955 Expression element = ResolveArrayElement (ec, o);
7956 if (element == null)
7959 // Initializers with the default values can be ignored
7960 Constant c = element as Constant;
7962 if (!c.IsDefaultInitializer (array_element_type)) {
7963 ++const_initializers_count;
7966 only_constant_initializers = false;
7969 array_data.Add (element);
7976 public override bool ContainsEmitWithAwait ()
7978 foreach (var arg in arguments) {
7979 if (arg.ContainsEmitWithAwait ())
7983 return InitializersContainAwait ();
7986 public override Expression CreateExpressionTree (ResolveContext ec)
7990 if (array_data == null) {
7991 args = new Arguments (arguments.Count + 1);
7992 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7993 foreach (Expression a in arguments)
7994 args.Add (new Argument (a.CreateExpressionTree (ec)));
7996 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7999 if (dimensions > 1) {
8000 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8004 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8005 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8006 if (array_data != null) {
8007 for (int i = 0; i < array_data.Count; ++i) {
8008 Expression e = array_data [i];
8009 args.Add (new Argument (e.CreateExpressionTree (ec)));
8013 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8016 void UpdateIndices (ResolveContext rc)
8019 for (var probe = initializers; probe != null;) {
8020 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8022 bounds[i++] = probe.Count;
8024 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8025 probe = (ArrayInitializer) probe[0];
8026 } else if (dimensions > i) {
8034 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8036 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8039 public override void FlowAnalysis (FlowAnalysisContext fc)
8041 foreach (var arg in arguments)
8042 arg.FlowAnalysis (fc);
8044 if (array_data != null) {
8045 foreach (var ad in array_data)
8046 ad.FlowAnalysis (fc);
8050 bool InitializersContainAwait ()
8052 if (array_data == null)
8055 foreach (var expr in array_data) {
8056 if (expr.ContainsEmitWithAwait ())
8063 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8065 element = element.Resolve (ec);
8066 if (element == null)
8069 if (element is CompoundAssign.TargetExpression) {
8070 if (first_emit != null)
8071 throw new InternalErrorException ("Can only handle one mutator at a time");
8072 first_emit = element;
8073 element = first_emit_temp = new LocalTemporary (element.Type);
8076 return Convert.ImplicitConversionRequired (
8077 ec, element, array_element_type, loc);
8080 protected bool ResolveInitializers (ResolveContext ec)
8083 only_constant_initializers = true;
8086 if (arguments != null) {
8088 for (int i = 0; i < arguments.Count; ++i) {
8089 res &= CheckIndices (ec, initializers, i, true, dimensions);
8090 if (initializers != null)
8097 arguments = new List<Expression> ();
8099 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8108 // Resolved the type of the array
8110 bool ResolveArrayType (ResolveContext ec)
8115 FullNamedExpression array_type_expr;
8116 if (num_arguments > 0) {
8117 array_type_expr = new ComposedCast (requested_base_type, rank);
8119 array_type_expr = requested_base_type;
8122 type = array_type_expr.ResolveAsType (ec);
8123 if (array_type_expr == null)
8126 var ac = type as ArrayContainer;
8128 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8132 array_element_type = ac.Element;
8133 dimensions = ac.Rank;
8138 protected override Expression DoResolve (ResolveContext ec)
8143 if (!ResolveArrayType (ec))
8147 // validate the initializers and fill in any missing bits
8149 if (!ResolveInitializers (ec))
8152 eclass = ExprClass.Value;
8156 byte [] MakeByteBlob ()
8161 int count = array_data.Count;
8163 TypeSpec element_type = array_element_type;
8164 if (element_type.IsEnum)
8165 element_type = EnumSpec.GetUnderlyingType (element_type);
8167 factor = BuiltinTypeSpec.GetSize (element_type);
8169 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8171 data = new byte [(count * factor + 3) & ~3];
8174 for (int i = 0; i < count; ++i) {
8175 var c = array_data[i] as Constant;
8181 object v = c.GetValue ();
8183 switch (element_type.BuiltinType) {
8184 case BuiltinTypeSpec.Type.Long:
8185 long lval = (long) v;
8187 for (int j = 0; j < factor; ++j) {
8188 data[idx + j] = (byte) (lval & 0xFF);
8192 case BuiltinTypeSpec.Type.ULong:
8193 ulong ulval = (ulong) v;
8195 for (int j = 0; j < factor; ++j) {
8196 data[idx + j] = (byte) (ulval & 0xFF);
8197 ulval = (ulval >> 8);
8200 case BuiltinTypeSpec.Type.Float:
8201 var fval = SingleConverter.SingleToInt32Bits((float) v);
8203 data[idx] = (byte) (fval & 0xff);
8204 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8205 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8206 data[idx + 3] = (byte) (fval >> 24);
8208 case BuiltinTypeSpec.Type.Double:
8209 element = BitConverter.GetBytes ((double) v);
8211 for (int j = 0; j < factor; ++j)
8212 data[idx + j] = element[j];
8214 // FIXME: Handle the ARM float format.
8215 if (!BitConverter.IsLittleEndian)
8216 System.Array.Reverse (data, idx, 8);
8218 case BuiltinTypeSpec.Type.Char:
8219 int chval = (int) ((char) v);
8221 data[idx] = (byte) (chval & 0xff);
8222 data[idx + 1] = (byte) (chval >> 8);
8224 case BuiltinTypeSpec.Type.Short:
8225 int sval = (int) ((short) v);
8227 data[idx] = (byte) (sval & 0xff);
8228 data[idx + 1] = (byte) (sval >> 8);
8230 case BuiltinTypeSpec.Type.UShort:
8231 int usval = (int) ((ushort) v);
8233 data[idx] = (byte) (usval & 0xff);
8234 data[idx + 1] = (byte) (usval >> 8);
8236 case BuiltinTypeSpec.Type.Int:
8239 data[idx] = (byte) (val & 0xff);
8240 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8241 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8242 data[idx + 3] = (byte) (val >> 24);
8244 case BuiltinTypeSpec.Type.UInt:
8245 uint uval = (uint) v;
8247 data[idx] = (byte) (uval & 0xff);
8248 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8249 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8250 data[idx + 3] = (byte) (uval >> 24);
8252 case BuiltinTypeSpec.Type.SByte:
8253 data[idx] = (byte) (sbyte) v;
8255 case BuiltinTypeSpec.Type.Byte:
8256 data[idx] = (byte) v;
8258 case BuiltinTypeSpec.Type.Bool:
8259 data[idx] = (byte) ((bool) v ? 1 : 0);
8261 case BuiltinTypeSpec.Type.Decimal:
8262 int[] bits = Decimal.GetBits ((decimal) v);
8265 // FIXME: For some reason, this doesn't work on the MS runtime.
8266 int[] nbits = new int[4];
8272 for (int j = 0; j < 4; j++) {
8273 data[p++] = (byte) (nbits[j] & 0xff);
8274 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8275 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8276 data[p++] = (byte) (nbits[j] >> 24);
8280 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8289 public override SLE.Expression MakeExpression (BuilderContext ctx)
8292 return base.MakeExpression (ctx);
8294 var initializers = new SLE.Expression [array_data.Count];
8295 for (var i = 0; i < initializers.Length; i++) {
8296 if (array_data [i] == null)
8297 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8299 initializers [i] = array_data [i].MakeExpression (ctx);
8302 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8307 // Emits the initializers for the array
8309 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8311 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8316 // First, the static data
8318 byte [] data = MakeByteBlob ();
8319 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8321 if (stackArray == null) {
8322 ec.Emit (OpCodes.Dup);
8324 stackArray.Emit (ec);
8327 ec.Emit (OpCodes.Ldtoken, fb);
8328 ec.Emit (OpCodes.Call, m);
8333 // Emits pieces of the array that can not be computed at compile
8334 // time (variables and string locations).
8336 // This always expect the top value on the stack to be the array
8338 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8340 int dims = bounds.Count;
8341 var current_pos = new int [dims];
8343 for (int i = 0; i < array_data.Count; i++){
8345 Expression e = array_data [i];
8346 var c = e as Constant;
8348 // Constant can be initialized via StaticInitializer
8349 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8353 if (stackArray != null) {
8354 if (e.ContainsEmitWithAwait ()) {
8355 e = e.EmitToField (ec);
8358 stackArray.EmitLoad (ec);
8360 ec.Emit (OpCodes.Dup);
8363 for (int idx = 0; idx < dims; idx++)
8364 ec.EmitInt (current_pos [idx]);
8367 // If we are dealing with a struct, get the
8368 // address of it, so we can store it.
8370 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8371 ec.Emit (OpCodes.Ldelema, etype);
8375 ec.EmitArrayStore ((ArrayContainer) type);
8381 for (int j = dims - 1; j >= 0; j--){
8383 if (current_pos [j] < bounds [j])
8385 current_pos [j] = 0;
8389 if (stackArray != null)
8390 stackArray.PrepareCleanup (ec);
8393 public override void Emit (EmitContext ec)
8395 var await_field = EmitToFieldSource (ec);
8396 if (await_field != null)
8397 await_field.Emit (ec);
8400 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8402 if (first_emit != null) {
8403 first_emit.Emit (ec);
8404 first_emit_temp.Store (ec);
8407 StackFieldExpr await_stack_field;
8408 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8409 await_stack_field = ec.GetTemporaryField (type);
8412 await_stack_field = null;
8415 EmitExpressionsList (ec, arguments);
8417 ec.EmitArrayNew ((ArrayContainer) type);
8419 if (initializers == null)
8420 return await_stack_field;
8422 if (await_stack_field != null)
8423 await_stack_field.EmitAssignFromStack (ec);
8427 // Emit static initializer for arrays which contain more than 2 items and
8428 // the static initializer will initialize at least 25% of array values or there
8429 // is more than 10 items to be initialized
8431 // NOTE: const_initializers_count does not contain default constant values.
8433 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8434 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8435 EmitStaticInitializers (ec, await_stack_field);
8437 if (!only_constant_initializers)
8438 EmitDynamicInitializers (ec, false, await_stack_field);
8442 EmitDynamicInitializers (ec, true, await_stack_field);
8445 if (first_emit_temp != null)
8446 first_emit_temp.Release (ec);
8448 return await_stack_field;
8451 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8453 // no multi dimensional or jagged arrays
8454 if (arguments.Count != 1 || array_element_type.IsArray) {
8455 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8459 // No array covariance, except for array -> object
8460 if (type != targetType) {
8461 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8462 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8466 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8467 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8472 // Single dimensional array of 0 size
8473 if (array_data == null) {
8474 IntConstant ic = arguments[0] as IntConstant;
8475 if (ic == null || !ic.IsDefaultValue) {
8476 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8484 enc.Encode (array_data.Count);
8485 foreach (var element in array_data) {
8486 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8490 protected override void CloneTo (CloneContext clonectx, Expression t)
8492 ArrayCreation target = (ArrayCreation) t;
8494 if (requested_base_type != null)
8495 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8497 if (arguments != null){
8498 target.arguments = new List<Expression> (arguments.Count);
8499 foreach (Expression e in arguments)
8500 target.arguments.Add (e.Clone (clonectx));
8503 if (initializers != null)
8504 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8507 public override object Accept (StructuralVisitor visitor)
8509 return visitor.Visit (this);
8514 // Represents an implicitly typed array epxression
8516 class ImplicitlyTypedArrayCreation : ArrayCreation
8518 TypeInferenceContext best_type_inference;
8520 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8521 : base (null, rank, initializers, loc)
8525 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8526 : base (null, initializers, loc)
8530 protected override Expression DoResolve (ResolveContext ec)
8535 dimensions = rank.Dimension;
8537 best_type_inference = new TypeInferenceContext ();
8539 if (!ResolveInitializers (ec))
8542 best_type_inference.FixAllTypes (ec);
8543 array_element_type = best_type_inference.InferredTypeArguments[0];
8544 best_type_inference = null;
8546 if (array_element_type == null ||
8547 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8548 arguments.Count != rank.Dimension) {
8549 ec.Report.Error (826, loc,
8550 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8555 // At this point we found common base type for all initializer elements
8556 // but we have to be sure that all static initializer elements are of
8559 UnifyInitializerElement (ec);
8561 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8562 eclass = ExprClass.Value;
8567 // Converts static initializer only
8569 void UnifyInitializerElement (ResolveContext ec)
8571 for (int i = 0; i < array_data.Count; ++i) {
8572 Expression e = array_data[i];
8574 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8578 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8580 element = element.Resolve (ec);
8581 if (element != null)
8582 best_type_inference.AddCommonTypeBound (element.Type);
8588 sealed class CompilerGeneratedThis : This
8590 public CompilerGeneratedThis (TypeSpec type, Location loc)
8596 protected override Expression DoResolve (ResolveContext rc)
8598 eclass = ExprClass.Variable;
8600 var block = rc.CurrentBlock;
8601 if (block != null) {
8602 var top = block.ParametersBlock.TopBlock;
8603 if (top.ThisVariable != null)
8604 variable_info = top.ThisVariable.VariableInfo;
8611 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8613 return DoResolve (rc);
8616 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8623 /// Represents the `this' construct
8626 public class This : VariableReference
8628 sealed class ThisVariable : ILocalVariable
8630 public static readonly ILocalVariable Instance = new ThisVariable ();
8632 public void Emit (EmitContext ec)
8637 public void EmitAssign (EmitContext ec)
8639 throw new InvalidOperationException ();
8642 public void EmitAddressOf (EmitContext ec)
8648 protected VariableInfo variable_info;
8650 public This (Location loc)
8657 public override string Name {
8658 get { return "this"; }
8661 public override bool IsLockedByStatement {
8669 public override bool IsRef {
8670 get { return type.IsStruct; }
8673 public override bool IsSideEffectFree {
8679 protected override ILocalVariable Variable {
8680 get { return ThisVariable.Instance; }
8683 public override VariableInfo VariableInfo {
8684 get { return variable_info; }
8687 public override bool IsFixed {
8688 get { return false; }
8693 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8696 // It's null for all cases when we don't need to check `this'
8697 // definitive assignment
8699 if (variable_info == null)
8702 if (fc.IsDefinitelyAssigned (variable_info))
8705 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8708 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8710 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8711 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8712 } else if (ec.CurrentAnonymousMethod != null) {
8713 ec.Report.Error (1673, loc,
8714 "Anonymous methods inside structs cannot access instance members of `this'. " +
8715 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8717 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8721 public override void FlowAnalysis (FlowAnalysisContext fc)
8723 CheckStructThisDefiniteAssignment (fc);
8726 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8731 AnonymousMethodStorey storey = ae.Storey;
8732 return storey != null ? storey.HoistedThis : null;
8735 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8737 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8740 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8743 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8749 public virtual void ResolveBase (ResolveContext ec)
8751 eclass = ExprClass.Variable;
8752 type = ec.CurrentType;
8754 if (!IsThisAvailable (ec, false)) {
8755 Error_ThisNotAvailable (ec);
8759 var block = ec.CurrentBlock;
8760 if (block != null) {
8761 var top = block.ParametersBlock.TopBlock;
8762 if (top.ThisVariable != null)
8763 variable_info = top.ThisVariable.VariableInfo;
8765 AnonymousExpression am = ec.CurrentAnonymousMethod;
8766 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8768 // Hoisted this is almost like hoisted variable but not exactly. When
8769 // there is no variable hoisted we can simply emit an instance method
8770 // without lifting this into a storey. Unfotunatelly this complicates
8771 // things in other cases because we don't know where this will be hoisted
8772 // until top-level block is fully resolved
8774 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8775 am.SetHasThisAccess ();
8780 protected override Expression DoResolve (ResolveContext ec)
8786 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8788 if (eclass == ExprClass.Unresolved)
8792 if (right_side == EmptyExpression.UnaryAddress)
8793 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8794 else if (right_side == EmptyExpression.OutAccess)
8795 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8797 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8803 public override int GetHashCode()
8805 throw new NotImplementedException ();
8808 public override bool Equals (object obj)
8810 This t = obj as This;
8817 protected override void CloneTo (CloneContext clonectx, Expression t)
8822 public override void SetHasAddressTaken ()
8827 public override object Accept (StructuralVisitor visitor)
8829 return visitor.Visit (this);
8834 /// Represents the `__arglist' construct
8836 public class ArglistAccess : Expression
8838 public ArglistAccess (Location loc)
8843 protected override void CloneTo (CloneContext clonectx, Expression target)
8848 public override bool ContainsEmitWithAwait ()
8853 public override Expression CreateExpressionTree (ResolveContext ec)
8855 throw new NotSupportedException ("ET");
8858 protected override Expression DoResolve (ResolveContext ec)
8860 eclass = ExprClass.Variable;
8861 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8863 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8864 ec.Report.Error (190, loc,
8865 "The __arglist construct is valid only within a variable argument method");
8871 public override void Emit (EmitContext ec)
8873 ec.Emit (OpCodes.Arglist);
8876 public override object Accept (StructuralVisitor visitor)
8878 return visitor.Visit (this);
8883 /// Represents the `__arglist (....)' construct
8885 public class Arglist : Expression
8887 Arguments arguments;
8889 public Arglist (Location loc)
8894 public Arglist (Arguments args, Location l)
8900 public Arguments Arguments {
8906 public MetaType[] ArgumentTypes {
8908 if (arguments == null)
8909 return MetaType.EmptyTypes;
8911 var retval = new MetaType[arguments.Count];
8912 for (int i = 0; i < retval.Length; i++)
8913 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8919 public override bool ContainsEmitWithAwait ()
8921 throw new NotImplementedException ();
8924 public override Expression CreateExpressionTree (ResolveContext ec)
8926 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8930 protected override Expression DoResolve (ResolveContext ec)
8932 eclass = ExprClass.Variable;
8933 type = InternalType.Arglist;
8934 if (arguments != null) {
8935 bool dynamic; // Can be ignored as there is always only 1 overload
8936 arguments.Resolve (ec, out dynamic);
8942 public override void Emit (EmitContext ec)
8944 if (arguments != null)
8945 arguments.Emit (ec);
8948 protected override void CloneTo (CloneContext clonectx, Expression t)
8950 Arglist target = (Arglist) t;
8952 if (arguments != null)
8953 target.arguments = arguments.Clone (clonectx);
8956 public override object Accept (StructuralVisitor visitor)
8958 return visitor.Visit (this);
8962 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8964 FullNamedExpression texpr;
8966 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8973 public FullNamedExpression TypeExpression {
8979 public override bool ContainsEmitWithAwait ()
8984 public void AddressOf (EmitContext ec, AddressOp mode)
8987 ec.Emit (OpCodes.Refanyval, type);
8990 protected override Expression DoResolve (ResolveContext rc)
8992 expr = expr.Resolve (rc);
8993 type = texpr.ResolveAsType (rc);
8994 if (expr == null || type == null)
8997 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8998 eclass = ExprClass.Variable;
9002 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9004 return DoResolve (rc);
9007 public override void Emit (EmitContext ec)
9010 ec.Emit (OpCodes.Refanyval, type);
9011 ec.EmitLoadFromPtr (type);
9014 public void Emit (EmitContext ec, bool leave_copy)
9016 throw new NotImplementedException ();
9019 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9022 ec.Emit (OpCodes.Refanyval, type);
9025 LocalTemporary temporary = null;
9027 ec.Emit (OpCodes.Dup);
9028 temporary = new LocalTemporary (source.Type);
9029 temporary.Store (ec);
9032 ec.EmitStoreFromPtr (type);
9034 if (temporary != null) {
9035 temporary.Emit (ec);
9036 temporary.Release (ec);
9040 public override object Accept (StructuralVisitor visitor)
9042 return visitor.Visit (this);
9046 public class RefTypeExpr : ShimExpression
9048 public RefTypeExpr (Expression expr, Location loc)
9054 protected override Expression DoResolve (ResolveContext rc)
9056 expr = expr.Resolve (rc);
9060 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9064 type = rc.BuiltinTypes.Type;
9065 eclass = ExprClass.Value;
9069 public override void Emit (EmitContext ec)
9072 ec.Emit (OpCodes.Refanytype);
9073 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9075 ec.Emit (OpCodes.Call, m);
9078 public override object Accept (StructuralVisitor visitor)
9080 return visitor.Visit (this);
9084 public class MakeRefExpr : ShimExpression
9086 public MakeRefExpr (Expression expr, Location loc)
9092 public override bool ContainsEmitWithAwait ()
9094 throw new NotImplementedException ();
9097 protected override Expression DoResolve (ResolveContext rc)
9099 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9100 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9101 eclass = ExprClass.Value;
9105 public override void Emit (EmitContext ec)
9107 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9108 ec.Emit (OpCodes.Mkrefany, expr.Type);
9111 public override object Accept (StructuralVisitor visitor)
9113 return visitor.Visit (this);
9118 /// Implements the typeof operator
9120 public class TypeOf : Expression {
9121 FullNamedExpression QueriedType;
9124 public TypeOf (FullNamedExpression queried_type, Location l)
9126 QueriedType = queried_type;
9131 // Use this constructor for any compiler generated typeof expression
9133 public TypeOf (TypeSpec type, Location loc)
9135 this.typearg = type;
9141 public override bool IsSideEffectFree {
9147 public TypeSpec TypeArgument {
9153 public FullNamedExpression TypeExpression {
9162 protected override void CloneTo (CloneContext clonectx, Expression t)
9164 TypeOf target = (TypeOf) t;
9165 if (QueriedType != null)
9166 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9169 public override bool ContainsEmitWithAwait ()
9174 public override Expression CreateExpressionTree (ResolveContext ec)
9176 Arguments args = new Arguments (2);
9177 args.Add (new Argument (this));
9178 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9179 return CreateExpressionFactoryCall (ec, "Constant", args);
9182 protected override Expression DoResolve (ResolveContext ec)
9184 if (eclass != ExprClass.Unresolved)
9187 if (typearg == null) {
9189 // Pointer types are allowed without explicit unsafe, they are just tokens
9191 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9192 typearg = QueriedType.ResolveAsType (ec, true);
9195 if (typearg == null)
9198 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9199 ec.Report.Error (1962, QueriedType.Location,
9200 "The typeof operator cannot be used on the dynamic type");
9204 type = ec.BuiltinTypes.Type;
9206 // Even though what is returned is a type object, it's treated as a value by the compiler.
9207 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9208 eclass = ExprClass.Value;
9212 static bool ContainsDynamicType (TypeSpec type)
9214 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9217 var element_container = type as ElementTypeSpec;
9218 if (element_container != null)
9219 return ContainsDynamicType (element_container.Element);
9221 foreach (var t in type.TypeArguments) {
9222 if (ContainsDynamicType (t)) {
9230 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9232 // Target type is not System.Type therefore must be object
9233 // and we need to use different encoding sequence
9234 if (targetType != type)
9237 if (typearg is InflatedTypeSpec) {
9240 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9241 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9242 typearg.GetSignatureForError ());
9246 gt = gt.DeclaringType;
9247 } while (gt != null);
9250 if (ContainsDynamicType (typearg)) {
9251 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9255 enc.EncodeTypeName (typearg);
9258 public override void Emit (EmitContext ec)
9260 ec.Emit (OpCodes.Ldtoken, typearg);
9261 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9263 ec.Emit (OpCodes.Call, m);
9266 public override object Accept (StructuralVisitor visitor)
9268 return visitor.Visit (this);
9272 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9274 public TypeOfMethod (MethodSpec method, Location loc)
9275 : base (method, loc)
9279 protected override Expression DoResolve (ResolveContext ec)
9281 if (member.IsConstructor) {
9282 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9284 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9290 return base.DoResolve (ec);
9293 public override void Emit (EmitContext ec)
9295 ec.Emit (OpCodes.Ldtoken, member);
9298 ec.Emit (OpCodes.Castclass, type);
9301 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9303 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9306 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9308 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9312 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9314 protected readonly T member;
9316 protected TypeOfMember (T member, Location loc)
9318 this.member = member;
9322 public override bool IsSideEffectFree {
9328 public override bool ContainsEmitWithAwait ()
9333 public override Expression CreateExpressionTree (ResolveContext ec)
9335 Arguments args = new Arguments (2);
9336 args.Add (new Argument (this));
9337 args.Add (new Argument (new TypeOf (type, loc)));
9338 return CreateExpressionFactoryCall (ec, "Constant", args);
9341 protected override Expression DoResolve (ResolveContext ec)
9343 eclass = ExprClass.Value;
9347 public override void Emit (EmitContext ec)
9349 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9350 PredefinedMember<MethodSpec> p;
9352 p = GetTypeFromHandleGeneric (ec);
9353 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9355 p = GetTypeFromHandle (ec);
9358 var mi = p.Resolve (loc);
9360 ec.Emit (OpCodes.Call, mi);
9363 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9364 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9367 sealed class TypeOfField : TypeOfMember<FieldSpec>
9369 public TypeOfField (FieldSpec field, Location loc)
9374 protected override Expression DoResolve (ResolveContext ec)
9376 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9380 return base.DoResolve (ec);
9383 public override void Emit (EmitContext ec)
9385 ec.Emit (OpCodes.Ldtoken, member);
9389 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9391 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9394 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9396 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9401 /// Implements the sizeof expression
9403 public class SizeOf : Expression {
9404 readonly Expression texpr;
9405 TypeSpec type_queried;
9407 public SizeOf (Expression queried_type, Location l)
9409 this.texpr = queried_type;
9413 public override bool IsSideEffectFree {
9419 public Expression TypeExpression {
9425 public override bool ContainsEmitWithAwait ()
9430 public override Expression CreateExpressionTree (ResolveContext ec)
9432 Error_PointerInsideExpressionTree (ec);
9436 protected override Expression DoResolve (ResolveContext ec)
9438 type_queried = texpr.ResolveAsType (ec);
9439 if (type_queried == null)
9442 if (type_queried.IsEnum)
9443 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9445 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9447 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9450 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9455 ec.Report.Error (233, loc,
9456 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9457 type_queried.GetSignatureForError ());
9460 type = ec.BuiltinTypes.Int;
9461 eclass = ExprClass.Value;
9465 public override void Emit (EmitContext ec)
9467 ec.Emit (OpCodes.Sizeof, type_queried);
9470 protected override void CloneTo (CloneContext clonectx, Expression t)
9474 public override object Accept (StructuralVisitor visitor)
9476 return visitor.Visit (this);
9481 /// Implements the qualified-alias-member (::) expression.
9483 public class QualifiedAliasMember : MemberAccess
9485 readonly string alias;
9486 public static readonly string GlobalAlias = "global";
9488 public QualifiedAliasMember (string alias, string identifier, Location l)
9489 : base (null, identifier, l)
9494 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9495 : base (null, identifier, targs, l)
9500 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9501 : base (null, identifier, arity, l)
9506 public string Alias {
9512 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9514 if (alias == GlobalAlias)
9515 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9517 int errors = mc.Module.Compiler.Report.Errors;
9518 var expr = mc.LookupNamespaceAlias (alias);
9520 if (errors == mc.Module.Compiler.Report.Errors)
9521 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9529 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9531 expr = CreateExpressionFromAlias (mc);
9535 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9538 protected override Expression DoResolve (ResolveContext rc)
9540 return ResolveAsTypeOrNamespace (rc, false);
9543 public override string GetSignatureForError ()
9546 if (targs != null) {
9547 name = Name + "<" + targs.GetSignatureForError () + ">";
9550 return alias + "::" + name;
9553 public override bool HasConditionalAccess ()
9558 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9560 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9561 rc.Module.Compiler.Report.Error (687, loc,
9562 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9563 GetSignatureForError ());
9568 return DoResolve (rc);
9571 protected override void CloneTo (CloneContext clonectx, Expression t)
9576 public override object Accept (StructuralVisitor visitor)
9578 return visitor.Visit (this);
9583 /// Implements the member access expression
9585 public class MemberAccess : ATypeNameExpression
9587 protected Expression expr;
9589 public MemberAccess (Expression expr, string id)
9590 : base (id, expr.Location)
9595 public MemberAccess (Expression expr, string identifier, Location loc)
9596 : base (identifier, loc)
9601 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9602 : base (identifier, args, loc)
9607 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9608 : base (identifier, arity, loc)
9613 public Expression LeftExpression {
9619 public override Location StartLocation {
9621 return expr == null ? loc : expr.StartLocation;
9625 protected override Expression DoResolve (ResolveContext rc)
9627 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9629 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9634 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9636 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9638 if (e is TypeExpr) {
9639 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9644 e = e.ResolveLValue (rc, rhs);
9649 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9651 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9652 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9654 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9657 public override bool HasConditionalAccess ()
9659 return LeftExpression.HasConditionalAccess ();
9662 public static bool IsValidDotExpression (TypeSpec type)
9664 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9665 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9667 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9670 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9672 var sn = expr as SimpleName;
9673 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9676 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9679 // Resolve expression which does have type set as we need expression type
9680 // with disable flow analysis as we don't know whether left side expression
9681 // is used as variable or type
9683 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9684 expr = expr.Resolve (rc);
9685 } else if (expr is TypeParameterExpr) {
9686 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9690 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9691 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9692 expr = expr.Resolve (rc, flags);
9695 expr = expr.Resolve (rc, flags);
9702 var ns = expr as NamespaceExpression;
9704 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9706 if (retval == null) {
9707 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9712 if (HasTypeArguments)
9713 return new GenericTypeExpr (retval.Type, targs, loc);
9715 targs.Resolve (rc, false);
9722 TypeSpec expr_type = expr.Type;
9723 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9724 me = expr as MemberExpr;
9726 me.ResolveInstanceExpression (rc, null);
9728 Arguments args = new Arguments (1);
9729 args.Add (new Argument (expr));
9730 return new DynamicMemberBinder (Name, args, loc);
9733 var cma = this as ConditionalMemberAccess;
9735 if (!IsNullPropagatingValid (expr.Type)) {
9736 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9740 if (expr_type.IsNullableType) {
9741 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9742 expr_type = expr.Type;
9746 if (!IsValidDotExpression (expr_type)) {
9747 Error_OperatorCannotBeApplied (rc, expr_type);
9751 var lookup_arity = Arity;
9752 bool errorMode = false;
9753 Expression member_lookup;
9755 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9756 if (member_lookup == null) {
9758 // Try to look for extension method when member lookup failed
9760 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9761 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9762 if (methods != null) {
9763 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9764 if (HasTypeArguments) {
9765 if (!targs.Resolve (rc, false))
9768 emg.SetTypeArguments (rc, targs);
9772 emg.ConditionalAccess = true;
9774 // TODO: it should really skip the checks bellow
9775 return emg.Resolve (rc);
9781 if (member_lookup == null) {
9782 var dep = expr_type.GetMissingDependencies ();
9784 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9785 } else if (expr is TypeExpr) {
9786 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9788 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9794 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9795 // Leave it to overload resolution to report correct error
9796 } else if (!(member_lookup is TypeExpr)) {
9797 // TODO: rc.SymbolRelatedToPreviousError
9798 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9803 if (member_lookup != null)
9807 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9811 TypeExpr texpr = member_lookup as TypeExpr;
9812 if (texpr != null) {
9813 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9814 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9815 Name, texpr.GetSignatureForError ());
9818 if (!texpr.Type.IsAccessible (rc)) {
9819 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9820 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9824 if (HasTypeArguments) {
9825 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9828 return member_lookup;
9831 me = member_lookup as MemberExpr;
9833 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9838 me.ConditionalAccess = true;
9841 me = me.ResolveMemberAccess (rc, expr, sn);
9844 if (!targs.Resolve (rc, false))
9847 me.SetTypeArguments (rc, targs);
9853 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9855 FullNamedExpression fexpr = expr as FullNamedExpression;
9856 if (fexpr == null) {
9857 expr.ResolveAsType (rc);
9861 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9863 if (expr_resolved == null)
9866 var ns = expr_resolved as NamespaceExpression;
9868 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9870 if (retval == null) {
9871 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9872 } else if (Arity > 0) {
9873 if (HasTypeArguments) {
9874 retval = new GenericTypeExpr (retval.Type, targs, loc);
9875 if (retval.ResolveAsType (rc) == null)
9878 targs.Resolve (rc, allowUnboundTypeArguments);
9880 retval = new GenericOpenTypeExpr (retval.Type, loc);
9887 var tnew_expr = expr_resolved.ResolveAsType (rc);
9888 if (tnew_expr == null)
9891 TypeSpec expr_type = tnew_expr;
9892 if (TypeManager.IsGenericParameter (expr_type)) {
9893 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9894 tnew_expr.GetSignatureForError ());
9898 var qam = this as QualifiedAliasMember;
9900 rc.Module.Compiler.Report.Error (431, loc,
9901 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9906 TypeSpec nested = null;
9907 while (expr_type != null) {
9908 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9909 if (nested == null) {
9910 if (expr_type == tnew_expr) {
9911 Error_IdentifierNotFound (rc, expr_type);
9915 expr_type = tnew_expr;
9916 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9917 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9921 if (nested.IsAccessible (rc))
9925 // Keep looking after inaccessible candidate but only if
9926 // we are not in same context as the definition itself
9928 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9931 expr_type = expr_type.BaseType;
9936 if (HasTypeArguments) {
9937 texpr = new GenericTypeExpr (nested, targs, loc);
9939 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9941 texpr = new GenericOpenTypeExpr (nested, loc);
9943 } else if (expr_resolved is GenericOpenTypeExpr) {
9944 texpr = new GenericOpenTypeExpr (nested, loc);
9946 texpr = new TypeExpression (nested, loc);
9949 if (texpr.ResolveAsType (rc) == null)
9955 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9957 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9959 if (nested != null) {
9960 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9964 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9965 if (any_other_member != null) {
9966 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9970 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9971 Name, expr_type.GetSignatureForError ());
9974 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9976 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9979 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9981 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9982 ec.Report.SymbolRelatedToPreviousError (type);
9984 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9986 // a using directive or an assembly reference
9988 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9990 missing = "an assembly reference";
9993 ec.Report.Error (1061, loc,
9994 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9995 type.GetSignatureForError (), name, missing);
9999 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10002 public override string GetSignatureForError ()
10004 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10007 protected override void CloneTo (CloneContext clonectx, Expression t)
10009 MemberAccess target = (MemberAccess) t;
10011 target.expr = expr.Clone (clonectx);
10014 public override object Accept (StructuralVisitor visitor)
10016 return visitor.Visit (this);
10020 public class ConditionalMemberAccess : MemberAccess
10022 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10023 : base (expr, identifier, args, loc)
10027 public override bool HasConditionalAccess ()
10034 /// Implements checked expressions
10036 public class CheckedExpr : Expression {
10038 public Expression Expr;
10040 public CheckedExpr (Expression e, Location l)
10046 public override bool ContainsEmitWithAwait ()
10048 return Expr.ContainsEmitWithAwait ();
10051 public override Expression CreateExpressionTree (ResolveContext ec)
10053 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10054 return Expr.CreateExpressionTree (ec);
10057 protected override Expression DoResolve (ResolveContext ec)
10059 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10060 Expr = Expr.Resolve (ec);
10065 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10068 eclass = Expr.eclass;
10073 public override void Emit (EmitContext ec)
10075 using (ec.With (EmitContext.Options.CheckedScope, true))
10079 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10081 using (ec.With (EmitContext.Options.CheckedScope, true))
10082 Expr.EmitBranchable (ec, target, on_true);
10085 public override void FlowAnalysis (FlowAnalysisContext fc)
10087 Expr.FlowAnalysis (fc);
10090 public override SLE.Expression MakeExpression (BuilderContext ctx)
10092 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10093 return Expr.MakeExpression (ctx);
10097 protected override void CloneTo (CloneContext clonectx, Expression t)
10099 CheckedExpr target = (CheckedExpr) t;
10101 target.Expr = Expr.Clone (clonectx);
10104 public override object Accept (StructuralVisitor visitor)
10106 return visitor.Visit (this);
10111 /// Implements the unchecked expression
10113 public class UnCheckedExpr : Expression {
10115 public Expression Expr;
10117 public UnCheckedExpr (Expression e, Location l)
10123 public override bool ContainsEmitWithAwait ()
10125 return Expr.ContainsEmitWithAwait ();
10128 public override Expression CreateExpressionTree (ResolveContext ec)
10130 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10131 return Expr.CreateExpressionTree (ec);
10134 protected override Expression DoResolve (ResolveContext ec)
10136 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10137 Expr = Expr.Resolve (ec);
10142 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10145 eclass = Expr.eclass;
10150 public override void Emit (EmitContext ec)
10152 using (ec.With (EmitContext.Options.CheckedScope, false))
10156 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10158 using (ec.With (EmitContext.Options.CheckedScope, false))
10159 Expr.EmitBranchable (ec, target, on_true);
10162 public override void FlowAnalysis (FlowAnalysisContext fc)
10164 Expr.FlowAnalysis (fc);
10167 protected override void CloneTo (CloneContext clonectx, Expression t)
10169 UnCheckedExpr target = (UnCheckedExpr) t;
10171 target.Expr = Expr.Clone (clonectx);
10174 public override object Accept (StructuralVisitor visitor)
10176 return visitor.Visit (this);
10181 /// An Element Access expression.
10183 /// During semantic analysis these are transformed into
10184 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10186 public class ElementAccess : Expression
10188 public Arguments Arguments;
10189 public Expression Expr;
10190 bool conditional_access_receiver;
10192 public ElementAccess (Expression e, Arguments args, Location loc)
10196 this.Arguments = args;
10199 public bool ConditionalAccess { get; set; }
10201 public override Location StartLocation {
10203 return Expr.StartLocation;
10207 public override bool ContainsEmitWithAwait ()
10209 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10213 // We perform some simple tests, and then to "split" the emit and store
10214 // code we create an instance of a different class, and return that.
10216 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10218 if (conditionalAccessReceiver)
10219 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10221 Expr = Expr.Resolve (ec);
10223 if (conditionalAccessReceiver)
10224 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10231 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10232 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10236 if (type.IsArray) {
10237 var aa = new ArrayAccess (this, loc) {
10238 ConditionalAccess = ConditionalAccess,
10241 if (conditionalAccessReceiver)
10242 aa.SetConditionalAccessReceiver ();
10247 if (type.IsPointer)
10248 return Expr.MakePointerAccess (ec, type, Arguments);
10250 FieldExpr fe = Expr as FieldExpr;
10252 var ff = fe.Spec as FixedFieldSpec;
10254 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10258 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10259 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10260 var indexer = new IndexerExpr (indexers, type, this) {
10261 ConditionalAccess = ConditionalAccess
10264 if (conditionalAccessReceiver)
10265 indexer.SetConditionalAccessReceiver ();
10270 Error_CannotApplyIndexing (ec, type, loc);
10275 public override Expression CreateExpressionTree (ResolveContext ec)
10277 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10278 Expr.CreateExpressionTree (ec));
10280 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10283 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10285 if (type != InternalType.ErrorType) {
10286 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10287 type.GetSignatureForError ());
10291 public override bool HasConditionalAccess ()
10293 return ConditionalAccess || Expr.HasConditionalAccess ();
10296 void ResolveConditionalAccessReceiver (ResolveContext rc)
10298 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10299 conditional_access_receiver = true;
10303 protected override Expression DoResolve (ResolveContext rc)
10305 ResolveConditionalAccessReceiver (rc);
10307 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10311 return expr.Resolve (rc);
10314 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10316 var res = CreateAccessExpression (ec, false);
10320 return res.ResolveLValue (ec, rhs);
10323 public override void Emit (EmitContext ec)
10325 throw new Exception ("Should never be reached");
10328 public override void FlowAnalysis (FlowAnalysisContext fc)
10330 Expr.FlowAnalysis (fc);
10332 Arguments.FlowAnalysis (fc);
10335 public override string GetSignatureForError ()
10337 return Expr.GetSignatureForError ();
10340 protected override void CloneTo (CloneContext clonectx, Expression t)
10342 ElementAccess target = (ElementAccess) t;
10344 target.Expr = Expr.Clone (clonectx);
10345 if (Arguments != null)
10346 target.Arguments = Arguments.Clone (clonectx);
10349 public override object Accept (StructuralVisitor visitor)
10351 return visitor.Visit (this);
10356 /// Implements array access
10358 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10360 // Points to our "data" repository
10364 LocalTemporary temp;
10366 bool? has_await_args;
10367 bool conditional_access_receiver;
10369 public ArrayAccess (ElementAccess ea_data, Location l)
10375 public bool ConditionalAccess { get; set; }
10377 public void AddressOf (EmitContext ec, AddressOp mode)
10379 var ac = (ArrayContainer) ea.Expr.Type;
10381 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10382 LoadInstanceAndArguments (ec, false, true);
10385 LoadInstanceAndArguments (ec, false, false);
10387 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10388 ec.Emit (OpCodes.Readonly);
10390 ec.EmitArrayAddress (ac);
10393 public override Expression CreateExpressionTree (ResolveContext ec)
10395 if (ConditionalAccess)
10396 Error_NullShortCircuitInsideExpressionTree (ec);
10398 return ea.CreateExpressionTree (ec);
10401 public override bool ContainsEmitWithAwait ()
10403 return ea.ContainsEmitWithAwait ();
10406 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10408 if (HasConditionalAccess ())
10409 Error_NullPropagatingLValue (ec);
10411 return DoResolve (ec);
10414 protected override Expression DoResolve (ResolveContext ec)
10416 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10418 ea.Arguments.Resolve (ec, out dynamic);
10420 var ac = ea.Expr.Type as ArrayContainer;
10421 int rank = ea.Arguments.Count;
10422 if (ac.Rank != rank) {
10423 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10424 rank.ToString (), ac.Rank.ToString ());
10429 if (type.IsPointer && !ec.IsUnsafe) {
10430 UnsafeError (ec, ea.Location);
10433 if (conditional_access_receiver)
10434 type = LiftMemberType (ec, type);
10436 foreach (Argument a in ea.Arguments) {
10437 var na = a as NamedArgument;
10439 ElementAccess.Error_NamedArgument (na, ec.Report);
10441 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10444 eclass = ExprClass.Variable;
10449 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10451 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10454 public override void FlowAnalysis (FlowAnalysisContext fc)
10456 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10458 ea.FlowAnalysis (fc);
10460 if (conditional_access_receiver)
10461 fc.DefiniteAssignment = da;
10464 public override bool HasConditionalAccess ()
10466 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10470 // Load the array arguments into the stack.
10472 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10474 if (prepareAwait) {
10475 ea.Expr = ea.Expr.EmitToField (ec);
10477 var ie = new InstanceEmitter (ea.Expr, false);
10478 ie.Emit (ec, ConditionalAccess);
10480 if (duplicateArguments) {
10481 ec.Emit (OpCodes.Dup);
10483 var copy = new LocalTemporary (ea.Expr.Type);
10489 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10490 if (dup_args != null)
10491 ea.Arguments = dup_args;
10494 public void Emit (EmitContext ec, bool leave_copy)
10497 ec.EmitLoadFromPtr (type);
10499 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10500 LoadInstanceAndArguments (ec, false, true);
10503 if (conditional_access_receiver)
10504 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10506 var ac = (ArrayContainer) ea.Expr.Type;
10507 LoadInstanceAndArguments (ec, false, false);
10508 ec.EmitArrayLoad (ac);
10510 if (conditional_access_receiver)
10511 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10515 ec.Emit (OpCodes.Dup);
10516 temp = new LocalTemporary (this.type);
10521 public override void Emit (EmitContext ec)
10526 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10528 var ac = (ArrayContainer) ea.Expr.Type;
10529 TypeSpec t = source.Type;
10531 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10534 // When we are dealing with a struct, get the address of it to avoid value copy
10535 // Same cannot be done for reference type because array covariance and the
10536 // check in ldelema requires to specify the type of array element stored at the index
10538 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10539 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10541 if (has_await_args.Value) {
10542 if (source.ContainsEmitWithAwait ()) {
10543 source = source.EmitToField (ec);
10544 isCompound = false;
10548 LoadInstanceAndArguments (ec, isCompound, false);
10553 ec.EmitArrayAddress (ac);
10556 ec.Emit (OpCodes.Dup);
10560 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10562 if (has_await_args.Value) {
10563 if (source.ContainsEmitWithAwait ())
10564 source = source.EmitToField (ec);
10566 LoadInstanceAndArguments (ec, false, false);
10573 var lt = ea.Expr as LocalTemporary;
10579 ec.Emit (OpCodes.Dup);
10580 temp = new LocalTemporary (this.type);
10585 ec.EmitStoreFromPtr (t);
10587 ec.EmitArrayStore (ac);
10590 if (temp != null) {
10596 public override Expression EmitToField (EmitContext ec)
10599 // Have to be specialized for arrays to get access to
10600 // underlying element. Instead of another result copy we
10601 // need direct access to element
10605 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10607 ea.Expr = ea.Expr.EmitToField (ec);
10608 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10612 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10614 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10617 public override SLE.Expression MakeExpression (BuilderContext ctx)
10619 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10622 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10624 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10625 return Arguments.MakeExpression (ea.Arguments, ctx);
10629 public void SetConditionalAccessReceiver ()
10631 conditional_access_receiver = true;
10636 // Indexer access expression
10638 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10640 IList<MemberSpec> indexers;
10641 Arguments arguments;
10642 TypeSpec queried_type;
10644 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10645 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10649 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10652 this.indexers = indexers;
10653 this.queried_type = queriedType;
10654 this.InstanceExpression = instance;
10655 this.arguments = args;
10660 protected override Arguments Arguments {
10669 protected override TypeSpec DeclaringType {
10671 return best_candidate.DeclaringType;
10675 public override bool IsInstance {
10681 public override bool IsStatic {
10687 public override string KindName {
10688 get { return "indexer"; }
10691 public override string Name {
10699 public override bool ContainsEmitWithAwait ()
10701 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10704 public override Expression CreateExpressionTree (ResolveContext ec)
10706 if (ConditionalAccess) {
10707 Error_NullShortCircuitInsideExpressionTree (ec);
10710 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10711 InstanceExpression.CreateExpressionTree (ec),
10712 new TypeOfMethod (Getter, loc));
10714 return CreateExpressionFactoryCall (ec, "Call", args);
10717 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10719 LocalTemporary await_source_arg = null;
10722 emitting_compound_assignment = true;
10723 if (source is DynamicExpressionStatement) {
10728 emitting_compound_assignment = false;
10730 if (has_await_arguments) {
10731 await_source_arg = new LocalTemporary (Type);
10732 await_source_arg.Store (ec);
10734 arguments.Add (new Argument (await_source_arg));
10737 temp = await_source_arg;
10740 has_await_arguments = false;
10745 ec.Emit (OpCodes.Dup);
10746 temp = new LocalTemporary (Type);
10752 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10753 source = source.EmitToField (ec);
10755 temp = new LocalTemporary (Type);
10762 arguments.Add (new Argument (source));
10765 var call = new CallEmitter ();
10766 call.InstanceExpression = InstanceExpression;
10767 if (arguments == null)
10768 call.InstanceExpressionOnStack = true;
10770 call.Emit (ec, Setter, arguments, loc);
10772 if (temp != null) {
10775 } else if (leave_copy) {
10779 if (await_source_arg != null) {
10780 await_source_arg.Release (ec);
10784 public override void FlowAnalysis (FlowAnalysisContext fc)
10786 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10788 base.FlowAnalysis (fc);
10789 arguments.FlowAnalysis (fc);
10791 if (conditional_access_receiver)
10792 fc.DefiniteAssignment = da;
10795 public override string GetSignatureForError ()
10797 return best_candidate.GetSignatureForError ();
10800 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10803 throw new NotSupportedException ();
10805 var value = new[] { source.MakeExpression (ctx) };
10806 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10807 return SLE.Expression.Block (
10808 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10813 public override SLE.Expression MakeExpression (BuilderContext ctx)
10816 return base.MakeExpression (ctx);
10818 var args = Arguments.MakeExpression (arguments, ctx);
10819 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10823 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10825 if (best_candidate != null)
10828 eclass = ExprClass.IndexerAccess;
10831 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10832 arguments.Resolve (rc, out dynamic);
10835 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10838 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10839 res.BaseMembersProvider = this;
10840 res.InstanceQualifier = this;
10842 // TODO: Do I need 2 argument sets?
10843 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10844 if (best_candidate != null)
10845 type = res.BestCandidateReturnType;
10846 else if (!res.BestCandidateIsDynamic)
10851 // It has dynamic arguments
10854 Arguments args = new Arguments (arguments.Count + 1);
10856 rc.Report.Error (1972, loc,
10857 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10859 args.Add (new Argument (InstanceExpression));
10861 args.AddRange (arguments);
10863 best_candidate = null;
10864 return new DynamicIndexBinder (args, loc);
10868 // Try to avoid resolving left expression again
10870 if (right_side != null)
10871 ResolveInstanceExpression (rc, right_side);
10876 protected override void CloneTo (CloneContext clonectx, Expression t)
10878 IndexerExpr target = (IndexerExpr) t;
10880 if (arguments != null)
10881 target.arguments = arguments.Clone (clonectx);
10884 public void SetConditionalAccessReceiver ()
10886 conditional_access_receiver = true;
10889 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10891 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10894 #region IBaseMembersProvider Members
10896 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10898 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10901 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10903 if (queried_type == member.DeclaringType)
10906 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10907 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10910 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10919 // A base access expression
10921 public class BaseThis : This
10923 public BaseThis (Location loc)
10928 public BaseThis (TypeSpec type, Location loc)
10932 eclass = ExprClass.Variable;
10937 public override string Name {
10945 public override Expression CreateExpressionTree (ResolveContext ec)
10947 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10948 return base.CreateExpressionTree (ec);
10951 public override void Emit (EmitContext ec)
10955 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10956 var context_type = ec.CurrentType;
10957 ec.Emit (OpCodes.Ldobj, context_type);
10958 ec.Emit (OpCodes.Box, context_type);
10962 protected override void Error_ThisNotAvailable (ResolveContext ec)
10965 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10967 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10971 public override void ResolveBase (ResolveContext ec)
10973 base.ResolveBase (ec);
10974 type = ec.CurrentType.BaseType;
10977 public override object Accept (StructuralVisitor visitor)
10979 return visitor.Visit (this);
10984 /// This class exists solely to pass the Type around and to be a dummy
10985 /// that can be passed to the conversion functions (this is used by
10986 /// foreach implementation to typecast the object return value from
10987 /// get_Current into the proper type. All code has been generated and
10988 /// we only care about the side effect conversions to be performed
10990 /// This is also now used as a placeholder where a no-action expression
10991 /// is needed (the `New' class).
10993 public class EmptyExpression : Expression
10995 sealed class OutAccessExpression : EmptyExpression
10997 public OutAccessExpression (TypeSpec t)
11002 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11004 rc.Report.Error (206, right_side.Location,
11005 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11011 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11012 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11013 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11014 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11015 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11016 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11017 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11018 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11020 public EmptyExpression (TypeSpec t)
11023 eclass = ExprClass.Value;
11024 loc = Location.Null;
11027 protected override void CloneTo (CloneContext clonectx, Expression target)
11031 public override bool ContainsEmitWithAwait ()
11036 public override Expression CreateExpressionTree (ResolveContext ec)
11038 throw new NotSupportedException ("ET");
11041 protected override Expression DoResolve (ResolveContext ec)
11046 public override void Emit (EmitContext ec)
11048 // nothing, as we only exist to not do anything.
11051 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11055 public override void EmitSideEffect (EmitContext ec)
11059 public override object Accept (StructuralVisitor visitor)
11061 return visitor.Visit (this);
11065 sealed class EmptyAwaitExpression : EmptyExpression
11067 public EmptyAwaitExpression (TypeSpec type)
11072 public override bool ContainsEmitWithAwait ()
11079 // Empty statement expression
11081 public sealed class EmptyExpressionStatement : ExpressionStatement
11083 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11085 private EmptyExpressionStatement ()
11087 loc = Location.Null;
11090 public override bool ContainsEmitWithAwait ()
11095 public override Expression CreateExpressionTree (ResolveContext ec)
11100 public override void EmitStatement (EmitContext ec)
11105 protected override Expression DoResolve (ResolveContext ec)
11107 eclass = ExprClass.Value;
11108 type = ec.BuiltinTypes.Object;
11112 public override void Emit (EmitContext ec)
11117 public override object Accept (StructuralVisitor visitor)
11119 return visitor.Visit (this);
11123 public class ErrorExpression : EmptyExpression
11125 public static readonly ErrorExpression Instance = new ErrorExpression ();
11127 private ErrorExpression ()
11128 : base (InternalType.ErrorType)
11132 public override Expression CreateExpressionTree (ResolveContext ec)
11137 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11142 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11146 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11150 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11154 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11158 public override object Accept (StructuralVisitor visitor)
11160 return visitor.Visit (this);
11164 public class UserCast : Expression {
11168 public UserCast (MethodSpec method, Expression source, Location l)
11170 if (source == null)
11171 throw new ArgumentNullException ("source");
11173 this.method = method;
11174 this.source = source;
11175 type = method.ReturnType;
11179 public Expression Source {
11188 public override bool ContainsEmitWithAwait ()
11190 return source.ContainsEmitWithAwait ();
11193 public override Expression CreateExpressionTree (ResolveContext ec)
11195 Arguments args = new Arguments (3);
11196 args.Add (new Argument (source.CreateExpressionTree (ec)));
11197 args.Add (new Argument (new TypeOf (type, loc)));
11198 args.Add (new Argument (new TypeOfMethod (method, loc)));
11199 return CreateExpressionFactoryCall (ec, "Convert", args);
11202 protected override Expression DoResolve (ResolveContext ec)
11204 method.CheckObsoleteness (ec, source.Location);
11206 eclass = ExprClass.Value;
11210 public override void Emit (EmitContext ec)
11213 ec.MarkCallEntry (loc);
11214 ec.Emit (OpCodes.Call, method);
11217 public override void FlowAnalysis (FlowAnalysisContext fc)
11219 source.FlowAnalysis (fc);
11222 public override string GetSignatureForError ()
11224 return TypeManager.CSharpSignature (method);
11227 public override SLE.Expression MakeExpression (BuilderContext ctx)
11230 return base.MakeExpression (ctx);
11232 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11238 // Holds additional type specifiers like ?, *, []
11240 public class ComposedTypeSpecifier
11242 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11244 public readonly int Dimension;
11245 public readonly Location Location;
11247 public ComposedTypeSpecifier (int specifier, Location loc)
11249 this.Dimension = specifier;
11250 this.Location = loc;
11254 public bool IsNullable {
11256 return Dimension == -1;
11260 public bool IsPointer {
11262 return Dimension == -2;
11266 public ComposedTypeSpecifier Next { get; set; }
11270 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11272 return new ComposedTypeSpecifier (dimension, loc);
11275 public static ComposedTypeSpecifier CreateNullable (Location loc)
11277 return new ComposedTypeSpecifier (-1, loc);
11280 public static ComposedTypeSpecifier CreatePointer (Location loc)
11282 return new ComposedTypeSpecifier (-2, loc);
11285 public string GetSignatureForError ()
11290 ArrayContainer.GetPostfixSignature (Dimension);
11292 return Next != null ? s + Next.GetSignatureForError () : s;
11297 // This class is used to "construct" the type during a typecast
11298 // operation. Since the Type.GetType class in .NET can parse
11299 // the type specification, we just use this to construct the type
11300 // one bit at a time.
11302 public class ComposedCast : TypeExpr {
11303 FullNamedExpression left;
11304 ComposedTypeSpecifier spec;
11306 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11309 throw new ArgumentNullException ("spec");
11313 this.loc = left.Location;
11316 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11318 type = left.ResolveAsType (ec);
11322 eclass = ExprClass.Type;
11324 var single_spec = spec;
11326 if (single_spec.IsNullable) {
11327 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11331 single_spec = single_spec.Next;
11332 } else if (single_spec.IsPointer) {
11334 // Declared fields cannot have unmanaged check done before all types are defined
11336 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11339 if (!ec.IsUnsafe) {
11340 UnsafeError (ec.Module.Compiler.Report, loc);
11344 type = PointerContainer.MakeType (ec.Module, type);
11345 single_spec = single_spec.Next;
11346 } while (single_spec != null && single_spec.IsPointer);
11349 if (single_spec != null && single_spec.Dimension > 0) {
11350 if (type.IsSpecialRuntimeType) {
11351 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11352 } else if (type.IsStatic) {
11353 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11354 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11355 type.GetSignatureForError ());
11357 MakeArray (ec.Module, single_spec);
11364 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11366 if (spec.Next != null)
11367 MakeArray (module, spec.Next);
11369 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11372 public override string GetSignatureForError ()
11374 return left.GetSignatureForError () + spec.GetSignatureForError ();
11377 public override object Accept (StructuralVisitor visitor)
11379 return visitor.Visit (this);
11383 class FixedBufferPtr : Expression
11385 readonly Expression array;
11387 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11389 this.type = array_type;
11390 this.array = array;
11394 public override bool ContainsEmitWithAwait ()
11396 throw new NotImplementedException ();
11399 public override Expression CreateExpressionTree (ResolveContext ec)
11401 Error_PointerInsideExpressionTree (ec);
11405 public override void Emit(EmitContext ec)
11410 protected override Expression DoResolve (ResolveContext ec)
11412 type = PointerContainer.MakeType (ec.Module, type);
11413 eclass = ExprClass.Value;
11420 // This class is used to represent the address of an array, used
11421 // only by the Fixed statement, this generates "&a [0]" construct
11422 // for fixed (char *pa = a)
11424 class ArrayPtr : FixedBufferPtr
11426 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11427 base (array, array_type, l)
11431 public override void Emit (EmitContext ec)
11436 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11441 // Encapsulates a conversion rules required for array indexes
11443 public class ArrayIndexCast : TypeCast
11445 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11446 : base (expr, returnType)
11448 if (expr.Type == returnType) // int -> int
11449 throw new ArgumentException ("unnecessary array index conversion");
11452 public override Expression CreateExpressionTree (ResolveContext ec)
11454 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11455 return base.CreateExpressionTree (ec);
11459 public override void Emit (EmitContext ec)
11463 switch (child.Type.BuiltinType) {
11464 case BuiltinTypeSpec.Type.UInt:
11465 ec.Emit (OpCodes.Conv_U);
11467 case BuiltinTypeSpec.Type.Long:
11468 ec.Emit (OpCodes.Conv_Ovf_I);
11470 case BuiltinTypeSpec.Type.ULong:
11471 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11474 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11480 // Implements the `stackalloc' keyword
11482 public class StackAlloc : Expression {
11487 public StackAlloc (Expression type, Expression count, Location l)
11490 this.count = count;
11494 public Expression TypeExpression {
11500 public Expression CountExpression {
11506 public override bool ContainsEmitWithAwait ()
11511 public override Expression CreateExpressionTree (ResolveContext ec)
11513 throw new NotSupportedException ("ET");
11516 protected override Expression DoResolve (ResolveContext ec)
11518 count = count.Resolve (ec);
11522 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11523 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11528 Constant c = count as Constant;
11529 if (c != null && c.IsNegative) {
11530 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11533 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11534 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11537 otype = texpr.ResolveAsType (ec);
11541 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11544 type = PointerContainer.MakeType (ec.Module, otype);
11545 eclass = ExprClass.Value;
11550 public override void Emit (EmitContext ec)
11552 int size = BuiltinTypeSpec.GetSize (otype);
11557 ec.Emit (OpCodes.Sizeof, otype);
11561 ec.Emit (OpCodes.Mul_Ovf_Un);
11562 ec.Emit (OpCodes.Localloc);
11565 protected override void CloneTo (CloneContext clonectx, Expression t)
11567 StackAlloc target = (StackAlloc) t;
11568 target.count = count.Clone (clonectx);
11569 target.texpr = texpr.Clone (clonectx);
11572 public override object Accept (StructuralVisitor visitor)
11574 return visitor.Visit (this);
11579 // An object initializer expression
11581 public class ElementInitializer : Assign
11583 public readonly string Name;
11585 public ElementInitializer (string name, Expression initializer, Location loc)
11586 : base (null, initializer, loc)
11591 public bool IsDictionaryInitializer {
11593 return Name == null;
11597 protected override void CloneTo (CloneContext clonectx, Expression t)
11599 ElementInitializer target = (ElementInitializer) t;
11600 target.source = source.Clone (clonectx);
11603 public override Expression CreateExpressionTree (ResolveContext ec)
11605 Arguments args = new Arguments (2);
11606 FieldExpr fe = target as FieldExpr;
11608 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11610 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11613 Expression arg_expr;
11614 var cinit = source as CollectionOrObjectInitializers;
11615 if (cinit == null) {
11617 arg_expr = source.CreateExpressionTree (ec);
11619 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11620 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11623 args.Add (new Argument (arg_expr));
11624 return CreateExpressionFactoryCall (ec, mname, args);
11627 protected override Expression DoResolve (ResolveContext ec)
11629 if (source == null)
11630 return EmptyExpressionStatement.Instance;
11632 if (!ResolveElement (ec))
11635 if (source is CollectionOrObjectInitializers) {
11636 target = target.Resolve (ec);
11637 if (target == null)
11640 Expression previous = ec.CurrentInitializerVariable;
11641 ec.CurrentInitializerVariable = target;
11642 source = source.Resolve (ec);
11643 ec.CurrentInitializerVariable = previous;
11644 if (source == null)
11647 eclass = source.eclass;
11648 type = source.Type;
11653 return base.DoResolve (ec);
11656 public override void EmitStatement (EmitContext ec)
11658 if (source is CollectionOrObjectInitializers)
11661 base.EmitStatement (ec);
11664 protected virtual bool ResolveElement (ResolveContext rc)
11666 var t = rc.CurrentInitializerVariable.Type;
11667 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11668 Arguments args = new Arguments (1);
11669 args.Add (new Argument (rc.CurrentInitializerVariable));
11670 target = new DynamicMemberBinder (Name, args, loc);
11673 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11674 if (member == null) {
11675 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11677 if (member != null) {
11678 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11679 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11684 if (member == null) {
11685 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11689 var me = member as MemberExpr;
11690 if (me is EventExpr) {
11691 me = me.ResolveMemberAccess (rc, null, null);
11692 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11693 rc.Report.Error (1913, loc,
11694 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11695 member.GetSignatureForError ());
11701 rc.Report.Error (1914, loc,
11702 "Static field or property `{0}' cannot be assigned in an object initializer",
11703 me.GetSignatureForError ());
11707 me.InstanceExpression = rc.CurrentInitializerVariable;
11715 // A collection initializer expression
11717 class CollectionElementInitializer : Invocation
11719 public class ElementInitializerArgument : Argument
11721 public ElementInitializerArgument (Expression e)
11727 sealed class AddMemberAccess : MemberAccess
11729 public AddMemberAccess (Expression expr, Location loc)
11730 : base (expr, "Add", loc)
11734 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11736 if (TypeManager.HasElementType (type))
11739 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11743 public CollectionElementInitializer (Expression argument)
11744 : base (null, new Arguments (1))
11746 base.arguments.Add (new ElementInitializerArgument (argument));
11747 this.loc = argument.Location;
11750 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11751 : base (null, new Arguments (arguments.Count))
11753 foreach (Expression e in arguments)
11754 base.arguments.Add (new ElementInitializerArgument (e));
11759 public CollectionElementInitializer (Location loc)
11760 : base (null, null)
11765 public override Expression CreateExpressionTree (ResolveContext ec)
11767 Arguments args = new Arguments (2);
11768 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11770 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11771 foreach (Argument a in arguments) {
11772 if (a.ArgType == Argument.AType.ExtensionType) {
11773 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11776 expr_initializers.Add (a.CreateExpressionTree (ec));
11779 args.Add (new Argument (new ArrayCreation (
11780 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11781 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11784 protected override void CloneTo (CloneContext clonectx, Expression t)
11786 CollectionElementInitializer target = (CollectionElementInitializer) t;
11787 if (arguments != null)
11788 target.arguments = arguments.Clone (clonectx);
11791 protected override Expression DoResolve (ResolveContext ec)
11793 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11795 return base.DoResolve (ec);
11799 class DictionaryElementInitializer : ElementInitializer
11801 readonly Arguments args;
11803 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11804 : base (null, initializer, loc)
11806 this.args = arguments;
11809 public override Expression CreateExpressionTree (ResolveContext ec)
11811 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11815 protected override bool ResolveElement (ResolveContext rc)
11817 var init = rc.CurrentInitializerVariable;
11818 var type = init.Type;
11820 if (type.IsArray) {
11821 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11825 if (type.IsPointer) {
11826 target = init.MakePointerAccess (rc, type, args);
11830 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11831 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11832 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11836 target = new IndexerExpr (indexers, type, init, args, loc);
11842 // A block of object or collection initializers
11844 public class CollectionOrObjectInitializers : ExpressionStatement
11846 IList<Expression> initializers;
11847 bool is_collection_initialization;
11849 public CollectionOrObjectInitializers (Location loc)
11850 : this (new Expression[0], loc)
11854 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11856 this.initializers = initializers;
11860 public IList<Expression> Initializers {
11862 return initializers;
11866 public bool IsEmpty {
11868 return initializers.Count == 0;
11872 public bool IsCollectionInitializer {
11874 return is_collection_initialization;
11878 protected override void CloneTo (CloneContext clonectx, Expression target)
11880 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11882 t.initializers = new List<Expression> (initializers.Count);
11883 foreach (var e in initializers)
11884 t.initializers.Add (e.Clone (clonectx));
11887 public override bool ContainsEmitWithAwait ()
11889 foreach (var e in initializers) {
11890 if (e.ContainsEmitWithAwait ())
11897 public override Expression CreateExpressionTree (ResolveContext ec)
11899 return CreateExpressionTree (ec, false);
11902 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11904 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11905 foreach (Expression e in initializers) {
11906 Expression expr = e.CreateExpressionTree (ec);
11908 expr_initializers.Add (expr);
11912 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11914 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11917 protected override Expression DoResolve (ResolveContext ec)
11919 List<string> element_names = null;
11920 for (int i = 0; i < initializers.Count; ++i) {
11921 Expression initializer = initializers [i];
11922 ElementInitializer element_initializer = initializer as ElementInitializer;
11925 if (element_initializer != null) {
11926 element_names = new List<string> (initializers.Count);
11927 if (!element_initializer.IsDictionaryInitializer)
11928 element_names.Add (element_initializer.Name);
11929 } else if (initializer is CompletingExpression) {
11930 initializer.Resolve (ec);
11931 throw new InternalErrorException ("This line should never be reached");
11933 var t = ec.CurrentInitializerVariable.Type;
11934 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11935 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11936 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11937 "object initializer because type `{1}' does not implement `{2}' interface",
11938 ec.CurrentInitializerVariable.GetSignatureForError (),
11939 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11940 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11943 is_collection_initialization = true;
11946 if (is_collection_initialization != (element_initializer == null)) {
11947 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11948 is_collection_initialization ? "collection initializer" : "object initializer");
11952 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11953 if (element_names.Contains (element_initializer.Name)) {
11954 ec.Report.Error (1912, element_initializer.Location,
11955 "An object initializer includes more than one member `{0}' initialization",
11956 element_initializer.Name);
11958 element_names.Add (element_initializer.Name);
11963 Expression e = initializer.Resolve (ec);
11964 if (e == EmptyExpressionStatement.Instance)
11965 initializers.RemoveAt (i--);
11967 initializers [i] = e;
11970 type = ec.CurrentInitializerVariable.Type;
11971 if (is_collection_initialization) {
11972 if (TypeManager.HasElementType (type)) {
11973 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11974 type.GetSignatureForError ());
11978 eclass = ExprClass.Variable;
11982 public override void Emit (EmitContext ec)
11984 EmitStatement (ec);
11987 public override void EmitStatement (EmitContext ec)
11989 foreach (ExpressionStatement e in initializers) {
11990 // TODO: need location region
11991 ec.Mark (e.Location);
11992 e.EmitStatement (ec);
11996 public override void FlowAnalysis (FlowAnalysisContext fc)
11998 foreach (var initializer in initializers) {
11999 if (initializer != null)
12000 initializer.FlowAnalysis (fc);
12006 // New expression with element/object initializers
12008 public class NewInitialize : New
12011 // This class serves as a proxy for variable initializer target instances.
12012 // A real variable is assigned later when we resolve left side of an
12015 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12017 NewInitialize new_instance;
12019 public InitializerTargetExpression (NewInitialize newInstance)
12021 this.type = newInstance.type;
12022 this.loc = newInstance.loc;
12023 this.eclass = newInstance.eclass;
12024 this.new_instance = newInstance;
12027 public override bool ContainsEmitWithAwait ()
12032 public override Expression CreateExpressionTree (ResolveContext ec)
12034 // Should not be reached
12035 throw new NotSupportedException ("ET");
12038 protected override Expression DoResolve (ResolveContext ec)
12043 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12048 public override void Emit (EmitContext ec)
12050 Expression e = (Expression) new_instance.instance;
12054 public override Expression EmitToField (EmitContext ec)
12056 return (Expression) new_instance.instance;
12059 #region IMemoryLocation Members
12061 public void AddressOf (EmitContext ec, AddressOp mode)
12063 new_instance.instance.AddressOf (ec, mode);
12069 CollectionOrObjectInitializers initializers;
12070 IMemoryLocation instance;
12071 DynamicExpressionStatement dynamic;
12073 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12074 : base (requested_type, arguments, l)
12076 this.initializers = initializers;
12079 public CollectionOrObjectInitializers Initializers {
12081 return initializers;
12085 protected override void CloneTo (CloneContext clonectx, Expression t)
12087 base.CloneTo (clonectx, t);
12089 NewInitialize target = (NewInitialize) t;
12090 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12093 public override bool ContainsEmitWithAwait ()
12095 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12098 public override Expression CreateExpressionTree (ResolveContext ec)
12100 Arguments args = new Arguments (2);
12101 args.Add (new Argument (base.CreateExpressionTree (ec)));
12102 if (!initializers.IsEmpty)
12103 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12105 return CreateExpressionFactoryCall (ec,
12106 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12110 protected override Expression DoResolve (ResolveContext ec)
12112 Expression e = base.DoResolve (ec);
12116 if (type.IsDelegate) {
12117 ec.Report.Error (1958, Initializers.Location,
12118 "Object and collection initializers cannot be used to instantiate a delegate");
12121 Expression previous = ec.CurrentInitializerVariable;
12122 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12123 initializers.Resolve (ec);
12124 ec.CurrentInitializerVariable = previous;
12126 dynamic = e as DynamicExpressionStatement;
12127 if (dynamic != null)
12133 public override void Emit (EmitContext ec)
12135 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12136 var fe = ec.GetTemporaryField (type);
12138 if (!Emit (ec, fe))
12147 public override bool Emit (EmitContext ec, IMemoryLocation target)
12150 // Expression is initialized into temporary target then moved
12151 // to real one for atomicity
12153 IMemoryLocation temp_target = target;
12155 LocalTemporary temp = null;
12156 bool by_ref = false;
12157 if (!initializers.IsEmpty) {
12158 temp_target = target as LocalTemporary;
12159 if (temp_target == null)
12160 temp_target = target as StackFieldExpr;
12162 if (temp_target == null) {
12163 var vr = target as VariableReference;
12164 if (vr != null && vr.IsRef) {
12170 if (temp_target == null)
12171 temp_target = temp = new LocalTemporary (type);
12174 bool left_on_stack;
12175 if (dynamic != null) {
12177 left_on_stack = true;
12179 left_on_stack = base.Emit (ec, temp_target);
12182 if (initializers.IsEmpty)
12183 return left_on_stack;
12185 StackFieldExpr sf = null;
12187 // Move a new instance (reference-type) to local temporary variable
12188 if (left_on_stack) {
12190 temp_target = temp = new LocalTemporary (type);
12196 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12198 throw new NotImplementedException ();
12200 sf = ec.GetTemporaryField (type);
12201 sf.EmitAssign (ec, temp, false, false);
12204 left_on_stack = false;
12208 instance = temp_target;
12210 initializers.Emit (ec);
12212 ((Expression)temp_target).Emit (ec);
12218 sf.IsAvailableForReuse = true;
12223 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12225 instance = base.EmitAddressOf (ec, Mode);
12227 if (!initializers.IsEmpty)
12228 initializers.Emit (ec);
12233 public override void FlowAnalysis (FlowAnalysisContext fc)
12235 base.FlowAnalysis (fc);
12236 initializers.FlowAnalysis (fc);
12239 public override object Accept (StructuralVisitor visitor)
12241 return visitor.Visit (this);
12245 public class NewAnonymousType : New
12247 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12249 List<AnonymousTypeParameter> parameters;
12250 readonly TypeContainer parent;
12251 AnonymousTypeClass anonymous_type;
12253 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12254 : base (null, null, loc)
12256 this.parameters = parameters;
12257 this.parent = parent;
12260 public List<AnonymousTypeParameter> Parameters {
12262 return this.parameters;
12266 protected override void CloneTo (CloneContext clonectx, Expression target)
12268 if (parameters == null)
12271 NewAnonymousType t = (NewAnonymousType) target;
12272 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12273 foreach (AnonymousTypeParameter atp in parameters)
12274 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12277 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12279 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12283 type = AnonymousTypeClass.Create (parent, parameters, loc);
12287 int errors = ec.Report.Errors;
12288 type.CreateContainer ();
12289 type.DefineContainer ();
12291 if ((ec.Report.Errors - errors) == 0) {
12292 parent.Module.AddAnonymousType (type);
12293 type.PrepareEmit ();
12299 public override Expression CreateExpressionTree (ResolveContext ec)
12301 if (parameters == null)
12302 return base.CreateExpressionTree (ec);
12304 var init = new ArrayInitializer (parameters.Count, loc);
12305 foreach (var m in anonymous_type.Members) {
12306 var p = m as Property;
12308 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12311 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12312 foreach (Argument a in arguments)
12313 ctor_args.Add (a.CreateExpressionTree (ec));
12315 Arguments args = new Arguments (3);
12316 args.Add (new Argument (new TypeOfMethod (method, loc)));
12317 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12318 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12320 return CreateExpressionFactoryCall (ec, "New", args);
12323 protected override Expression DoResolve (ResolveContext ec)
12325 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12326 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12330 if (parameters == null) {
12331 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12332 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12333 return base.DoResolve (ec);
12336 bool error = false;
12337 arguments = new Arguments (parameters.Count);
12338 var t_args = new TypeSpec [parameters.Count];
12339 for (int i = 0; i < parameters.Count; ++i) {
12340 Expression e = parameters [i].Resolve (ec);
12346 arguments.Add (new Argument (e));
12347 t_args [i] = e.Type;
12353 anonymous_type = CreateAnonymousType (ec, parameters);
12354 if (anonymous_type == null)
12357 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12358 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12359 eclass = ExprClass.Value;
12363 public override object Accept (StructuralVisitor visitor)
12365 return visitor.Visit (this);
12369 public class AnonymousTypeParameter : ShimExpression
12371 public readonly string Name;
12373 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12374 : base (initializer)
12380 public AnonymousTypeParameter (Parameter parameter)
12381 : base (new SimpleName (parameter.Name, parameter.Location))
12383 this.Name = parameter.Name;
12384 this.loc = parameter.Location;
12387 public override bool Equals (object o)
12389 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12390 return other != null && Name == other.Name;
12393 public override int GetHashCode ()
12395 return Name.GetHashCode ();
12398 protected override Expression DoResolve (ResolveContext ec)
12400 Expression e = expr.Resolve (ec);
12404 if (e.eclass == ExprClass.MethodGroup) {
12405 Error_InvalidInitializer (ec, e.ExprClassName);
12410 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12411 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12418 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12420 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12421 Name, initializer);
12425 public class CatchFilterExpression : BooleanExpression
12427 public CatchFilterExpression (Expression expr, Location loc)
12434 public class InterpolatedString : Expression
12436 readonly StringLiteral start, end;
12437 List<Expression> interpolations;
12438 Arguments arguments;
12440 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12442 this.start = start;
12444 this.interpolations = interpolations;
12445 loc = start.Location;
12448 protected override void CloneTo (CloneContext clonectx, Expression t)
12450 InterpolatedString target = (InterpolatedString) t;
12452 if (interpolations != null) {
12453 target.interpolations = new List<Expression> ();
12454 foreach (var interpolation in interpolations) {
12455 target.interpolations.Add (interpolation.Clone (clonectx));
12460 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12462 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12463 if (factory == null)
12466 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12467 var res = new Invocation (ma, arguments).Resolve (rc);
12468 if (res != null && res.Type != type)
12469 res = Convert.ExplicitConversion (rc, res, type, loc);
12474 public override bool ContainsEmitWithAwait ()
12476 if (interpolations == null)
12479 foreach (var expr in interpolations) {
12480 if (expr.ContainsEmitWithAwait ())
12487 public override Expression CreateExpressionTree (ResolveContext rc)
12489 var best = ResolveBestFormatOverload (rc);
12493 Expression instance = new NullLiteral (loc);
12494 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12495 return CreateExpressionFactoryCall (rc, "Call", args);
12498 protected override Expression DoResolve (ResolveContext rc)
12502 if (interpolations == null) {
12504 arguments = new Arguments (1);
12506 for (int i = 0; i < interpolations.Count; i += 2) {
12507 var ipi = (InterpolatedStringInsert)interpolations [i];
12511 arguments = new Arguments (interpolations.Count);
12513 var sb = new StringBuilder (start.Value);
12514 for (int i = 0; i < interpolations.Count; ++i) {
12516 sb.Append ('{').Append (i / 2);
12517 var isi = (InterpolatedStringInsert)interpolations [i];
12518 if (isi.Alignment != null) {
12520 var value = isi.ResolveAligment (rc);
12522 sb.Append (value.Value);
12525 if (isi.Format != null) {
12527 sb.Append (isi.Format);
12531 arguments.Add (new Argument (interpolations [i]));
12533 sb.Append (((StringLiteral)interpolations [i]).Value);
12537 sb.Append (end.Value);
12538 str = sb.ToString ();
12541 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12543 eclass = ExprClass.Value;
12544 type = rc.BuiltinTypes.String;
12548 public override void Emit (EmitContext ec)
12550 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12551 if (interpolations == null) {
12552 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12553 if (str != start.Value)
12554 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12561 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12565 var ca = new CallEmitter ();
12566 ca.Emit (ec, best, arguments, loc);
12569 public override void FlowAnalysis (FlowAnalysisContext fc)
12571 if (interpolations != null) {
12572 foreach (var expr in interpolations) {
12573 expr.FlowAnalysis (fc);
12578 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12580 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12581 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12582 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12586 public class InterpolatedStringInsert : CompositeExpression
12588 public InterpolatedStringInsert (Expression expr)
12593 public Expression Alignment { get; set; }
12594 public string Format { get; set; }
12596 protected override void CloneTo (CloneContext clonectx, Expression t)
12598 var target = (InterpolatedStringInsert)t;
12599 target.expr = expr.Clone (clonectx);
12600 if (Alignment != null)
12601 target.Alignment = Alignment.Clone (clonectx);
12604 protected override Expression DoResolve (ResolveContext rc)
12606 var expr = base.DoResolve (rc);
12611 // For better error reporting, assumes the built-in implementation uses object
12614 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12617 public override void FlowAnalysis (FlowAnalysisContext fc)
12619 Child.FlowAnalysis (fc);
12622 public int? ResolveAligment (ResolveContext rc)
12624 var c = Alignment.ResolveLabelConstant (rc);
12628 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12632 var value = (int) c.GetValueAsLong ();
12633 if (value > 32767 || value < -32767) {
12634 rc.Report.Warning (8094, 1, Alignment.Location,
12635 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");