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 ec)
112 var res = expr.Resolve (ec);
113 var constant = res as Constant;
114 if (constant != null && constant.IsLiteral)
115 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
120 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
122 return expr.DoResolveLValue (ec, right_side);
125 public override object Accept (StructuralVisitor visitor)
127 return visitor.Visit (this);
130 public override bool HasConditionalAccess ()
132 return expr.HasConditionalAccess ();
137 // Unary implements unary expressions.
139 public class Unary : Expression
141 public enum Operator : byte {
142 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
146 public readonly Operator Oper;
147 public Expression Expr;
148 ConvCast.Mode enum_conversion;
150 public Unary (Operator op, Expression expr, Location loc)
158 // This routine will attempt to simplify the unary expression when the
159 // argument is a constant.
161 Constant TryReduceConstant (ResolveContext ec, Constant constant)
165 while (e is EmptyConstantCast)
166 e = ((EmptyConstantCast) e).child;
168 if (e is SideEffectConstant) {
169 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
170 return r == null ? null : new SideEffectConstant (r, e, r.Location);
173 TypeSpec expr_type = e.Type;
176 case Operator.UnaryPlus:
177 // Unary numeric promotions
178 switch (expr_type.BuiltinType) {
179 case BuiltinTypeSpec.Type.Byte:
180 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
181 case BuiltinTypeSpec.Type.SByte:
182 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
183 case BuiltinTypeSpec.Type.Short:
184 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
185 case BuiltinTypeSpec.Type.UShort:
186 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
187 case BuiltinTypeSpec.Type.Char:
188 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
190 // Predefined operators
191 case BuiltinTypeSpec.Type.Int:
192 case BuiltinTypeSpec.Type.UInt:
193 case BuiltinTypeSpec.Type.Long:
194 case BuiltinTypeSpec.Type.ULong:
195 case BuiltinTypeSpec.Type.Float:
196 case BuiltinTypeSpec.Type.Double:
197 case BuiltinTypeSpec.Type.Decimal:
203 case Operator.UnaryNegation:
204 // Unary numeric promotions
205 switch (expr_type.BuiltinType) {
206 case BuiltinTypeSpec.Type.Byte:
207 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
208 case BuiltinTypeSpec.Type.SByte:
209 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
210 case BuiltinTypeSpec.Type.Short:
211 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
212 case BuiltinTypeSpec.Type.UShort:
213 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
214 case BuiltinTypeSpec.Type.Char:
215 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
217 // Predefined operators
218 case BuiltinTypeSpec.Type.Int:
219 int ivalue = ((IntConstant) e).Value;
220 if (ivalue == int.MinValue) {
221 if (ec.ConstantCheckState) {
222 ConstantFold.Error_CompileTimeOverflow (ec, loc);
227 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
229 case BuiltinTypeSpec.Type.Long:
230 long lvalue = ((LongConstant) e).Value;
231 if (lvalue == long.MinValue) {
232 if (ec.ConstantCheckState) {
233 ConstantFold.Error_CompileTimeOverflow (ec, loc);
238 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
240 case BuiltinTypeSpec.Type.UInt:
241 UIntLiteral uil = constant as UIntLiteral;
243 if (uil.Value == int.MaxValue + (uint) 1)
244 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
245 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
247 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
250 case BuiltinTypeSpec.Type.ULong:
251 ULongLiteral ull = constant as ULongLiteral;
252 if (ull != null && ull.Value == 9223372036854775808)
253 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
256 case BuiltinTypeSpec.Type.Float:
257 FloatLiteral fl = constant as FloatLiteral;
258 // For better error reporting
260 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
262 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
264 case BuiltinTypeSpec.Type.Double:
265 DoubleLiteral dl = constant as DoubleLiteral;
266 // For better error reporting
268 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
270 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
272 case BuiltinTypeSpec.Type.Decimal:
273 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
278 case Operator.LogicalNot:
279 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
282 bool b = (bool)e.GetValue ();
283 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
285 case Operator.OnesComplement:
286 // Unary numeric promotions
287 switch (expr_type.BuiltinType) {
288 case BuiltinTypeSpec.Type.Byte:
289 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
290 case BuiltinTypeSpec.Type.SByte:
291 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
292 case BuiltinTypeSpec.Type.Short:
293 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
294 case BuiltinTypeSpec.Type.UShort:
295 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
296 case BuiltinTypeSpec.Type.Char:
297 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
299 // Predefined operators
300 case BuiltinTypeSpec.Type.Int:
301 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
302 case BuiltinTypeSpec.Type.UInt:
303 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
304 case BuiltinTypeSpec.Type.Long:
305 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
306 case BuiltinTypeSpec.Type.ULong:
307 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
309 if (e is EnumConstant) {
310 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
313 // Numeric promotion upgraded types to int but for enum constant
314 // original underlying constant type is needed
316 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
317 int v = ((IntConstant) res).Value;
318 switch (((EnumConstant) e).Child.Type.BuiltinType) {
319 case BuiltinTypeSpec.Type.UShort:
320 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
322 case BuiltinTypeSpec.Type.Short:
323 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
325 case BuiltinTypeSpec.Type.Byte:
326 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
328 case BuiltinTypeSpec.Type.SByte:
329 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
334 res = new EnumConstant (res, expr_type);
340 throw new Exception ("Can not constant fold: " + Oper.ToString());
343 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
345 eclass = ExprClass.Value;
347 TypeSpec expr_type = expr.Type;
348 Expression best_expr;
350 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
353 // Primitive types first
355 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
356 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
357 if (best_expr == null)
360 type = best_expr.Type;
366 // E operator ~(E x);
368 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
369 return ResolveEnumOperator (ec, expr, predefined);
371 return ResolveUserType (ec, expr, predefined);
374 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
376 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
377 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
378 if (best_expr == null)
382 enum_conversion = Binary.GetEnumResultCast (underlying_type);
384 return EmptyCast.Create (this, type);
387 public override bool ContainsEmitWithAwait ()
389 return Expr.ContainsEmitWithAwait ();
392 public override Expression CreateExpressionTree (ResolveContext ec)
394 return CreateExpressionTree (ec, null);
397 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
401 case Operator.AddressOf:
402 Error_PointerInsideExpressionTree (ec);
404 case Operator.UnaryNegation:
405 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
406 method_name = "NegateChecked";
408 method_name = "Negate";
410 case Operator.OnesComplement:
411 case Operator.LogicalNot:
414 case Operator.UnaryPlus:
415 method_name = "UnaryPlus";
418 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
421 Arguments args = new Arguments (2);
422 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
424 args.Add (new Argument (user_op));
426 return CreateExpressionFactoryCall (ec, method_name, args);
429 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
431 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
434 // 7.6.1 Unary plus operator
436 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
437 types.Int, types.UInt,
438 types.Long, types.ULong,
439 types.Float, types.Double,
444 // 7.6.2 Unary minus operator
446 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
447 types.Int, types.Long,
448 types.Float, types.Double,
453 // 7.6.3 Logical negation operator
455 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
460 // 7.6.4 Bitwise complement operator
462 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
463 types.Int, types.UInt,
464 types.Long, types.ULong
467 return predefined_operators;
471 // Unary numeric promotions
473 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
475 TypeSpec expr_type = expr.Type;
476 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
477 switch (expr_type.BuiltinType) {
478 case BuiltinTypeSpec.Type.Byte:
479 case BuiltinTypeSpec.Type.SByte:
480 case BuiltinTypeSpec.Type.Short:
481 case BuiltinTypeSpec.Type.UShort:
482 case BuiltinTypeSpec.Type.Char:
483 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
487 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
488 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
493 protected override Expression DoResolve (ResolveContext ec)
495 if (Oper == Operator.AddressOf) {
496 return ResolveAddressOf (ec);
499 Expr = Expr.Resolve (ec);
503 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
504 Arguments args = new Arguments (1);
505 args.Add (new Argument (Expr));
506 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
509 if (Expr.Type.IsNullableType)
510 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
513 // Attempt to use a constant folding operation.
515 Constant cexpr = Expr as Constant;
517 cexpr = TryReduceConstant (ec, cexpr);
522 Expression expr = ResolveOperator (ec, Expr);
524 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
527 // Reduce unary operator on predefined types
529 if (expr == this && Oper == Operator.UnaryPlus)
535 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
540 public override void Emit (EmitContext ec)
542 EmitOperator (ec, type);
545 protected void EmitOperator (EmitContext ec, TypeSpec type)
548 case Operator.UnaryPlus:
552 case Operator.UnaryNegation:
553 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
554 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
555 Expr = Expr.EmitToField (ec);
558 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
559 ec.Emit (OpCodes.Conv_U8);
561 ec.Emit (OpCodes.Sub_Ovf);
564 ec.Emit (OpCodes.Neg);
569 case Operator.LogicalNot:
572 ec.Emit (OpCodes.Ceq);
575 case Operator.OnesComplement:
577 ec.Emit (OpCodes.Not);
580 case Operator.AddressOf:
581 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
585 throw new Exception ("This should not happen: Operator = "
590 // Same trick as in Binary expression
592 if (enum_conversion != 0) {
593 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
594 ConvCast.Emit (ec, enum_conversion);
599 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
601 if (Oper == Operator.LogicalNot)
602 Expr.EmitBranchable (ec, target, !on_true);
604 base.EmitBranchable (ec, target, on_true);
607 public override void EmitSideEffect (EmitContext ec)
609 Expr.EmitSideEffect (ec);
612 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
614 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
615 oper, type.GetSignatureForError ());
618 public override void FlowAnalysis (FlowAnalysisContext fc)
620 FlowAnalysis (fc, false);
623 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
625 FlowAnalysis (fc, true);
628 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
630 if (Oper == Operator.AddressOf) {
631 var vr = Expr as VariableReference;
632 if (vr != null && vr.VariableInfo != null)
633 fc.SetVariableAssigned (vr.VariableInfo);
638 if (Oper == Operator.LogicalNot && conditional) {
639 Expr.FlowAnalysisConditional (fc);
641 var temp = fc.DefiniteAssignmentOnTrue;
642 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
643 fc.DefiniteAssignmentOnFalse = temp;
645 Expr.FlowAnalysis (fc);
650 // Converts operator to System.Linq.Expressions.ExpressionType enum name
652 string GetOperatorExpressionTypeName ()
655 case Operator.OnesComplement:
656 return "OnesComplement";
657 case Operator.LogicalNot:
659 case Operator.UnaryNegation:
661 case Operator.UnaryPlus:
664 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
668 static bool IsFloat (TypeSpec t)
670 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
674 // Returns a stringified representation of the Operator
676 public static string OperName (Operator oper)
679 case Operator.UnaryPlus:
681 case Operator.UnaryNegation:
683 case Operator.LogicalNot:
685 case Operator.OnesComplement:
687 case Operator.AddressOf:
691 throw new NotImplementedException (oper.ToString ());
694 public override SLE.Expression MakeExpression (BuilderContext ctx)
696 var expr = Expr.MakeExpression (ctx);
697 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
700 case Operator.UnaryNegation:
701 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
702 case Operator.LogicalNot:
703 return SLE.Expression.Not (expr);
704 case Operator.OnesComplement:
705 return SLE.Expression.OnesComplement (expr);
707 throw new NotImplementedException (Oper.ToString ());
711 Expression ResolveAddressOf (ResolveContext ec)
714 UnsafeError (ec, loc);
716 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
717 if (Expr == null || Expr.eclass != ExprClass.Variable) {
718 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
722 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
726 IVariableReference vr = Expr as IVariableReference;
729 is_fixed = vr.IsFixed;
730 vr.SetHasAddressTaken ();
733 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
736 IFixedExpression fe = Expr as IFixedExpression;
737 is_fixed = fe != null && fe.IsFixed;
740 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
741 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
744 type = PointerContainer.MakeType (ec.Module, Expr.Type);
745 eclass = ExprClass.Value;
749 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
751 expr = DoNumericPromotion (rc, Oper, expr);
752 TypeSpec expr_type = expr.Type;
753 foreach (TypeSpec t in predefined) {
761 // Perform user-operator overload resolution
763 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
765 CSharp.Operator.OpType op_type;
767 case Operator.LogicalNot:
768 op_type = CSharp.Operator.OpType.LogicalNot; break;
769 case Operator.OnesComplement:
770 op_type = CSharp.Operator.OpType.OnesComplement; break;
771 case Operator.UnaryNegation:
772 op_type = CSharp.Operator.OpType.UnaryNegation; break;
773 case Operator.UnaryPlus:
774 op_type = CSharp.Operator.OpType.UnaryPlus; break;
776 throw new InternalErrorException (Oper.ToString ());
779 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
783 Arguments args = new Arguments (1);
784 args.Add (new Argument (expr));
786 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
787 var oper = res.ResolveOperator (ec, ref args);
792 Expr = args [0].Expr;
793 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
797 // Unary user type overload resolution
799 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
801 Expression best_expr = ResolveUserOperator (ec, expr);
802 if (best_expr != null)
805 foreach (TypeSpec t in predefined) {
806 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
807 if (oper_expr == null)
810 if (oper_expr == ErrorExpression.Instance)
814 // decimal type is predefined but has user-operators
816 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
817 oper_expr = ResolveUserType (ec, oper_expr, predefined);
819 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
821 if (oper_expr == null)
824 if (best_expr == null) {
825 best_expr = oper_expr;
829 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
831 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
832 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
834 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
841 best_expr = oper_expr;
844 if (best_expr == null)
848 // HACK: Decimal user-operator is included in standard operators
850 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
854 type = best_expr.Type;
858 protected override void CloneTo (CloneContext clonectx, Expression t)
860 Unary target = (Unary) t;
862 target.Expr = Expr.Clone (clonectx);
865 public override object Accept (StructuralVisitor visitor)
867 return visitor.Visit (this);
873 // Unary operators are turned into Indirection expressions
874 // after semantic analysis (this is so we can take the address
875 // of an indirection).
877 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
879 LocalTemporary temporary;
882 public Indirection (Expression expr, Location l)
888 public Expression Expr {
894 public bool IsFixed {
898 public override Location StartLocation {
900 return expr.StartLocation;
904 protected override void CloneTo (CloneContext clonectx, Expression t)
906 Indirection target = (Indirection) t;
907 target.expr = expr.Clone (clonectx);
910 public override bool ContainsEmitWithAwait ()
912 throw new NotImplementedException ();
915 public override Expression CreateExpressionTree (ResolveContext ec)
917 Error_PointerInsideExpressionTree (ec);
921 public override void Emit (EmitContext ec)
926 ec.EmitLoadFromPtr (Type);
929 public void Emit (EmitContext ec, bool leave_copy)
933 ec.Emit (OpCodes.Dup);
934 temporary = new LocalTemporary (expr.Type);
935 temporary.Store (ec);
939 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
941 prepared = isCompound;
946 ec.Emit (OpCodes.Dup);
950 ec.Emit (OpCodes.Dup);
951 temporary = new LocalTemporary (source.Type);
952 temporary.Store (ec);
955 ec.EmitStoreFromPtr (type);
957 if (temporary != null) {
959 temporary.Release (ec);
963 public void AddressOf (EmitContext ec, AddressOp Mode)
968 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
970 return DoResolve (ec);
973 protected override Expression DoResolve (ResolveContext ec)
975 expr = expr.Resolve (ec);
980 UnsafeError (ec, loc);
982 var pc = expr.Type as PointerContainer;
985 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
991 if (type.Kind == MemberKind.Void) {
992 Error_VoidPointerOperation (ec);
996 eclass = ExprClass.Variable;
1000 public override object Accept (StructuralVisitor visitor)
1002 return visitor.Visit (this);
1007 /// Unary Mutator expressions (pre and post ++ and --)
1011 /// UnaryMutator implements ++ and -- expressions. It derives from
1012 /// ExpressionStatement becuase the pre/post increment/decrement
1013 /// operators can be used in a statement context.
1015 /// FIXME: Idea, we could split this up in two classes, one simpler
1016 /// for the common case, and one with the extra fields for more complex
1017 /// classes (indexers require temporary access; overloaded require method)
1020 public class UnaryMutator : ExpressionStatement
1022 class DynamicPostMutator : Expression, IAssignMethod
1024 LocalTemporary temp;
1027 public DynamicPostMutator (Expression expr)
1030 this.type = expr.Type;
1031 this.loc = expr.Location;
1034 public override Expression CreateExpressionTree (ResolveContext ec)
1036 throw new NotImplementedException ("ET");
1039 protected override Expression DoResolve (ResolveContext rc)
1041 eclass = expr.eclass;
1045 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1047 expr.DoResolveLValue (ec, right_side);
1048 return DoResolve (ec);
1051 public override void Emit (EmitContext ec)
1056 public void Emit (EmitContext ec, bool leave_copy)
1058 throw new NotImplementedException ();
1062 // Emits target assignment using unmodified source value
1064 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1067 // Allocate temporary variable to keep original value before it's modified
1069 temp = new LocalTemporary (type);
1073 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1084 public enum Mode : byte {
1091 PreDecrement = IsDecrement,
1092 PostIncrement = IsPost,
1093 PostDecrement = IsPost | IsDecrement
1097 bool is_expr, recurse;
1099 protected Expression expr;
1101 // Holds the real operation
1102 Expression operation;
1104 public UnaryMutator (Mode m, Expression e, Location loc)
1111 public Mode UnaryMutatorMode {
1117 public Expression Expr {
1123 public override Location StartLocation {
1125 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1129 public override bool ContainsEmitWithAwait ()
1131 return expr.ContainsEmitWithAwait ();
1134 public override Expression CreateExpressionTree (ResolveContext ec)
1136 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1139 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1142 // Predefined ++ and -- operators exist for the following types:
1143 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1145 return new TypeSpec[] {
1161 protected override Expression DoResolve (ResolveContext ec)
1163 expr = expr.Resolve (ec);
1165 if (expr == null || expr.Type == InternalType.ErrorType)
1168 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1170 // Handle postfix unary operators using local
1171 // temporary variable
1173 if ((mode & Mode.IsPost) != 0)
1174 expr = new DynamicPostMutator (expr);
1176 Arguments args = new Arguments (1);
1177 args.Add (new Argument (expr));
1178 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1181 if (expr.Type.IsNullableType)
1182 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1184 return DoResolveOperation (ec);
1187 protected Expression DoResolveOperation (ResolveContext ec)
1189 eclass = ExprClass.Value;
1192 if (expr is RuntimeValueExpression) {
1195 // Use itself at the top of the stack
1196 operation = new EmptyExpression (type);
1200 // The operand of the prefix/postfix increment decrement operators
1201 // should be an expression that is classified as a variable,
1202 // a property access or an indexer access
1204 // TODO: Move to parser, expr is ATypeNameExpression
1205 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1206 expr = expr.ResolveLValue (ec, expr);
1208 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1212 // Step 1: Try to find a user operator, it has priority over predefined ones
1214 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1215 var methods = MemberCache.GetUserOperator (type, user_op, false);
1217 if (methods != null) {
1218 Arguments args = new Arguments (1);
1219 args.Add (new Argument (expr));
1221 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1222 var method = res.ResolveOperator (ec, ref args);
1226 args[0].Expr = operation;
1227 operation = new UserOperatorCall (method, args, null, loc);
1228 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1233 // Step 2: Try predefined types
1236 Expression source = null;
1237 bool primitive_type;
1240 // Predefined without user conversion first for speed-up
1242 // Predefined ++ and -- operators exist for the following types:
1243 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1245 switch (type.BuiltinType) {
1246 case BuiltinTypeSpec.Type.Byte:
1247 case BuiltinTypeSpec.Type.SByte:
1248 case BuiltinTypeSpec.Type.Short:
1249 case BuiltinTypeSpec.Type.UShort:
1250 case BuiltinTypeSpec.Type.Int:
1251 case BuiltinTypeSpec.Type.UInt:
1252 case BuiltinTypeSpec.Type.Long:
1253 case BuiltinTypeSpec.Type.ULong:
1254 case BuiltinTypeSpec.Type.Char:
1255 case BuiltinTypeSpec.Type.Float:
1256 case BuiltinTypeSpec.Type.Double:
1257 case BuiltinTypeSpec.Type.Decimal:
1259 primitive_type = true;
1262 primitive_type = false;
1264 // ++/-- on pointer variables of all types except void*
1265 if (type.IsPointer) {
1266 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1267 Error_VoidPointerOperation (ec);
1273 Expression best_source = null;
1274 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1275 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1277 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1281 if (best_source == null) {
1282 best_source = source;
1286 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1291 best_source = source;
1295 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1299 source = best_source;
1302 // ++/-- on enum types
1303 if (source == null && type.IsEnum)
1306 if (source == null) {
1307 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1314 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1315 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1316 operation = new Binary (op, source, one);
1317 operation = operation.Resolve (ec);
1318 if (operation == null)
1319 throw new NotImplementedException ("should not be reached");
1321 if (operation.Type != type) {
1323 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1325 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1331 void EmitCode (EmitContext ec, bool is_expr)
1334 this.is_expr = is_expr;
1335 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1338 public override void Emit (EmitContext ec)
1341 // We use recurse to allow ourselfs to be the source
1342 // of an assignment. This little hack prevents us from
1343 // having to allocate another expression
1346 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1354 EmitCode (ec, true);
1357 protected virtual void EmitOperation (EmitContext ec)
1359 operation.Emit (ec);
1362 public override void EmitStatement (EmitContext ec)
1364 EmitCode (ec, false);
1367 public override void FlowAnalysis (FlowAnalysisContext fc)
1369 expr.FlowAnalysis (fc);
1373 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1375 string GetOperatorExpressionTypeName ()
1377 return IsDecrement ? "Decrement" : "Increment";
1381 get { return (mode & Mode.IsDecrement) != 0; }
1385 #if NET_4_0 || MOBILE_DYNAMIC
1386 public override SLE.Expression MakeExpression (BuilderContext ctx)
1388 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1389 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1390 return SLE.Expression.Assign (target, source);
1394 public static string OperName (Mode oper)
1396 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1399 protected override void CloneTo (CloneContext clonectx, Expression t)
1401 UnaryMutator target = (UnaryMutator) t;
1403 target.expr = expr.Clone (clonectx);
1406 public override object Accept (StructuralVisitor visitor)
1408 return visitor.Visit (this);
1414 // Base class for the `is' and `as' operators
1416 public abstract class Probe : Expression
1418 public Expression ProbeType;
1419 protected Expression expr;
1420 protected TypeSpec probe_type_expr;
1422 protected Probe (Expression expr, Expression probe_type, Location l)
1424 ProbeType = probe_type;
1429 public Expression Expr {
1435 public override bool ContainsEmitWithAwait ()
1437 return expr.ContainsEmitWithAwait ();
1440 protected Expression ResolveCommon (ResolveContext rc)
1442 expr = expr.Resolve (rc);
1446 ResolveProbeType (rc);
1447 if (probe_type_expr == null)
1450 if (probe_type_expr.IsStatic) {
1451 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1452 probe_type_expr.GetSignatureForError ());
1456 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1457 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1462 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1463 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1471 protected virtual void ResolveProbeType (ResolveContext rc)
1473 probe_type_expr = ProbeType.ResolveAsType (rc);
1476 public override void EmitSideEffect (EmitContext ec)
1478 expr.EmitSideEffect (ec);
1481 public override void FlowAnalysis (FlowAnalysisContext fc)
1483 expr.FlowAnalysis (fc);
1486 public override bool HasConditionalAccess ()
1488 return expr.HasConditionalAccess ();
1491 protected abstract string OperatorName { get; }
1493 protected override void CloneTo (CloneContext clonectx, Expression t)
1495 Probe target = (Probe) t;
1497 target.expr = expr.Clone (clonectx);
1498 target.ProbeType = ProbeType.Clone (clonectx);
1504 /// Implementation of the `is' operator.
1506 public class Is : Probe
1508 Nullable.Unwrap expr_unwrap;
1509 MethodSpec number_mg;
1510 Arguments number_args;
1512 public Is (Expression expr, Expression probe_type, Location l)
1513 : base (expr, probe_type, l)
1517 protected override string OperatorName {
1518 get { return "is"; }
1521 public LocalVariable Variable { get; set; }
1523 public override Expression CreateExpressionTree (ResolveContext ec)
1525 if (Variable != null)
1526 throw new NotSupportedException ();
1528 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1529 expr.CreateExpressionTree (ec),
1530 new TypeOf (probe_type_expr, loc));
1532 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1535 Expression CreateConstantResult (ResolveContext rc, bool result)
1538 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1539 probe_type_expr.GetSignatureForError ());
1541 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1542 probe_type_expr.GetSignatureForError ());
1544 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1545 return expr.IsSideEffectFree ?
1546 ReducedExpression.Create (c, this) :
1547 new SideEffectConstant (c, this, loc);
1550 public override void Emit (EmitContext ec)
1552 if (probe_type_expr == null) {
1553 if (ProbeType is WildcardPattern) {
1554 expr.EmitSideEffect (ec);
1555 ProbeType.Emit (ec);
1557 EmitPatternMatch (ec);
1564 if (expr_unwrap == null) {
1566 ec.Emit (OpCodes.Cgt_Un);
1570 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1572 if (probe_type_expr == null) {
1573 EmitPatternMatch (ec);
1578 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1581 void EmitPatternMatch (EmitContext ec)
1583 var no_match = ec.DefineLabel ();
1584 var end = ec.DefineLabel ();
1586 if (expr_unwrap != null) {
1587 expr_unwrap.EmitCheck (ec);
1589 if (ProbeType.IsNull) {
1591 ec.Emit (OpCodes.Ceq);
1595 ec.Emit (OpCodes.Brfalse_S, no_match);
1596 expr_unwrap.Emit (ec);
1597 ProbeType.Emit (ec);
1598 ec.Emit (OpCodes.Ceq);
1599 ec.Emit (OpCodes.Br_S, end);
1600 ec.MarkLabel (no_match);
1606 if (number_args != null && number_args.Count == 3) {
1607 var ce = new CallEmitter ();
1608 ce.Emit (ec, number_mg, number_args, loc);
1612 var probe_type = ProbeType.Type;
1615 ec.Emit (OpCodes.Isinst, probe_type);
1616 ec.Emit (OpCodes.Dup);
1617 ec.Emit (OpCodes.Brfalse, no_match);
1619 bool complex_pattern = ProbeType is ComplexPatternExpression;
1620 Label prev = ec.RecursivePatternLabel;
1621 if (complex_pattern)
1622 ec.RecursivePatternLabel = ec.DefineLabel ();
1624 if (number_mg != null) {
1625 var ce = new CallEmitter ();
1626 ce.Emit (ec, number_mg, number_args, loc);
1628 if (TypeSpec.IsValueType (probe_type))
1629 ec.Emit (OpCodes.Unbox_Any, probe_type);
1631 ProbeType.Emit (ec);
1632 if (complex_pattern) {
1635 ec.Emit (OpCodes.Ceq);
1638 ec.Emit (OpCodes.Br_S, end);
1639 ec.MarkLabel (no_match);
1641 ec.Emit (OpCodes.Pop);
1643 if (complex_pattern)
1644 ec.MarkLabel (ec.RecursivePatternLabel);
1646 ec.RecursivePatternLabel = prev;
1652 void EmitLoad (EmitContext ec)
1654 Label no_value_label = new Label ();
1656 if (expr_unwrap != null) {
1657 expr_unwrap.EmitCheck (ec);
1659 if (Variable == null)
1662 ec.Emit (OpCodes.Dup);
1663 no_value_label = ec.DefineLabel ();
1664 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1665 expr_unwrap.Emit (ec);
1669 // Only to make verifier happy
1670 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1671 ec.Emit (OpCodes.Box, expr.Type);
1673 ec.Emit (OpCodes.Isinst, probe_type_expr);
1676 if (Variable != null) {
1677 bool value_on_stack;
1678 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1679 ec.Emit (OpCodes.Dup);
1680 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1681 value_on_stack = true;
1683 value_on_stack = false;
1686 Variable.CreateBuilder (ec);
1687 Variable.EmitAssign (ec);
1689 if (expr_unwrap != null) {
1690 ec.MarkLabel (no_value_label);
1691 } else if (!value_on_stack) {
1697 protected override Expression DoResolve (ResolveContext rc)
1699 if (ResolveCommon (rc) == null)
1702 type = rc.BuiltinTypes.Bool;
1703 eclass = ExprClass.Value;
1705 if (probe_type_expr == null)
1706 return ResolveMatchingExpression (rc);
1708 var res = ResolveResultExpression (rc);
1709 if (Variable != null) {
1710 if (res is Constant)
1711 throw new NotImplementedException ("constant in type pattern matching");
1713 Variable.Type = probe_type_expr;
1714 var bc = rc as BlockContext;
1716 Variable.PrepareAssignmentAnalysis (bc);
1722 public override void FlowAnalysis (FlowAnalysisContext fc)
1724 base.FlowAnalysis (fc);
1726 if (Variable != null)
1727 fc.SetVariableAssigned (Variable.VariableInfo, true);
1730 protected override void ResolveProbeType (ResolveContext rc)
1732 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1733 if (ProbeType is PatternExpression) {
1734 ProbeType.Resolve (rc);
1739 // Have to use session recording because we don't have reliable type probing
1740 // mechanism (similar issue as in attributes resolving)
1742 // TODO: This is still wrong because ResolveAsType can be destructive
1744 var type_printer = new SessionReportPrinter ();
1745 var prev_recorder = rc.Report.SetPrinter (type_printer);
1747 probe_type_expr = ProbeType.ResolveAsType (rc);
1748 type_printer.EndSession ();
1750 if (probe_type_expr != null) {
1751 type_printer.Merge (rc.Report.Printer);
1752 rc.Report.SetPrinter (prev_recorder);
1756 var vexpr = ProbeType as VarExpr;
1757 if (vexpr != null && vexpr.InferType (rc, expr)) {
1758 probe_type_expr = vexpr.Type;
1759 rc.Report.SetPrinter (prev_recorder);
1763 var expr_printer = new SessionReportPrinter ();
1764 rc.Report.SetPrinter (expr_printer);
1765 ProbeType = ProbeType.Resolve (rc);
1766 expr_printer.EndSession ();
1768 if (ProbeType != null) {
1769 expr_printer.Merge (rc.Report.Printer);
1771 type_printer.Merge (rc.Report.Printer);
1774 rc.Report.SetPrinter (prev_recorder);
1778 base.ResolveProbeType (rc);
1781 Expression ResolveMatchingExpression (ResolveContext rc)
1783 var mc = ProbeType as Constant;
1785 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1786 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1791 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1793 var c = Expr as Constant;
1795 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1800 if (Expr.Type.IsNullableType) {
1801 expr_unwrap = new Nullable.Unwrap (Expr);
1802 expr_unwrap.Resolve (rc);
1803 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1804 } else if (ProbeType.Type == Expr.Type) {
1805 // TODO: Better error handling
1806 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1807 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1808 var helper = rc.Module.CreatePatterMatchingHelper ();
1809 number_mg = helper.NumberMatcher.Spec;
1812 // There are actually 3 arguments but the first one is already on the stack
1814 number_args = new Arguments (3);
1815 if (!ProbeType.Type.IsEnum)
1816 number_args.Add (new Argument (Expr));
1818 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1819 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1825 if (ProbeType is PatternExpression) {
1826 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1827 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1833 // TODO: Better error message
1834 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1838 Expression ResolveResultExpression (ResolveContext ec)
1840 TypeSpec d = expr.Type;
1841 bool d_is_nullable = false;
1844 // If E is a method group or the null literal, or if the type of E is a reference
1845 // type or a nullable type and the value of E is null, the result is false
1847 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1848 return CreateConstantResult (ec, false);
1850 if (d.IsNullableType) {
1851 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1852 if (!ut.IsGenericParameter) {
1854 d_is_nullable = true;
1858 TypeSpec t = probe_type_expr;
1859 bool t_is_nullable = false;
1860 if (t.IsNullableType) {
1861 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1862 if (!ut.IsGenericParameter) {
1864 t_is_nullable = true;
1871 // D and T are the same value types but D can be null
1873 if (d_is_nullable && !t_is_nullable) {
1874 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1879 // The result is true if D and T are the same value types
1881 return CreateConstantResult (ec, true);
1884 var tp = d as TypeParameterSpec;
1886 return ResolveGenericParameter (ec, t, tp);
1889 // An unboxing conversion exists
1891 if (Convert.ExplicitReferenceConversionExists (d, t))
1895 // open generic type
1897 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1900 var tps = t as TypeParameterSpec;
1902 return ResolveGenericParameter (ec, d, tps);
1904 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1905 ec.Report.Warning (1981, 3, loc,
1906 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1907 OperatorName, t.GetSignatureForError ());
1910 if (TypeManager.IsGenericParameter (d))
1911 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1913 if (TypeSpec.IsValueType (d)) {
1914 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1915 if (d_is_nullable && !t_is_nullable) {
1916 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1920 return CreateConstantResult (ec, true);
1923 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1924 var c = expr as Constant;
1926 return CreateConstantResult (ec, !c.IsNull);
1929 // Do not optimize for imported type or dynamic type
1931 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1932 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1936 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1940 // Turn is check into simple null check for implicitly convertible reference types
1942 return ReducedExpression.Create (
1943 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
1947 if (Convert.ExplicitReferenceConversionExists (d, t))
1951 // open generic type
1953 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1958 return CreateConstantResult (ec, false);
1961 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1963 if (t.IsReferenceType) {
1965 return CreateConstantResult (ec, false);
1968 if (expr.Type.IsGenericParameter) {
1969 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1970 return CreateConstantResult (ec, true);
1972 expr = new BoxedCast (expr, d);
1978 public override object Accept (StructuralVisitor visitor)
1980 return visitor.Visit (this);
1984 class WildcardPattern : PatternExpression
1986 public WildcardPattern (Location loc)
1991 protected override Expression DoResolve (ResolveContext rc)
1993 eclass = ExprClass.Value;
1994 type = rc.BuiltinTypes.Object;
1998 public override void Emit (EmitContext ec)
2004 class RecursivePattern : ComplexPatternExpression
2006 MethodGroupExpr operator_mg;
2007 Arguments operator_args;
2009 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2010 : base (typeExpresion, loc)
2012 Arguments = arguments;
2015 public Arguments Arguments { get; private set; }
2017 protected override Expression DoResolve (ResolveContext rc)
2019 type = TypeExpression.ResolveAsType (rc);
2023 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2024 if (operators == null) {
2025 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2029 var ops = FindMatchingOverloads (operators);
2031 // TODO: better error message
2032 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2037 Arguments.Resolve (rc, out dynamic_args);
2039 throw new NotImplementedException ("dynamic argument");
2041 var op = FindBestOverload (rc, ops);
2043 // TODO: better error message
2044 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2048 var op_types = op.Parameters.Types;
2049 operator_args = new Arguments (op_types.Length);
2050 operator_args.Add (new Argument (new EmptyExpression (type)));
2052 for (int i = 0; i < Arguments.Count; ++i) {
2053 // TODO: Needs releasing optimization
2054 var lt = new LocalTemporary (op_types [i + 1]);
2055 operator_args.Add (new Argument (lt, Argument.AType.Out));
2057 if (comparisons == null)
2058 comparisons = new Expression[Arguments.Count];
2063 var arg = Arguments [i];
2064 var named = arg as NamedArgument;
2065 if (named != null) {
2066 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2067 expr = Arguments [arg_comp_index].Expr;
2073 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2076 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2078 eclass = ExprClass.Value;
2082 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2084 int arg_count = Arguments.Count + 1;
2085 List<MethodSpec> best = null;
2086 foreach (MethodSpec method in members) {
2087 var pm = method.Parameters;
2088 if (pm.Count != arg_count)
2091 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2093 for (int ii = 1; ii < pm.Count; ++ii) {
2094 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2104 best = new List<MethodSpec> ();
2112 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2114 for (int ii = 0; ii < Arguments.Count; ++ii) {
2115 var arg = Arguments [ii];
2116 var expr = arg.Expr;
2117 if (expr is WildcardPattern)
2120 var na = arg as NamedArgument;
2121 for (int i = 0; i < methods.Count; ++i) {
2122 var pd = methods [i].Parameters;
2126 index = pd.GetParameterIndexByName (na.Name);
2128 methods.RemoveAt (i--);
2135 var m = pd.Types [index];
2136 if (!Convert.ImplicitConversionExists (rc, expr, m))
2137 methods.RemoveAt (i--);
2141 if (methods.Count != 1)
2147 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2149 operator_mg.EmitCall (ec, operator_args, false);
2150 ec.Emit (OpCodes.Brfalse, target);
2152 base.EmitBranchable (ec, target, on_true);
2155 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2157 if (expr is WildcardPattern)
2158 return new EmptyExpression (expr.Type);
2160 var recursive = expr as RecursivePattern;
2161 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2165 if (recursive != null) {
2166 recursive.SetParentInstance (lt);
2170 // TODO: Better error handling
2171 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2174 public void SetParentInstance (Expression instance)
2176 operator_args [0] = new Argument (instance);
2180 class PropertyPattern : ComplexPatternExpression
2182 LocalTemporary instance;
2184 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2185 : base (typeExpresion, loc)
2190 public List<PropertyPatternMember> Members { get; private set; }
2192 protected override Expression DoResolve (ResolveContext rc)
2194 type = TypeExpression.ResolveAsType (rc);
2198 comparisons = new Expression[Members.Count];
2200 // TODO: optimize when source is VariableReference, it'd save dup+pop
2201 instance = new LocalTemporary (type);
2203 for (int i = 0; i < Members.Count; i++) {
2204 var lookup = Members [i];
2206 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2207 if (member == null) {
2208 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2209 if (member != null) {
2210 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2215 if (member == null) {
2216 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2220 var pe = member as PropertyExpr;
2221 if (pe == null || member is FieldExpr) {
2222 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2226 // TODO: Obsolete checks
2227 // TODO: check accessibility
2228 if (pe != null && !pe.PropertyInfo.HasGet) {
2229 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2233 var expr = lookup.Expr.Resolve (rc);
2237 var me = (MemberExpr)member;
2238 me.InstanceExpression = instance;
2240 comparisons [i] = ResolveComparison (rc, expr, me);
2243 eclass = ExprClass.Value;
2247 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2249 if (expr is WildcardPattern)
2250 return new EmptyExpression (expr.Type);
2252 return new Is (instance, expr, expr.Location).Resolve (rc);
2255 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2257 instance.Store (ec);
2259 base.EmitBranchable (ec, target, on_true);
2263 class PropertyPatternMember
2265 public PropertyPatternMember (string name, Expression expr, Location loc)
2272 public string Name { get; private set; }
2273 public Expression Expr { get; private set; }
2274 public Location Location { get; private set; }
2277 abstract class PatternExpression : Expression
2279 protected PatternExpression (Location loc)
2284 public override Expression CreateExpressionTree (ResolveContext ec)
2286 throw new NotImplementedException ();
2290 abstract class ComplexPatternExpression : PatternExpression
2292 protected Expression[] comparisons;
2294 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2297 TypeExpression = typeExpresion;
2300 public ATypeNameExpression TypeExpression { get; private set; }
2302 public override void Emit (EmitContext ec)
2304 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2307 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2309 if (comparisons != null) {
2310 foreach (var comp in comparisons) {
2311 comp.EmitBranchable (ec, target, false);
2318 /// Implementation of the `as' operator.
2320 public class As : Probe {
2322 public As (Expression expr, Expression probe_type, Location l)
2323 : base (expr, probe_type, l)
2327 protected override string OperatorName {
2328 get { return "as"; }
2331 public override Expression CreateExpressionTree (ResolveContext ec)
2333 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2334 expr.CreateExpressionTree (ec),
2335 new TypeOf (probe_type_expr, loc));
2337 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2340 public override void Emit (EmitContext ec)
2344 ec.Emit (OpCodes.Isinst, type);
2346 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2347 ec.Emit (OpCodes.Unbox_Any, type);
2350 protected override Expression DoResolve (ResolveContext ec)
2352 if (ResolveCommon (ec) == null)
2355 type = probe_type_expr;
2356 eclass = ExprClass.Value;
2357 TypeSpec etype = expr.Type;
2359 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2360 if (TypeManager.IsGenericParameter (type)) {
2361 ec.Report.Error (413, loc,
2362 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2363 probe_type_expr.GetSignatureForError ());
2365 ec.Report.Error (77, loc,
2366 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2367 type.GetSignatureForError ());
2372 if (expr.IsNull && type.IsNullableType) {
2373 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2376 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2377 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2381 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2383 e = EmptyCast.Create (e, type);
2384 return ReducedExpression.Create (e, this).Resolve (ec);
2387 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2388 if (TypeManager.IsGenericParameter (etype))
2389 expr = new BoxedCast (expr, etype);
2394 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2395 expr = new BoxedCast (expr, etype);
2399 if (etype != InternalType.ErrorType) {
2400 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2401 etype.GetSignatureForError (), type.GetSignatureForError ());
2407 public override object Accept (StructuralVisitor visitor)
2409 return visitor.Visit (this);
2414 // This represents a typecast in the source language.
2416 public class Cast : ShimExpression {
2417 Expression target_type;
2419 public Cast (Expression cast_type, Expression expr, Location loc)
2422 this.target_type = cast_type;
2426 public Expression TargetType {
2427 get { return target_type; }
2430 protected override Expression DoResolve (ResolveContext ec)
2432 expr = expr.Resolve (ec);
2436 type = target_type.ResolveAsType (ec);
2440 if (type.IsStatic) {
2441 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2445 if (type.IsPointer && !ec.IsUnsafe) {
2446 UnsafeError (ec, loc);
2449 eclass = ExprClass.Value;
2451 Constant c = expr as Constant;
2453 c = c.Reduce (ec, type);
2458 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2460 return EmptyCast.Create (res, type);
2465 protected override void CloneTo (CloneContext clonectx, Expression t)
2467 Cast target = (Cast) t;
2469 target.target_type = target_type.Clone (clonectx);
2470 target.expr = expr.Clone (clonectx);
2473 public override object Accept (StructuralVisitor visitor)
2475 return visitor.Visit (this);
2479 public class ImplicitCast : ShimExpression
2483 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2486 this.loc = expr.Location;
2488 this.arrayAccess = arrayAccess;
2491 protected override Expression DoResolve (ResolveContext ec)
2493 expr = expr.Resolve (ec);
2498 expr = ConvertExpressionToArrayIndex (ec, expr);
2500 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2506 public class DeclarationExpression : Expression, IMemoryLocation
2508 LocalVariableReference lvr;
2510 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2512 VariableType = variableType;
2513 Variable = variable;
2514 this.loc = variable.Location;
2517 public LocalVariable Variable { get; set; }
2518 public Expression Initializer { get; set; }
2519 public FullNamedExpression VariableType { get; set; }
2521 public void AddressOf (EmitContext ec, AddressOp mode)
2523 Variable.CreateBuilder (ec);
2525 if (Initializer != null) {
2526 lvr.EmitAssign (ec, Initializer, false, false);
2529 lvr.AddressOf (ec, mode);
2532 protected override void CloneTo (CloneContext clonectx, Expression t)
2534 var target = (DeclarationExpression) t;
2536 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2538 if (Initializer != null)
2539 target.Initializer = Initializer.Clone (clonectx);
2542 public override Expression CreateExpressionTree (ResolveContext rc)
2544 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2548 bool DoResolveCommon (ResolveContext rc)
2550 var var_expr = VariableType as VarExpr;
2551 if (var_expr != null) {
2552 type = InternalType.VarOutType;
2554 type = VariableType.ResolveAsType (rc);
2559 if (Initializer != null) {
2560 Initializer = Initializer.Resolve (rc);
2562 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2563 type = var_expr.Type;
2567 Variable.Type = type;
2568 lvr = new LocalVariableReference (Variable, loc);
2570 eclass = ExprClass.Variable;
2574 protected override Expression DoResolve (ResolveContext rc)
2576 if (DoResolveCommon (rc))
2582 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2584 if (lvr == null && DoResolveCommon (rc))
2585 lvr.ResolveLValue (rc, right_side);
2590 public override void Emit (EmitContext ec)
2592 throw new NotImplementedException ();
2597 // C# 2.0 Default value expression
2599 public class DefaultValueExpression : Expression
2603 public DefaultValueExpression (Expression expr, Location loc)
2609 public Expression Expr {
2615 public override bool IsSideEffectFree {
2621 public override bool ContainsEmitWithAwait ()
2626 public override Expression CreateExpressionTree (ResolveContext ec)
2628 Arguments args = new Arguments (2);
2629 args.Add (new Argument (this));
2630 args.Add (new Argument (new TypeOf (type, loc)));
2631 return CreateExpressionFactoryCall (ec, "Constant", args);
2634 protected override Expression DoResolve (ResolveContext ec)
2636 type = expr.ResolveAsType (ec);
2640 if (type.IsStatic) {
2641 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2645 return new NullLiteral (Location).ConvertImplicitly (type);
2647 if (TypeSpec.IsReferenceType (type))
2648 return new NullConstant (type, loc);
2650 Constant c = New.Constantify (type, expr.Location);
2654 eclass = ExprClass.Variable;
2658 public override void Emit (EmitContext ec)
2660 LocalTemporary temp_storage = new LocalTemporary(type);
2662 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2663 ec.Emit(OpCodes.Initobj, type);
2664 temp_storage.Emit(ec);
2665 temp_storage.Release (ec);
2668 #if (NET_4_0 || MOBILE_DYNAMIC) && !STATIC
2669 public override SLE.Expression MakeExpression (BuilderContext ctx)
2671 return SLE.Expression.Default (type.GetMetaInfo ());
2675 protected override void CloneTo (CloneContext clonectx, Expression t)
2677 DefaultValueExpression target = (DefaultValueExpression) t;
2679 target.expr = expr.Clone (clonectx);
2682 public override object Accept (StructuralVisitor visitor)
2684 return visitor.Visit (this);
2689 /// Binary operators
2691 public class Binary : Expression, IDynamicBinder
2693 public class PredefinedOperator
2695 protected readonly TypeSpec left;
2696 protected readonly TypeSpec right;
2697 protected readonly TypeSpec left_unwrap;
2698 protected readonly TypeSpec right_unwrap;
2699 public readonly Operator OperatorsMask;
2700 public TypeSpec ReturnType;
2702 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2703 : this (ltype, rtype, op_mask, ltype)
2707 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2708 : this (type, type, op_mask, return_type)
2712 public PredefinedOperator (TypeSpec type, Operator op_mask)
2713 : this (type, type, op_mask, type)
2717 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2719 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2720 throw new InternalErrorException ("Only masked values can be used");
2722 if ((op_mask & Operator.NullableMask) != 0) {
2723 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2724 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2726 left_unwrap = ltype;
2727 right_unwrap = rtype;
2732 this.OperatorsMask = op_mask;
2733 this.ReturnType = return_type;
2736 public bool IsLifted {
2738 return (OperatorsMask & Operator.NullableMask) != 0;
2742 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2746 var left_expr = b.left;
2747 var right_expr = b.right;
2749 b.type = ReturnType;
2752 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2753 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2754 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2757 if (right_expr.IsNull) {
2758 if ((b.oper & Operator.EqualityMask) != 0) {
2759 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2760 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2761 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2762 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2763 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2765 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2766 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2768 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2769 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2771 return b.CreateLiftedValueTypeResult (rc, left);
2773 } else if (left_expr.IsNull) {
2774 if ((b.oper & Operator.EqualityMask) != 0) {
2775 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2776 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2777 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2778 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2779 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2781 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2782 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2784 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2785 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2787 return b.CreateLiftedValueTypeResult (rc, right);
2793 // A user operators does not support multiple user conversions, but decimal type
2794 // is considered to be predefined type therefore we apply predefined operators rules
2795 // and then look for decimal user-operator implementation
2797 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2798 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2799 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2801 return b.ResolveUserOperator (rc, b.left, b.right);
2804 c = right_expr as Constant;
2806 if (c.IsDefaultValue) {
2810 // (expr + 0) to expr
2811 // (expr - 0) to expr
2812 // (bool? | false) to bool?
2814 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2815 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2816 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2817 return ReducedExpression.Create (b.left, b).Resolve (rc);
2821 // Optimizes (value &/&& 0) to 0
2823 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2824 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2825 return ReducedExpression.Create (side_effect, b);
2829 // Optimizes (bool? & true) to bool?
2831 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2832 return ReducedExpression.Create (b.left, b).Resolve (rc);
2836 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2837 return ReducedExpression.Create (b.left, b).Resolve (rc);
2839 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2840 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2844 c = b.left as Constant;
2846 if (c.IsDefaultValue) {
2850 // (0 + expr) to expr
2851 // (false | bool?) to bool?
2853 if (b.oper == Operator.Addition ||
2854 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2855 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2856 return ReducedExpression.Create (b.right, b).Resolve (rc);
2860 // Optimizes (false && expr) to false
2862 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2863 // No rhs side-effects
2864 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2865 return ReducedExpression.Create (c, b);
2869 // Optimizes (0 & value) to 0
2871 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2872 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2873 return ReducedExpression.Create (side_effect, b);
2877 // Optimizes (true & bool?) to bool?
2879 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2880 return ReducedExpression.Create (b.right, b).Resolve (rc);
2884 // Optimizes (true || expr) to true
2886 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2887 // No rhs side-effects
2888 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2889 return ReducedExpression.Create (c, b);
2893 if (b.oper == Operator.Multiply && c.IsOneInteger)
2894 return ReducedExpression.Create (b.right, b).Resolve (rc);
2898 var lifted = new Nullable.LiftedBinaryOperator (b);
2900 TypeSpec ltype, rtype;
2901 if (b.left.Type.IsNullableType) {
2902 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2903 ltype = left_unwrap;
2908 if (b.right.Type.IsNullableType) {
2909 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2910 rtype = right_unwrap;
2915 lifted.Left = b.left.IsNull ?
2917 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2919 lifted.Right = b.right.IsNull ?
2921 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2923 return lifted.Resolve (rc);
2926 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2927 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2932 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2935 // We are dealing with primitive types only
2937 return left == ltype && ltype == rtype;
2940 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2943 if (left == lexpr.Type && right == rexpr.Type)
2946 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2947 Convert.ImplicitConversionExists (ec, rexpr, right);
2950 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2952 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2953 return best_operator;
2955 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2959 if (left != null && best_operator.left != null) {
2960 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2964 // When second argument is same as the first one, the result is same
2966 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2967 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2970 if (result == 0 || result > 2)
2973 return result == 1 ? best_operator : this;
2977 sealed class PredefinedStringOperator : PredefinedOperator
2979 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2980 : base (type, type, op_mask, retType)
2984 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2985 : base (ltype, rtype, op_mask, retType)
2989 public override Expression ConvertResult (ResolveContext ec, Binary b)
2992 // Use original expression for nullable arguments
2994 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2996 b.left = unwrap.Original;
2998 unwrap = b.right as Nullable.Unwrap;
3000 b.right = unwrap.Original;
3002 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3003 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3006 // Start a new concat expression using converted expression
3008 return StringConcat.Create (ec, b.left, b.right, b.loc);
3012 sealed class PredefinedEqualityOperator : PredefinedOperator
3014 MethodSpec equal_method, inequal_method;
3016 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3017 : base (arg, arg, Operator.EqualityMask, retType)
3021 public override Expression ConvertResult (ResolveContext ec, Binary b)
3023 b.type = ReturnType;
3025 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3026 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3028 Arguments args = new Arguments (2);
3029 args.Add (new Argument (b.left));
3030 args.Add (new Argument (b.right));
3033 if (b.oper == Operator.Equality) {
3034 if (equal_method == null) {
3035 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3036 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3037 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3038 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3040 throw new NotImplementedException (left.GetSignatureForError ());
3043 method = equal_method;
3045 if (inequal_method == null) {
3046 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3047 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3048 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3049 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3051 throw new NotImplementedException (left.GetSignatureForError ());
3054 method = inequal_method;
3057 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3061 class PredefinedPointerOperator : PredefinedOperator
3063 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3064 : base (ltype, rtype, op_mask)
3068 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3069 : base (ltype, rtype, op_mask, retType)
3073 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3074 : base (type, op_mask, return_type)
3078 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3081 if (!lexpr.Type.IsPointer)
3084 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3088 if (right == null) {
3089 if (!rexpr.Type.IsPointer)
3092 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3099 public override Expression ConvertResult (ResolveContext ec, Binary b)
3102 b.left = EmptyCast.Create (b.left, left);
3103 } else if (right != null) {
3104 b.right = EmptyCast.Create (b.right, right);
3107 TypeSpec r_type = ReturnType;
3108 Expression left_arg, right_arg;
3109 if (r_type == null) {
3112 right_arg = b.right;
3113 r_type = b.left.Type;
3117 r_type = b.right.Type;
3121 right_arg = b.right;
3124 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3129 public enum Operator {
3130 Multiply = 0 | ArithmeticMask,
3131 Division = 1 | ArithmeticMask,
3132 Modulus = 2 | ArithmeticMask,
3133 Addition = 3 | ArithmeticMask | AdditionMask,
3134 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3136 LeftShift = 5 | ShiftMask,
3137 RightShift = 6 | ShiftMask,
3139 LessThan = 7 | ComparisonMask | RelationalMask,
3140 GreaterThan = 8 | ComparisonMask | RelationalMask,
3141 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3142 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3143 Equality = 11 | ComparisonMask | EqualityMask,
3144 Inequality = 12 | ComparisonMask | EqualityMask,
3146 BitwiseAnd = 13 | BitwiseMask,
3147 ExclusiveOr = 14 | BitwiseMask,
3148 BitwiseOr = 15 | BitwiseMask,
3150 LogicalAnd = 16 | LogicalMask,
3151 LogicalOr = 17 | LogicalMask,
3156 ValuesOnlyMask = ArithmeticMask - 1,
3157 ArithmeticMask = 1 << 5,
3159 ComparisonMask = 1 << 7,
3160 EqualityMask = 1 << 8,
3161 BitwiseMask = 1 << 9,
3162 LogicalMask = 1 << 10,
3163 AdditionMask = 1 << 11,
3164 SubtractionMask = 1 << 12,
3165 RelationalMask = 1 << 13,
3167 DecomposedMask = 1 << 19,
3168 NullableMask = 1 << 20
3172 public enum State : byte
3176 UserOperatorsExcluded = 1 << 2
3179 readonly Operator oper;
3180 Expression left, right;
3182 ConvCast.Mode enum_conversion;
3184 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3185 : this (oper, left, right, State.Compound)
3189 public Binary (Operator oper, Expression left, Expression right, State state)
3190 : this (oper, left, right)
3195 public Binary (Operator oper, Expression left, Expression right)
3196 : this (oper, left, right, left.Location)
3200 public Binary (Operator oper, Expression left, Expression right, Location loc)
3210 public bool IsCompound {
3212 return (state & State.Compound) != 0;
3216 public Operator Oper {
3222 public Expression Left {
3228 public Expression Right {
3234 public override Location StartLocation {
3236 return left.StartLocation;
3243 /// Returns a stringified representation of the Operator
3245 string OperName (Operator oper)
3249 case Operator.Multiply:
3252 case Operator.Division:
3255 case Operator.Modulus:
3258 case Operator.Addition:
3261 case Operator.Subtraction:
3264 case Operator.LeftShift:
3267 case Operator.RightShift:
3270 case Operator.LessThan:
3273 case Operator.GreaterThan:
3276 case Operator.LessThanOrEqual:
3279 case Operator.GreaterThanOrEqual:
3282 case Operator.Equality:
3285 case Operator.Inequality:
3288 case Operator.BitwiseAnd:
3291 case Operator.BitwiseOr:
3294 case Operator.ExclusiveOr:
3297 case Operator.LogicalOr:
3300 case Operator.LogicalAnd:
3304 s = oper.ToString ();
3314 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3316 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3319 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3321 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3325 l = left.Type.GetSignatureForError ();
3326 r = right.Type.GetSignatureForError ();
3328 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3332 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3334 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3337 public override void FlowAnalysis (FlowAnalysisContext fc)
3340 // Optimized version when on-true/on-false data are not needed
3342 if ((oper & Operator.LogicalMask) == 0) {
3343 left.FlowAnalysis (fc);
3344 right.FlowAnalysis (fc);
3348 left.FlowAnalysisConditional (fc);
3349 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3350 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3352 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3353 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3354 right.FlowAnalysisConditional (fc);
3356 if (oper == Operator.LogicalOr)
3357 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3359 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3362 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3364 if ((oper & Operator.LogicalMask) == 0) {
3365 base.FlowAnalysisConditional (fc);
3369 left.FlowAnalysisConditional (fc);
3370 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3371 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3373 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3374 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3375 right.FlowAnalysisConditional (fc);
3377 var lc = left as Constant;
3378 if (oper == Operator.LogicalOr) {
3379 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3380 if (lc != null && lc.IsDefaultValue)
3381 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3383 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3385 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3386 if (lc != null && !lc.IsDefaultValue)
3387 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3389 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3394 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3396 string GetOperatorExpressionTypeName ()
3399 case Operator.Addition:
3400 return IsCompound ? "AddAssign" : "Add";
3401 case Operator.BitwiseAnd:
3402 return IsCompound ? "AndAssign" : "And";
3403 case Operator.BitwiseOr:
3404 return IsCompound ? "OrAssign" : "Or";
3405 case Operator.Division:
3406 return IsCompound ? "DivideAssign" : "Divide";
3407 case Operator.ExclusiveOr:
3408 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3409 case Operator.Equality:
3411 case Operator.GreaterThan:
3412 return "GreaterThan";
3413 case Operator.GreaterThanOrEqual:
3414 return "GreaterThanOrEqual";
3415 case Operator.Inequality:
3417 case Operator.LeftShift:
3418 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3419 case Operator.LessThan:
3421 case Operator.LessThanOrEqual:
3422 return "LessThanOrEqual";
3423 case Operator.LogicalAnd:
3425 case Operator.LogicalOr:
3427 case Operator.Modulus:
3428 return IsCompound ? "ModuloAssign" : "Modulo";
3429 case Operator.Multiply:
3430 return IsCompound ? "MultiplyAssign" : "Multiply";
3431 case Operator.RightShift:
3432 return IsCompound ? "RightShiftAssign" : "RightShift";
3433 case Operator.Subtraction:
3434 return IsCompound ? "SubtractAssign" : "Subtract";
3436 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3440 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3443 case Operator.Addition:
3444 return CSharp.Operator.OpType.Addition;
3445 case Operator.BitwiseAnd:
3446 case Operator.LogicalAnd:
3447 return CSharp.Operator.OpType.BitwiseAnd;
3448 case Operator.BitwiseOr:
3449 case Operator.LogicalOr:
3450 return CSharp.Operator.OpType.BitwiseOr;
3451 case Operator.Division:
3452 return CSharp.Operator.OpType.Division;
3453 case Operator.Equality:
3454 return CSharp.Operator.OpType.Equality;
3455 case Operator.ExclusiveOr:
3456 return CSharp.Operator.OpType.ExclusiveOr;
3457 case Operator.GreaterThan:
3458 return CSharp.Operator.OpType.GreaterThan;
3459 case Operator.GreaterThanOrEqual:
3460 return CSharp.Operator.OpType.GreaterThanOrEqual;
3461 case Operator.Inequality:
3462 return CSharp.Operator.OpType.Inequality;
3463 case Operator.LeftShift:
3464 return CSharp.Operator.OpType.LeftShift;
3465 case Operator.LessThan:
3466 return CSharp.Operator.OpType.LessThan;
3467 case Operator.LessThanOrEqual:
3468 return CSharp.Operator.OpType.LessThanOrEqual;
3469 case Operator.Modulus:
3470 return CSharp.Operator.OpType.Modulus;
3471 case Operator.Multiply:
3472 return CSharp.Operator.OpType.Multiply;
3473 case Operator.RightShift:
3474 return CSharp.Operator.OpType.RightShift;
3475 case Operator.Subtraction:
3476 return CSharp.Operator.OpType.Subtraction;
3478 throw new InternalErrorException (op.ToString ());
3482 public override bool ContainsEmitWithAwait ()
3484 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3487 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3492 case Operator.Multiply:
3493 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3494 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3495 opcode = OpCodes.Mul_Ovf;
3496 else if (!IsFloat (l))
3497 opcode = OpCodes.Mul_Ovf_Un;
3499 opcode = OpCodes.Mul;
3501 opcode = OpCodes.Mul;
3505 case Operator.Division:
3507 opcode = OpCodes.Div_Un;
3509 opcode = OpCodes.Div;
3512 case Operator.Modulus:
3514 opcode = OpCodes.Rem_Un;
3516 opcode = OpCodes.Rem;
3519 case Operator.Addition:
3520 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3521 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3522 opcode = OpCodes.Add_Ovf;
3523 else if (!IsFloat (l))
3524 opcode = OpCodes.Add_Ovf_Un;
3526 opcode = OpCodes.Add;
3528 opcode = OpCodes.Add;
3531 case Operator.Subtraction:
3532 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3533 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3534 opcode = OpCodes.Sub_Ovf;
3535 else if (!IsFloat (l))
3536 opcode = OpCodes.Sub_Ovf_Un;
3538 opcode = OpCodes.Sub;
3540 opcode = OpCodes.Sub;
3543 case Operator.RightShift:
3544 if (!(right is IntConstant)) {
3545 ec.EmitInt (GetShiftMask (l));
3546 ec.Emit (OpCodes.And);
3550 opcode = OpCodes.Shr_Un;
3552 opcode = OpCodes.Shr;
3555 case Operator.LeftShift:
3556 if (!(right is IntConstant)) {
3557 ec.EmitInt (GetShiftMask (l));
3558 ec.Emit (OpCodes.And);
3561 opcode = OpCodes.Shl;
3564 case Operator.Equality:
3565 opcode = OpCodes.Ceq;
3568 case Operator.Inequality:
3569 ec.Emit (OpCodes.Ceq);
3572 opcode = OpCodes.Ceq;
3575 case Operator.LessThan:
3577 opcode = OpCodes.Clt_Un;
3579 opcode = OpCodes.Clt;
3582 case Operator.GreaterThan:
3584 opcode = OpCodes.Cgt_Un;
3586 opcode = OpCodes.Cgt;
3589 case Operator.LessThanOrEqual:
3590 if (IsUnsigned (l) || IsFloat (l))
3591 ec.Emit (OpCodes.Cgt_Un);
3593 ec.Emit (OpCodes.Cgt);
3596 opcode = OpCodes.Ceq;
3599 case Operator.GreaterThanOrEqual:
3600 if (IsUnsigned (l) || IsFloat (l))
3601 ec.Emit (OpCodes.Clt_Un);
3603 ec.Emit (OpCodes.Clt);
3607 opcode = OpCodes.Ceq;
3610 case Operator.BitwiseOr:
3611 opcode = OpCodes.Or;
3614 case Operator.BitwiseAnd:
3615 opcode = OpCodes.And;
3618 case Operator.ExclusiveOr:
3619 opcode = OpCodes.Xor;
3623 throw new InternalErrorException (oper.ToString ());
3629 static int GetShiftMask (TypeSpec type)
3631 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3634 static bool IsUnsigned (TypeSpec t)
3636 switch (t.BuiltinType) {
3637 case BuiltinTypeSpec.Type.Char:
3638 case BuiltinTypeSpec.Type.UInt:
3639 case BuiltinTypeSpec.Type.ULong:
3640 case BuiltinTypeSpec.Type.UShort:
3641 case BuiltinTypeSpec.Type.Byte:
3648 static bool IsFloat (TypeSpec t)
3650 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3653 public Expression ResolveOperator (ResolveContext rc)
3655 eclass = ExprClass.Value;
3657 TypeSpec l = left.Type;
3658 TypeSpec r = right.Type;
3660 bool primitives_only = false;
3663 // Handles predefined primitive types
3665 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3666 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3667 if ((oper & Operator.ShiftMask) == 0) {
3668 if (!DoBinaryOperatorPromotion (rc))
3671 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3675 if (l.IsPointer || r.IsPointer)
3676 return ResolveOperatorPointer (rc, l, r);
3679 if ((state & State.UserOperatorsExcluded) == 0) {
3680 expr = ResolveUserOperator (rc, left, right);
3685 bool lenum = l.IsEnum;
3686 bool renum = r.IsEnum;
3687 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3691 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3692 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3697 if ((oper & Operator.BitwiseMask) != 0) {
3698 expr = EmptyCast.Create (expr, type);
3699 enum_conversion = GetEnumResultCast (type);
3701 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3702 expr = OptimizeAndOperation (expr);
3706 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3707 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3710 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3711 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3715 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3718 // We cannot break here there is also Enum + String possible match
3719 // which is not ambiguous with predefined enum operators
3722 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3723 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3727 } else if (l.IsDelegate || r.IsDelegate) {
3731 expr = ResolveOperatorDelegate (rc, l, r);
3733 // TODO: Can this be ambiguous
3741 // Equality operators are more complicated
3743 if ((oper & Operator.EqualityMask) != 0) {
3744 return ResolveEquality (rc, l, r, primitives_only);
3747 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3751 if (primitives_only)
3755 // Lifted operators have lower priority
3757 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3760 static bool IsEnumOrNullableEnum (TypeSpec type)
3762 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3766 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3767 // if 'left' is not an enumeration constant, create one from the type of 'right'
3768 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3771 case Operator.BitwiseOr:
3772 case Operator.BitwiseAnd:
3773 case Operator.ExclusiveOr:
3774 case Operator.Equality:
3775 case Operator.Inequality:
3776 case Operator.LessThan:
3777 case Operator.LessThanOrEqual:
3778 case Operator.GreaterThan:
3779 case Operator.GreaterThanOrEqual:
3780 if (left.Type.IsEnum)
3783 if (left.IsZeroInteger)
3784 return left.Reduce (ec, right.Type);
3788 case Operator.Addition:
3789 case Operator.Subtraction:
3792 case Operator.Multiply:
3793 case Operator.Division:
3794 case Operator.Modulus:
3795 case Operator.LeftShift:
3796 case Operator.RightShift:
3797 if (right.Type.IsEnum || left.Type.IsEnum)
3806 // The `|' operator used on types which were extended is dangerous
3808 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3810 OpcodeCast lcast = left as OpcodeCast;
3811 if (lcast != null) {
3812 if (IsUnsigned (lcast.UnderlyingType))
3816 OpcodeCast rcast = right as OpcodeCast;
3817 if (rcast != null) {
3818 if (IsUnsigned (rcast.UnderlyingType))
3822 if (lcast == null && rcast == null)
3825 // FIXME: consider constants
3827 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3828 ec.Report.Warning (675, 3, loc,
3829 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3830 ltype.GetSignatureForError ());
3833 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3835 return new PredefinedOperator[] {
3837 // Pointer arithmetic:
3839 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3840 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3841 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3842 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3844 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3845 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3846 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3847 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3850 // T* operator + (int y, T* x);
3851 // T* operator + (uint y, T *x);
3852 // T* operator + (long y, T *x);
3853 // T* operator + (ulong y, T *x);
3855 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3856 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3857 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3858 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3861 // long operator - (T* x, T *y)
3863 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3867 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3869 TypeSpec bool_type = types.Bool;
3872 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3873 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3874 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3875 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3876 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3877 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3878 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3880 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3881 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3882 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3883 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3884 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3885 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3886 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3888 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3889 // Remaining string operators are in lifted tables
3891 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3893 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3894 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3895 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3899 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3901 var types = module.Compiler.BuiltinTypes;
3904 // Not strictly lifted but need to be in second group otherwise expressions like
3905 // int + null would resolve to +(object, string) instead of +(int?, int?)
3907 var string_operators = new [] {
3908 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3909 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3912 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3913 if (nullable == null)
3914 return string_operators;
3916 var bool_type = types.Bool;
3918 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3919 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3920 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3921 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3922 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3923 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3924 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3925 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3928 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3929 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3930 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3931 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3932 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3933 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3934 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3936 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3937 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3938 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3939 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3940 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3941 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3942 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3944 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3946 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3947 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3948 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3950 string_operators [0],
3951 string_operators [1]
3955 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3957 TypeSpec bool_type = types.Bool;
3960 new PredefinedEqualityOperator (types.String, bool_type),
3961 new PredefinedEqualityOperator (types.Delegate, bool_type),
3962 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3963 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3964 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3965 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3966 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3967 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3968 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3969 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3973 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3975 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3977 if (nullable == null)
3978 return new PredefinedOperator [0];
3980 var types = module.Compiler.BuiltinTypes;
3981 var bool_type = types.Bool;
3982 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3983 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3984 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3985 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3986 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3987 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3988 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3989 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3992 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3993 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3994 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3995 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3996 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3997 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3998 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3999 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4004 // 7.2.6.2 Binary numeric promotions
4006 bool DoBinaryOperatorPromotion (ResolveContext rc)
4008 TypeSpec ltype = left.Type;
4009 if (ltype.IsNullableType) {
4010 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4014 // This is numeric promotion code only
4016 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4019 TypeSpec rtype = right.Type;
4020 if (rtype.IsNullableType) {
4021 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4024 var lb = ltype.BuiltinType;
4025 var rb = rtype.BuiltinType;
4029 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4030 type = rc.BuiltinTypes.Decimal;
4031 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4032 type = rc.BuiltinTypes.Double;
4033 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4034 type = rc.BuiltinTypes.Float;
4035 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4036 type = rc.BuiltinTypes.ULong;
4038 if (IsSignedType (lb)) {
4039 expr = ConvertSignedConstant (left, type);
4043 } else if (IsSignedType (rb)) {
4044 expr = ConvertSignedConstant (right, type);
4050 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4051 type = rc.BuiltinTypes.Long;
4052 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4053 type = rc.BuiltinTypes.UInt;
4055 if (IsSignedType (lb)) {
4056 expr = ConvertSignedConstant (left, type);
4058 type = rc.BuiltinTypes.Long;
4059 } else if (IsSignedType (rb)) {
4060 expr = ConvertSignedConstant (right, type);
4062 type = rc.BuiltinTypes.Long;
4065 type = rc.BuiltinTypes.Int;
4068 if (ltype != type) {
4069 expr = PromoteExpression (rc, left, type);
4076 if (rtype != type) {
4077 expr = PromoteExpression (rc, right, type);
4087 static bool IsSignedType (BuiltinTypeSpec.Type type)
4090 case BuiltinTypeSpec.Type.Int:
4091 case BuiltinTypeSpec.Type.Short:
4092 case BuiltinTypeSpec.Type.SByte:
4093 case BuiltinTypeSpec.Type.Long:
4100 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4102 var c = expr as Constant;
4106 return c.ConvertImplicitly (type);
4109 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4111 if (expr.Type.IsNullableType) {
4112 return Convert.ImplicitConversionStandard (rc, expr,
4113 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4116 var c = expr as Constant;
4118 return c.ConvertImplicitly (type);
4120 return Convert.ImplicitNumericConversion (expr, type);
4123 protected override Expression DoResolve (ResolveContext ec)
4128 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4129 left = ((ParenthesizedExpression) left).Expr;
4130 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4134 if (left.eclass == ExprClass.Type) {
4135 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4139 left = left.Resolve (ec);
4144 right = right.Resolve (ec);
4148 Constant lc = left as Constant;
4149 Constant rc = right as Constant;
4151 // The conversion rules are ignored in enum context but why
4152 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4153 lc = EnumLiftUp (ec, lc, rc);
4155 rc = EnumLiftUp (ec, rc, lc);
4158 if (rc != null && lc != null) {
4159 int prev_e = ec.Report.Errors;
4160 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4161 if (e != null || ec.Report.Errors != prev_e)
4165 // Comparison warnings
4166 if ((oper & Operator.ComparisonMask) != 0) {
4167 if (left.Equals (right)) {
4168 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4170 CheckOutOfRangeComparison (ec, lc, right.Type);
4171 CheckOutOfRangeComparison (ec, rc, left.Type);
4174 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4175 return DoResolveDynamic (ec);
4177 return DoResolveCore (ec, left, right);
4180 Expression DoResolveDynamic (ResolveContext rc)
4183 var rt = right.Type;
4184 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4185 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4186 Error_OperatorCannotBeApplied (rc, left, right);
4193 // Special handling for logical boolean operators which require rhs not to be
4194 // evaluated based on lhs value
4196 if ((oper & Operator.LogicalMask) != 0) {
4197 Expression cond_left, cond_right, expr;
4199 args = new Arguments (2);
4201 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4202 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4204 var cond_args = new Arguments (1);
4205 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4208 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4209 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4211 left = temp.CreateReferenceExpression (rc, loc);
4212 if (oper == Operator.LogicalAnd) {
4213 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4216 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4220 args.Add (new Argument (left));
4221 args.Add (new Argument (right));
4222 cond_right = new DynamicExpressionStatement (this, args, loc);
4224 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4226 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4227 rc.Report.Error (7083, left.Location,
4228 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4229 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4233 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4234 args.Add (new Argument (right));
4235 right = new DynamicExpressionStatement (this, args, loc);
4238 // bool && dynamic => (temp = left) ? temp && right : temp;
4239 // bool || dynamic => (temp = left) ? temp : temp || right;
4241 if (oper == Operator.LogicalAnd) {
4243 cond_right = temp.CreateReferenceExpression (rc, loc);
4245 cond_left = temp.CreateReferenceExpression (rc, loc);
4249 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4252 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4255 args = new Arguments (2);
4256 args.Add (new Argument (left));
4257 args.Add (new Argument (right));
4258 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4261 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4263 Expression expr = ResolveOperator (ec);
4265 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4267 if (left == null || right == null)
4268 throw new InternalErrorException ("Invalid conversion");
4270 if (oper == Operator.BitwiseOr)
4271 CheckBitwiseOrOnSignExtended (ec);
4276 public override SLE.Expression MakeExpression (BuilderContext ctx)
4278 return MakeExpression (ctx, left, right);
4281 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4283 var le = left.MakeExpression (ctx);
4284 var re = right.MakeExpression (ctx);
4285 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4288 case Operator.Addition:
4289 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4290 case Operator.BitwiseAnd:
4291 return SLE.Expression.And (le, re);
4292 case Operator.BitwiseOr:
4293 return SLE.Expression.Or (le, re);
4294 case Operator.Division:
4295 return SLE.Expression.Divide (le, re);
4296 case Operator.Equality:
4297 return SLE.Expression.Equal (le, re);
4298 case Operator.ExclusiveOr:
4299 return SLE.Expression.ExclusiveOr (le, re);
4300 case Operator.GreaterThan:
4301 return SLE.Expression.GreaterThan (le, re);
4302 case Operator.GreaterThanOrEqual:
4303 return SLE.Expression.GreaterThanOrEqual (le, re);
4304 case Operator.Inequality:
4305 return SLE.Expression.NotEqual (le, re);
4306 case Operator.LeftShift:
4307 return SLE.Expression.LeftShift (le, re);
4308 case Operator.LessThan:
4309 return SLE.Expression.LessThan (le, re);
4310 case Operator.LessThanOrEqual:
4311 return SLE.Expression.LessThanOrEqual (le, re);
4312 case Operator.LogicalAnd:
4313 return SLE.Expression.AndAlso (le, re);
4314 case Operator.LogicalOr:
4315 return SLE.Expression.OrElse (le, re);
4316 case Operator.Modulus:
4317 return SLE.Expression.Modulo (le, re);
4318 case Operator.Multiply:
4319 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4320 case Operator.RightShift:
4321 return SLE.Expression.RightShift (le, re);
4322 case Operator.Subtraction:
4323 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4325 throw new NotImplementedException (oper.ToString ());
4330 // D operator + (D x, D y)
4331 // D operator - (D x, D y)
4333 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4335 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4337 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4338 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4343 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4344 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4354 MethodSpec method = null;
4355 Arguments args = new Arguments (2);
4356 args.Add (new Argument (left));
4357 args.Add (new Argument (right));
4359 if (oper == Operator.Addition) {
4360 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4361 } else if (oper == Operator.Subtraction) {
4362 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4366 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4368 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4369 return new ClassCast (expr, l);
4373 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4375 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4378 // bool operator == (E x, E y);
4379 // bool operator != (E x, E y);
4380 // bool operator < (E x, E y);
4381 // bool operator > (E x, E y);
4382 // bool operator <= (E x, E y);
4383 // bool operator >= (E x, E y);
4385 // E operator & (E x, E y);
4386 // E operator | (E x, E y);
4387 // E operator ^ (E x, E y);
4390 if ((oper & Operator.ComparisonMask) != 0) {
4391 type = rc.BuiltinTypes.Bool;
4397 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4403 if (ltype == rtype) {
4407 var lifted = new Nullable.LiftedBinaryOperator (this);
4409 lifted.Right = right;
4410 return lifted.Resolve (rc);
4413 if (renum && !ltype.IsNullableType) {
4414 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4419 } else if (lenum && !rtype.IsNullableType) {
4420 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4428 // Now try lifted version of predefined operator
4430 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4431 if (nullable_type != null) {
4432 if (renum && !ltype.IsNullableType) {
4433 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4435 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4438 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4441 if ((oper & Operator.BitwiseMask) != 0)
4445 if ((oper & Operator.BitwiseMask) != 0)
4446 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4448 return CreateLiftedValueTypeResult (rc, rtype);
4452 var lifted = new Nullable.LiftedBinaryOperator (this);
4454 lifted.Right = right;
4455 return lifted.Resolve (rc);
4457 } else if (lenum && !rtype.IsNullableType) {
4458 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4460 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4463 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4466 if ((oper & Operator.BitwiseMask) != 0)
4470 if ((oper & Operator.BitwiseMask) != 0)
4471 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4473 return CreateLiftedValueTypeResult (rc, ltype);
4477 var lifted = new Nullable.LiftedBinaryOperator (this);
4479 lifted.Right = expr;
4480 return lifted.Resolve (rc);
4482 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4483 Nullable.Unwrap unwrap = null;
4484 if (left.IsNull || right.IsNull) {
4485 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4486 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4488 if ((oper & Operator.RelationalMask) != 0)
4489 return CreateLiftedValueTypeResult (rc, rtype);
4491 if ((oper & Operator.BitwiseMask) != 0)
4492 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4495 return CreateLiftedValueTypeResult (rc, left.Type);
4497 // Equality operators are valid between E? and null
4499 unwrap = new Nullable.Unwrap (right);
4501 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4507 var lifted = new Nullable.LiftedBinaryOperator (this);
4509 lifted.Right = right;
4510 lifted.UnwrapRight = unwrap;
4511 return lifted.Resolve (rc);
4513 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4514 Nullable.Unwrap unwrap = null;
4515 if (right.IsNull || left.IsNull) {
4516 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4517 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4519 if ((oper & Operator.RelationalMask) != 0)
4520 return CreateLiftedValueTypeResult (rc, ltype);
4522 if ((oper & Operator.BitwiseMask) != 0)
4523 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4526 return CreateLiftedValueTypeResult (rc, right.Type);
4528 // Equality operators are valid between E? and null
4530 unwrap = new Nullable.Unwrap (left);
4532 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4538 var lifted = new Nullable.LiftedBinaryOperator (this);
4540 lifted.UnwrapLeft = unwrap;
4541 lifted.Right = expr;
4542 return lifted.Resolve (rc);
4550 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4552 TypeSpec underlying_type;
4553 if (expr.Type.IsNullableType) {
4554 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4556 underlying_type = EnumSpec.GetUnderlyingType (nt);
4558 underlying_type = nt;
4559 } else if (expr.Type.IsEnum) {
4560 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4562 underlying_type = expr.Type;
4565 switch (underlying_type.BuiltinType) {
4566 case BuiltinTypeSpec.Type.SByte:
4567 case BuiltinTypeSpec.Type.Byte:
4568 case BuiltinTypeSpec.Type.Short:
4569 case BuiltinTypeSpec.Type.UShort:
4570 underlying_type = rc.BuiltinTypes.Int;
4574 if (expr.Type.IsNullableType || liftType)
4575 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4577 if (expr.Type == underlying_type)
4580 return EmptyCast.Create (expr, underlying_type);
4583 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4586 // U operator - (E e, E f)
4587 // E operator - (E e, U x) // Internal decomposition operator
4588 // E operator - (U x, E e) // Internal decomposition operator
4590 // E operator + (E e, U x)
4591 // E operator + (U x, E e)
4600 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4606 if (!enum_type.IsNullableType) {
4607 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4609 if (oper == Operator.Subtraction)
4610 expr = ConvertEnumSubtractionResult (rc, expr);
4612 expr = ConvertEnumAdditionalResult (expr, enum_type);
4614 enum_conversion = GetEnumResultCast (expr.Type);
4619 var nullable = rc.Module.PredefinedTypes.Nullable;
4622 // Don't try nullable version when nullable type is undefined
4624 if (!nullable.IsDefined)
4627 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4630 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4632 if (oper == Operator.Subtraction)
4633 expr = ConvertEnumSubtractionResult (rc, expr);
4635 expr = ConvertEnumAdditionalResult (expr, enum_type);
4637 enum_conversion = GetEnumResultCast (expr.Type);
4643 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4645 return EmptyCast.Create (expr, enumType);
4648 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4651 // Enumeration subtraction has different result type based on
4654 TypeSpec result_type;
4655 if (left.Type == right.Type) {
4656 var c = right as EnumConstant;
4657 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4659 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4660 // E which is not what expressions E - 1 or 0 - E return
4662 result_type = left.Type;
4664 result_type = left.Type.IsNullableType ?
4665 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4666 EnumSpec.GetUnderlyingType (left.Type);
4669 if (IsEnumOrNullableEnum (left.Type)) {
4670 result_type = left.Type;
4672 result_type = right.Type;
4675 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4676 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4679 return EmptyCast.Create (expr, result_type);
4682 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4684 if (type.IsNullableType)
4685 type = Nullable.NullableInfo.GetUnderlyingType (type);
4688 type = EnumSpec.GetUnderlyingType (type);
4690 switch (type.BuiltinType) {
4691 case BuiltinTypeSpec.Type.SByte:
4692 return ConvCast.Mode.I4_I1;
4693 case BuiltinTypeSpec.Type.Byte:
4694 return ConvCast.Mode.I4_U1;
4695 case BuiltinTypeSpec.Type.Short:
4696 return ConvCast.Mode.I4_I2;
4697 case BuiltinTypeSpec.Type.UShort:
4698 return ConvCast.Mode.I4_U2;
4705 // Equality operators rules
4707 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4710 type = ec.BuiltinTypes.Bool;
4711 bool no_arg_conv = false;
4713 if (!primitives_only) {
4716 // a, Both operands are reference-type values or the value null
4717 // b, One operand is a value of type T where T is a type-parameter and
4718 // the other operand is the value null. Furthermore T does not have the
4719 // value type constraint
4721 // LAMESPEC: Very confusing details in the specification, basically any
4722 // reference like type-parameter is allowed
4724 var tparam_l = l as TypeParameterSpec;
4725 var tparam_r = r as TypeParameterSpec;
4726 if (tparam_l != null) {
4727 if (right is NullLiteral) {
4728 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4731 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4735 if (!tparam_l.IsReferenceType)
4738 l = tparam_l.GetEffectiveBase ();
4739 left = new BoxedCast (left, l);
4740 } else if (left is NullLiteral && tparam_r == null) {
4741 if (TypeSpec.IsReferenceType (r))
4744 if (r.Kind == MemberKind.InternalCompilerType)
4748 if (tparam_r != null) {
4749 if (left is NullLiteral) {
4750 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4753 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4757 if (!tparam_r.IsReferenceType)
4760 r = tparam_r.GetEffectiveBase ();
4761 right = new BoxedCast (right, r);
4762 } else if (right is NullLiteral) {
4763 if (TypeSpec.IsReferenceType (l))
4766 if (l.Kind == MemberKind.InternalCompilerType)
4771 // LAMESPEC: method groups can be compared when they convert to other side delegate
4774 if (right.eclass == ExprClass.MethodGroup) {
4775 result = Convert.ImplicitConversion (ec, right, l, loc);
4781 } else if (r.IsDelegate && l != r) {
4784 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4785 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4792 no_arg_conv = l == r && !l.IsStruct;
4797 // bool operator != (string a, string b)
4798 // bool operator == (string a, string b)
4800 // bool operator != (Delegate a, Delegate b)
4801 // bool operator == (Delegate a, Delegate b)
4803 // bool operator != (bool a, bool b)
4804 // bool operator == (bool a, bool b)
4806 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4807 // they implement an implicit conversion to any of types above. This does
4808 // not apply when both operands are of same reference type
4810 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4811 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4816 // Now try lifted version of predefined operators
4818 if (no_arg_conv && !l.IsNullableType) {
4820 // Optimizes cases which won't match
4823 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4829 // The == and != operators permit one operand to be a value of a nullable
4830 // type and the other to be the null literal, even if no predefined or user-defined
4831 // operator (in unlifted or lifted form) exists for the operation.
4833 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4834 var lifted = new Nullable.LiftedBinaryOperator (this);
4836 lifted.Right = right;
4837 return lifted.Resolve (ec);
4842 // bool operator != (object a, object b)
4843 // bool operator == (object a, object b)
4845 // An explicit reference conversion exists from the
4846 // type of either operand to the type of the other operand.
4849 // Optimize common path
4851 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4854 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4855 !Convert.ExplicitReferenceConversionExists (r, l))
4858 // Reject allowed explicit conversions like int->object
4859 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4862 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4863 ec.Report.Warning (253, 2, loc,
4864 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4865 l.GetSignatureForError ());
4867 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4868 ec.Report.Warning (252, 2, loc,
4869 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4870 r.GetSignatureForError ());
4876 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4879 // bool operator == (void* x, void* y);
4880 // bool operator != (void* x, void* y);
4881 // bool operator < (void* x, void* y);
4882 // bool operator > (void* x, void* y);
4883 // bool operator <= (void* x, void* y);
4884 // bool operator >= (void* x, void* y);
4886 if ((oper & Operator.ComparisonMask) != 0) {
4889 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4896 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4902 type = ec.BuiltinTypes.Bool;
4906 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4910 // Build-in operators method overloading
4912 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4914 PredefinedOperator best_operator = null;
4915 TypeSpec l = left.Type;
4916 TypeSpec r = right.Type;
4917 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4919 foreach (PredefinedOperator po in operators) {
4920 if ((po.OperatorsMask & oper_mask) == 0)
4923 if (primitives_only) {
4924 if (!po.IsPrimitiveApplicable (l, r))
4927 if (!po.IsApplicable (ec, left, right))
4931 if (best_operator == null) {
4933 if (primitives_only)
4939 best_operator = po.ResolveBetterOperator (ec, best_operator);
4941 if (best_operator == null) {
4942 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4943 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4950 if (best_operator == null)
4953 return best_operator.ConvertResult (ec, this);
4957 // Optimize & constant expressions with 0 value
4959 Expression OptimizeAndOperation (Expression expr)
4961 Constant rc = right as Constant;
4962 Constant lc = left as Constant;
4963 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4965 // The result is a constant with side-effect
4967 Constant side_effect = rc == null ?
4968 new SideEffectConstant (lc, right, loc) :
4969 new SideEffectConstant (rc, left, loc);
4971 return ReducedExpression.Create (side_effect, expr);
4978 // Value types can be compared with the null literal because of the lifting
4979 // language rules. However the result is always true or false.
4981 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4983 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4984 type = rc.BuiltinTypes.Bool;
4988 // FIXME: Handle side effect constants
4989 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4991 if ((Oper & Operator.EqualityMask) != 0) {
4992 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4993 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4995 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4996 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5003 // Performs user-operator overloading
5005 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5007 Expression oper_expr;
5009 var op = ConvertBinaryToUserOperator (oper);
5011 if (l.IsNullableType)
5012 l = Nullable.NullableInfo.GetUnderlyingType (l);
5014 if (r.IsNullableType)
5015 r = Nullable.NullableInfo.GetUnderlyingType (r);
5017 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5018 IList<MemberSpec> right_operators = null;
5021 right_operators = MemberCache.GetUserOperator (r, op, false);
5022 if (right_operators == null && left_operators == null)
5024 } else if (left_operators == null) {
5028 Arguments args = new Arguments (2);
5029 Argument larg = new Argument (left);
5031 Argument rarg = new Argument (right);
5035 // User-defined operator implementations always take precedence
5036 // over predefined operator implementations
5038 if (left_operators != null && right_operators != null) {
5039 left_operators = CombineUserOperators (left_operators, right_operators);
5040 } else if (right_operators != null) {
5041 left_operators = right_operators;
5044 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5045 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5047 var res = new OverloadResolver (left_operators, restr, loc);
5049 var oper_method = res.ResolveOperator (rc, ref args);
5050 if (oper_method == null) {
5052 // Logical && and || cannot be lifted
5054 if ((oper & Operator.LogicalMask) != 0)
5058 // Apply lifted user operators only for liftable types. Implicit conversion
5059 // to nullable types is not allowed
5061 if (!IsLiftedOperatorApplicable ())
5064 // TODO: Cache the result in module container
5065 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5066 if (lifted_methods == null)
5069 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5071 oper_method = res.ResolveOperator (rc, ref args);
5072 if (oper_method == null)
5075 MethodSpec best_original = null;
5076 foreach (MethodSpec ms in left_operators) {
5077 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5083 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5085 // Expression trees use lifted notation in this case
5087 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5088 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5091 var ptypes = best_original.Parameters.Types;
5093 if (left.IsNull || right.IsNull) {
5095 // The lifted operator produces a null value if one or both operands are null
5097 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5098 type = oper_method.ReturnType;
5099 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5103 // The lifted operator produces the value false if one or both operands are null for
5104 // relational operators.
5106 if ((oper & Operator.RelationalMask) != 0) {
5108 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5109 // because return type is actually bool
5111 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5114 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5115 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5119 type = oper_method.ReturnType;
5120 var lifted = new Nullable.LiftedBinaryOperator (this);
5121 lifted.UserOperator = best_original;
5123 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5124 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5127 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5128 lifted.UnwrapRight = new Nullable.Unwrap (right);
5131 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5132 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5134 return lifted.Resolve (rc);
5137 if ((oper & Operator.LogicalMask) != 0) {
5138 // TODO: CreateExpressionTree is allocated every time
5139 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5140 oper == Operator.LogicalAnd, loc).Resolve (rc);
5142 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5145 this.left = larg.Expr;
5146 this.right = rarg.Expr;
5151 bool IsLiftedOperatorApplicable ()
5153 if (left.Type.IsNullableType) {
5154 if ((oper & Operator.EqualityMask) != 0)
5155 return !right.IsNull;
5160 if (right.Type.IsNullableType) {
5161 if ((oper & Operator.EqualityMask) != 0)
5162 return !left.IsNull;
5167 if (TypeSpec.IsValueType (left.Type))
5168 return right.IsNull;
5170 if (TypeSpec.IsValueType (right.Type))
5176 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5178 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5179 if (nullable_type == null)
5183 // Lifted operators permit predefined and user-defined operators that operate
5184 // on non-nullable value types to also be used with nullable forms of those types.
5185 // Lifted operators are constructed from predefined and user-defined operators
5186 // that meet certain requirements
5188 List<MemberSpec> lifted = null;
5189 foreach (MethodSpec oper in operators) {
5191 if ((Oper & Operator.ComparisonMask) != 0) {
5193 // Result type must be of type bool for lifted comparison operators
5195 rt = oper.ReturnType;
5196 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5199 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5205 var ptypes = oper.Parameters.Types;
5206 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5210 // LAMESPEC: I am not sure why but for equality operators to be lifted
5211 // both types have to match
5213 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5217 lifted = new List<MemberSpec> ();
5220 // The lifted form is constructed by adding a single ? modifier to each operand and
5221 // result type except for comparison operators where return type is bool
5224 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5226 var parameters = ParametersCompiled.CreateFullyResolved (
5227 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5228 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5230 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5231 rt, parameters, oper.Modifiers);
5233 lifted.Add (lifted_op);
5240 // Merge two sets of user operators into one, they are mostly distinguish
5241 // except when they share base type and it contains an operator
5243 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5245 var combined = new List<MemberSpec> (left.Count + right.Count);
5246 combined.AddRange (left);
5247 foreach (var r in right) {
5249 foreach (var l in left) {
5250 if (l.DeclaringType == r.DeclaringType) {
5263 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5265 if (c is IntegralConstant || c is CharConstant) {
5267 c.ConvertExplicitly (true, type);
5268 } catch (OverflowException) {
5269 ec.Report.Warning (652, 2, loc,
5270 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5271 type.GetSignatureForError ());
5277 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5278 /// context of a conditional bool expression. This function will return
5279 /// false if it is was possible to use EmitBranchable, or true if it was.
5281 /// The expression's code is generated, and we will generate a branch to `target'
5282 /// if the resulting expression value is equal to isTrue
5284 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5286 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5287 left = left.EmitToField (ec);
5289 if ((oper & Operator.LogicalMask) == 0) {
5290 right = right.EmitToField (ec);
5295 // This is more complicated than it looks, but its just to avoid
5296 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5297 // but on top of that we want for == and != to use a special path
5298 // if we are comparing against null
5300 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5301 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5304 // put the constant on the rhs, for simplicity
5306 if (left is Constant) {
5307 Expression swap = right;
5313 // brtrue/brfalse works with native int only
5315 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5316 left.EmitBranchable (ec, target, my_on_true);
5319 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5320 // right is a boolean, and it's not 'false' => it is 'true'
5321 left.EmitBranchable (ec, target, !my_on_true);
5325 } else if (oper == Operator.LogicalAnd) {
5328 Label tests_end = ec.DefineLabel ();
5330 left.EmitBranchable (ec, tests_end, false);
5331 right.EmitBranchable (ec, target, true);
5332 ec.MarkLabel (tests_end);
5335 // This optimizes code like this
5336 // if (true && i > 4)
5338 if (!(left is Constant))
5339 left.EmitBranchable (ec, target, false);
5341 if (!(right is Constant))
5342 right.EmitBranchable (ec, target, false);
5347 } else if (oper == Operator.LogicalOr){
5349 left.EmitBranchable (ec, target, true);
5350 right.EmitBranchable (ec, target, true);
5353 Label tests_end = ec.DefineLabel ();
5354 left.EmitBranchable (ec, tests_end, true);
5355 right.EmitBranchable (ec, target, false);
5356 ec.MarkLabel (tests_end);
5361 } else if ((oper & Operator.ComparisonMask) == 0) {
5362 base.EmitBranchable (ec, target, on_true);
5369 TypeSpec t = left.Type;
5370 bool is_float = IsFloat (t);
5371 bool is_unsigned = is_float || IsUnsigned (t);
5374 case Operator.Equality:
5376 ec.Emit (OpCodes.Beq, target);
5378 ec.Emit (OpCodes.Bne_Un, target);
5381 case Operator.Inequality:
5383 ec.Emit (OpCodes.Bne_Un, target);
5385 ec.Emit (OpCodes.Beq, target);
5388 case Operator.LessThan:
5390 if (is_unsigned && !is_float)
5391 ec.Emit (OpCodes.Blt_Un, target);
5393 ec.Emit (OpCodes.Blt, target);
5396 ec.Emit (OpCodes.Bge_Un, target);
5398 ec.Emit (OpCodes.Bge, target);
5401 case Operator.GreaterThan:
5403 if (is_unsigned && !is_float)
5404 ec.Emit (OpCodes.Bgt_Un, target);
5406 ec.Emit (OpCodes.Bgt, target);
5409 ec.Emit (OpCodes.Ble_Un, target);
5411 ec.Emit (OpCodes.Ble, target);
5414 case Operator.LessThanOrEqual:
5416 if (is_unsigned && !is_float)
5417 ec.Emit (OpCodes.Ble_Un, target);
5419 ec.Emit (OpCodes.Ble, target);
5422 ec.Emit (OpCodes.Bgt_Un, target);
5424 ec.Emit (OpCodes.Bgt, target);
5428 case Operator.GreaterThanOrEqual:
5430 if (is_unsigned && !is_float)
5431 ec.Emit (OpCodes.Bge_Un, target);
5433 ec.Emit (OpCodes.Bge, target);
5436 ec.Emit (OpCodes.Blt_Un, target);
5438 ec.Emit (OpCodes.Blt, target);
5441 throw new InternalErrorException (oper.ToString ());
5445 public override void Emit (EmitContext ec)
5447 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5448 left = left.EmitToField (ec);
5450 if ((oper & Operator.LogicalMask) == 0) {
5451 right = right.EmitToField (ec);
5456 // Handle short-circuit operators differently
5459 if ((oper & Operator.LogicalMask) != 0) {
5460 Label load_result = ec.DefineLabel ();
5461 Label end = ec.DefineLabel ();
5463 bool is_or = oper == Operator.LogicalOr;
5464 left.EmitBranchable (ec, load_result, is_or);
5466 ec.Emit (OpCodes.Br_S, end);
5468 ec.MarkLabel (load_result);
5469 ec.EmitInt (is_or ? 1 : 0);
5475 // Optimize zero-based operations which cannot be optimized at expression level
5477 if (oper == Operator.Subtraction) {
5478 var lc = left as IntegralConstant;
5479 if (lc != null && lc.IsDefaultValue) {
5481 ec.Emit (OpCodes.Neg);
5486 EmitOperator (ec, left, right);
5489 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5494 EmitOperatorOpcode (ec, oper, left.Type, right);
5497 // Emit result enumerable conversion this way because it's quite complicated get it
5498 // to resolved tree because expression tree cannot see it.
5500 if (enum_conversion != 0)
5501 ConvCast.Emit (ec, enum_conversion);
5504 public override void EmitSideEffect (EmitContext ec)
5506 if ((oper & Operator.LogicalMask) != 0 ||
5507 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5508 base.EmitSideEffect (ec);
5510 left.EmitSideEffect (ec);
5511 right.EmitSideEffect (ec);
5515 public override Expression EmitToField (EmitContext ec)
5517 if ((oper & Operator.LogicalMask) == 0) {
5518 var await_expr = left as Await;
5519 if (await_expr != null && right.IsSideEffectFree) {
5520 await_expr.Statement.EmitPrologue (ec);
5521 left = await_expr.Statement.GetResultExpression (ec);
5525 await_expr = right as Await;
5526 if (await_expr != null && left.IsSideEffectFree) {
5527 await_expr.Statement.EmitPrologue (ec);
5528 right = await_expr.Statement.GetResultExpression (ec);
5533 return base.EmitToField (ec);
5536 protected override void CloneTo (CloneContext clonectx, Expression t)
5538 Binary target = (Binary) t;
5540 target.left = left.Clone (clonectx);
5541 target.right = right.Clone (clonectx);
5544 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5546 Arguments binder_args = new Arguments (4);
5548 MemberAccess sle = new MemberAccess (new MemberAccess (
5549 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5551 CSharpBinderFlags flags = 0;
5552 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5553 flags = CSharpBinderFlags.CheckedContext;
5555 if ((oper & Operator.LogicalMask) != 0)
5556 flags |= CSharpBinderFlags.BinaryOperationLogical;
5558 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5559 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5560 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5561 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5563 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5566 public override Expression CreateExpressionTree (ResolveContext ec)
5568 return CreateExpressionTree (ec, null);
5571 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5574 bool lift_arg = false;
5577 case Operator.Addition:
5578 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5579 method_name = "AddChecked";
5581 method_name = "Add";
5583 case Operator.BitwiseAnd:
5584 method_name = "And";
5586 case Operator.BitwiseOr:
5589 case Operator.Division:
5590 method_name = "Divide";
5592 case Operator.Equality:
5593 method_name = "Equal";
5596 case Operator.ExclusiveOr:
5597 method_name = "ExclusiveOr";
5599 case Operator.GreaterThan:
5600 method_name = "GreaterThan";
5603 case Operator.GreaterThanOrEqual:
5604 method_name = "GreaterThanOrEqual";
5607 case Operator.Inequality:
5608 method_name = "NotEqual";
5611 case Operator.LeftShift:
5612 method_name = "LeftShift";
5614 case Operator.LessThan:
5615 method_name = "LessThan";
5618 case Operator.LessThanOrEqual:
5619 method_name = "LessThanOrEqual";
5622 case Operator.LogicalAnd:
5623 method_name = "AndAlso";
5625 case Operator.LogicalOr:
5626 method_name = "OrElse";
5628 case Operator.Modulus:
5629 method_name = "Modulo";
5631 case Operator.Multiply:
5632 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5633 method_name = "MultiplyChecked";
5635 method_name = "Multiply";
5637 case Operator.RightShift:
5638 method_name = "RightShift";
5640 case Operator.Subtraction:
5641 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5642 method_name = "SubtractChecked";
5644 method_name = "Subtract";
5648 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5651 Arguments args = new Arguments (2);
5652 args.Add (new Argument (left.CreateExpressionTree (ec)));
5653 args.Add (new Argument (right.CreateExpressionTree (ec)));
5654 if (method != null) {
5656 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5658 args.Add (new Argument (method));
5661 return CreateExpressionFactoryCall (ec, method_name, args);
5664 public override object Accept (StructuralVisitor visitor)
5666 return visitor.Visit (this);
5672 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5673 // b, c, d... may be strings or objects.
5675 public class StringConcat : Expression
5677 Arguments arguments;
5679 StringConcat (Location loc)
5682 arguments = new Arguments (2);
5685 public override bool ContainsEmitWithAwait ()
5687 return arguments.ContainsEmitWithAwait ();
5690 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5692 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5693 throw new ArgumentException ();
5695 var s = new StringConcat (loc);
5696 s.type = rc.BuiltinTypes.String;
5697 s.eclass = ExprClass.Value;
5699 s.Append (rc, left);
5700 s.Append (rc, right);
5704 public override Expression CreateExpressionTree (ResolveContext ec)
5706 Argument arg = arguments [0];
5707 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5711 // Creates nested calls tree from an array of arguments used for IL emit
5713 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5715 Arguments concat_args = new Arguments (2);
5716 Arguments add_args = new Arguments (3);
5718 concat_args.Add (left);
5719 add_args.Add (new Argument (left_etree));
5721 concat_args.Add (arguments [pos]);
5722 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5724 var methods = GetConcatMethodCandidates ();
5725 if (methods == null)
5728 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5729 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5733 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5735 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5736 if (++pos == arguments.Count)
5739 left = new Argument (new EmptyExpression (method.ReturnType));
5740 return CreateExpressionAddCall (ec, left, expr, pos);
5743 protected override Expression DoResolve (ResolveContext ec)
5748 void Append (ResolveContext rc, Expression operand)
5753 StringConstant sc = operand as StringConstant;
5755 if (arguments.Count != 0) {
5756 Argument last_argument = arguments [arguments.Count - 1];
5757 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5758 if (last_expr_constant != null) {
5759 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5765 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5767 StringConcat concat_oper = operand as StringConcat;
5768 if (concat_oper != null) {
5769 arguments.AddRange (concat_oper.arguments);
5774 arguments.Add (new Argument (operand));
5777 IList<MemberSpec> GetConcatMethodCandidates ()
5779 return MemberCache.FindMembers (type, "Concat", true);
5782 public override void Emit (EmitContext ec)
5784 // Optimize by removing any extra null arguments, they are no-op
5785 for (int i = 0; i < arguments.Count; ++i) {
5786 if (arguments[i].Expr is NullConstant)
5787 arguments.RemoveAt (i--);
5790 var members = GetConcatMethodCandidates ();
5791 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5792 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5793 if (method != null) {
5794 var call = new CallEmitter ();
5795 call.EmitPredefined (ec, method, arguments, false);
5799 public override void FlowAnalysis (FlowAnalysisContext fc)
5801 arguments.FlowAnalysis (fc);
5804 public override SLE.Expression MakeExpression (BuilderContext ctx)
5806 if (arguments.Count != 2)
5807 throw new NotImplementedException ("arguments.Count != 2");
5809 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5810 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5815 // User-defined conditional logical operator
5817 public class ConditionalLogicalOperator : UserOperatorCall
5819 readonly bool is_and;
5820 Expression oper_expr;
5822 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5823 : base (oper, arguments, expr_tree, loc)
5825 this.is_and = is_and;
5826 eclass = ExprClass.Unresolved;
5829 protected override Expression DoResolve (ResolveContext ec)
5831 AParametersCollection pd = oper.Parameters;
5832 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5833 ec.Report.Error (217, loc,
5834 "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",
5835 oper.GetSignatureForError ());
5839 Expression left_dup = new EmptyExpression (type);
5840 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5841 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5842 if (op_true == null || op_false == null) {
5843 ec.Report.Error (218, loc,
5844 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5845 type.GetSignatureForError (), oper.GetSignatureForError ());
5849 oper_expr = is_and ? op_false : op_true;
5850 eclass = ExprClass.Value;
5854 public override void Emit (EmitContext ec)
5856 Label end_target = ec.DefineLabel ();
5859 // Emit and duplicate left argument
5861 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5862 if (right_contains_await) {
5863 arguments[0] = arguments[0].EmitToField (ec, false);
5864 arguments[0].Expr.Emit (ec);
5866 arguments[0].Expr.Emit (ec);
5867 ec.Emit (OpCodes.Dup);
5868 arguments.RemoveAt (0);
5871 oper_expr.EmitBranchable (ec, end_target, true);
5875 if (right_contains_await) {
5877 // Special handling when right expression contains await and left argument
5878 // could not be left on stack before logical branch
5880 Label skip_left_load = ec.DefineLabel ();
5881 ec.Emit (OpCodes.Br_S, skip_left_load);
5882 ec.MarkLabel (end_target);
5883 arguments[0].Expr.Emit (ec);
5884 ec.MarkLabel (skip_left_load);
5886 ec.MarkLabel (end_target);
5891 public class PointerArithmetic : Expression {
5892 Expression left, right;
5893 readonly Binary.Operator op;
5896 // We assume that `l' is always a pointer
5898 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5907 public override bool ContainsEmitWithAwait ()
5909 throw new NotImplementedException ();
5912 public override Expression CreateExpressionTree (ResolveContext ec)
5914 Error_PointerInsideExpressionTree (ec);
5918 protected override Expression DoResolve (ResolveContext ec)
5920 eclass = ExprClass.Variable;
5922 var pc = left.Type as PointerContainer;
5923 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5924 Error_VoidPointerOperation (ec);
5931 public override void Emit (EmitContext ec)
5933 TypeSpec op_type = left.Type;
5935 // It must be either array or fixed buffer
5937 if (TypeManager.HasElementType (op_type)) {
5938 element = TypeManager.GetElementType (op_type);
5940 FieldExpr fe = left as FieldExpr;
5942 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5947 int size = BuiltinTypeSpec.GetSize(element);
5948 TypeSpec rtype = right.Type;
5950 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5952 // handle (pointer - pointer)
5956 ec.Emit (OpCodes.Sub);
5960 ec.Emit (OpCodes.Sizeof, element);
5963 ec.Emit (OpCodes.Div);
5965 ec.Emit (OpCodes.Conv_I8);
5968 // handle + and - on (pointer op int)
5970 Constant left_const = left as Constant;
5971 if (left_const != null) {
5973 // Optimize ((T*)null) pointer operations
5975 if (left_const.IsDefaultValue) {
5976 left = EmptyExpression.Null;
5984 var right_const = right as Constant;
5985 if (right_const != null) {
5987 // Optimize 0-based arithmetic
5989 if (right_const.IsDefaultValue)
5993 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5995 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5997 // TODO: Should be the checks resolve context sensitive?
5998 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5999 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6005 switch (rtype.BuiltinType) {
6006 case BuiltinTypeSpec.Type.SByte:
6007 case BuiltinTypeSpec.Type.Byte:
6008 case BuiltinTypeSpec.Type.Short:
6009 case BuiltinTypeSpec.Type.UShort:
6010 ec.Emit (OpCodes.Conv_I);
6012 case BuiltinTypeSpec.Type.UInt:
6013 ec.Emit (OpCodes.Conv_U);
6017 if (right_const == null && size != 1){
6019 ec.Emit (OpCodes.Sizeof, element);
6022 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6023 ec.Emit (OpCodes.Conv_I8);
6025 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6028 if (left_const == null) {
6029 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6030 ec.Emit (OpCodes.Conv_I);
6031 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6032 ec.Emit (OpCodes.Conv_U);
6034 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6041 // A boolean-expression is an expression that yields a result
6044 public class BooleanExpression : ShimExpression
6046 public BooleanExpression (Expression expr)
6049 this.loc = expr.Location;
6052 public override Expression CreateExpressionTree (ResolveContext ec)
6054 // TODO: We should emit IsTrue (v4) instead of direct user operator
6055 // call but that would break csc compatibility
6056 return base.CreateExpressionTree (ec);
6059 protected override Expression DoResolve (ResolveContext ec)
6061 // A boolean-expression is required to be of a type
6062 // that can be implicitly converted to bool or of
6063 // a type that implements operator true
6065 expr = expr.Resolve (ec);
6069 Assign ass = expr as Assign;
6070 if (ass != null && ass.Source is Constant) {
6071 ec.Report.Warning (665, 3, loc,
6072 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6075 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6078 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6079 Arguments args = new Arguments (1);
6080 args.Add (new Argument (expr));
6081 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6084 type = ec.BuiltinTypes.Bool;
6085 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6086 if (converted != null)
6090 // If no implicit conversion to bool exists, try using `operator true'
6092 converted = GetOperatorTrue (ec, expr, loc);
6093 if (converted == null) {
6094 expr.Error_ValueCannotBeConverted (ec, type, false);
6101 public override object Accept (StructuralVisitor visitor)
6103 return visitor.Visit (this);
6107 public class BooleanExpressionFalse : Unary
6109 public BooleanExpressionFalse (Expression expr)
6110 : base (Operator.LogicalNot, expr, expr.Location)
6114 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6116 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6121 /// Implements the ternary conditional operator (?:)
6123 public class Conditional : Expression {
6124 Expression expr, true_expr, false_expr;
6126 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6129 this.true_expr = true_expr;
6130 this.false_expr = false_expr;
6136 public Expression Expr {
6142 public Expression TrueExpr {
6148 public Expression FalseExpr {
6156 public override bool ContainsEmitWithAwait ()
6158 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6161 public override Expression CreateExpressionTree (ResolveContext ec)
6163 Arguments args = new Arguments (3);
6164 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6165 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6166 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6167 return CreateExpressionFactoryCall (ec, "Condition", args);
6170 protected override Expression DoResolve (ResolveContext ec)
6172 expr = expr.Resolve (ec);
6173 true_expr = true_expr.Resolve (ec);
6174 false_expr = false_expr.Resolve (ec);
6176 if (true_expr == null || false_expr == null || expr == null)
6179 eclass = ExprClass.Value;
6180 TypeSpec true_type = true_expr.Type;
6181 TypeSpec false_type = false_expr.Type;
6185 // First, if an implicit conversion exists from true_expr
6186 // to false_expr, then the result type is of type false_expr.Type
6188 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6189 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6190 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6192 // Check if both can convert implicitly to each other's type
6196 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6197 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6199 // LAMESPEC: There seems to be hardcoded promotition to int type when
6200 // both sides are numeric constants and one side is int constant and
6201 // other side is numeric constant convertible to int.
6203 // var res = condition ? (short)1 : 1;
6205 // Type of res is int even if according to the spec the conversion is
6206 // ambiguous because 1 literal can be converted to short.
6208 if (conv_false_expr != null) {
6209 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6211 conv_false_expr = null;
6212 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6213 conv_false_expr = null;
6217 if (conv_false_expr != null) {
6218 ec.Report.Error (172, true_expr.Location,
6219 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6220 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6225 if (true_expr.Type != type)
6226 true_expr = EmptyCast.Create (true_expr, type);
6227 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6230 if (false_type != InternalType.ErrorType) {
6231 ec.Report.Error (173, true_expr.Location,
6232 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6233 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6239 Constant c = expr as Constant;
6241 bool is_false = c.IsDefaultValue;
6244 // Don't issue the warning for constant expressions
6246 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6247 // CSC: Missing warning
6248 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6251 return ReducedExpression.Create (
6252 is_false ? false_expr : true_expr, this,
6253 false_expr is Constant && true_expr is Constant).Resolve (ec);
6259 public override void Emit (EmitContext ec)
6261 Label false_target = ec.DefineLabel ();
6262 Label end_target = ec.DefineLabel ();
6264 expr.EmitBranchable (ec, false_target, false);
6265 true_expr.Emit (ec);
6268 // Verifier doesn't support interface merging. When there are two types on
6269 // the stack without common type hint and the common type is an interface.
6270 // Use temporary local to give verifier hint on what type to unify the stack
6272 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6273 var temp = ec.GetTemporaryLocal (type);
6274 ec.Emit (OpCodes.Stloc, temp);
6275 ec.Emit (OpCodes.Ldloc, temp);
6276 ec.FreeTemporaryLocal (temp, type);
6279 ec.Emit (OpCodes.Br, end_target);
6280 ec.MarkLabel (false_target);
6281 false_expr.Emit (ec);
6282 ec.MarkLabel (end_target);
6285 public override void FlowAnalysis (FlowAnalysisContext fc)
6287 expr.FlowAnalysisConditional (fc);
6288 var expr_true = fc.DefiniteAssignmentOnTrue;
6289 var expr_false = fc.DefiniteAssignmentOnFalse;
6291 fc.BranchDefiniteAssignment (expr_true);
6292 true_expr.FlowAnalysis (fc);
6293 var true_fc = fc.DefiniteAssignment;
6295 fc.BranchDefiniteAssignment (expr_false);
6296 false_expr.FlowAnalysis (fc);
6298 fc.DefiniteAssignment &= true_fc;
6301 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6303 expr.FlowAnalysisConditional (fc);
6304 var expr_true = fc.DefiniteAssignmentOnTrue;
6305 var expr_false = fc.DefiniteAssignmentOnFalse;
6307 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6308 true_expr.FlowAnalysisConditional (fc);
6309 var true_fc = fc.DefiniteAssignment;
6310 var true_da_true = fc.DefiniteAssignmentOnTrue;
6311 var true_da_false = fc.DefiniteAssignmentOnFalse;
6313 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6314 false_expr.FlowAnalysisConditional (fc);
6316 fc.DefiniteAssignment &= true_fc;
6317 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6318 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6321 protected override void CloneTo (CloneContext clonectx, Expression t)
6323 Conditional target = (Conditional) t;
6325 target.expr = expr.Clone (clonectx);
6326 target.true_expr = true_expr.Clone (clonectx);
6327 target.false_expr = false_expr.Clone (clonectx);
6331 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6333 LocalTemporary temp;
6336 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6337 public abstract void SetHasAddressTaken ();
6339 public abstract bool IsLockedByStatement { get; set; }
6341 public abstract bool IsFixed { get; }
6342 public abstract bool IsRef { get; }
6343 public abstract string Name { get; }
6346 // Variable IL data, it has to be protected to encapsulate hoisted variables
6348 protected abstract ILocalVariable Variable { get; }
6351 // Variable flow-analysis data
6353 public abstract VariableInfo VariableInfo { get; }
6356 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6358 HoistedVariable hv = GetHoistedVariable (ec);
6360 hv.AddressOf (ec, mode);
6364 Variable.EmitAddressOf (ec);
6367 public override bool ContainsEmitWithAwait ()
6372 public override Expression CreateExpressionTree (ResolveContext ec)
6374 HoistedVariable hv = GetHoistedVariable (ec);
6376 return hv.CreateExpressionTree ();
6378 Arguments arg = new Arguments (1);
6379 arg.Add (new Argument (this));
6380 return CreateExpressionFactoryCall (ec, "Constant", arg);
6383 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6385 if (IsLockedByStatement) {
6386 rc.Report.Warning (728, 2, loc,
6387 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6394 public override void Emit (EmitContext ec)
6399 public override void EmitSideEffect (EmitContext ec)
6405 // This method is used by parameters that are references, that are
6406 // being passed as references: we only want to pass the pointer (that
6407 // is already stored in the parameter, not the address of the pointer,
6408 // and not the value of the variable).
6410 public void EmitLoad (EmitContext ec)
6415 public void Emit (EmitContext ec, bool leave_copy)
6417 HoistedVariable hv = GetHoistedVariable (ec);
6419 hv.Emit (ec, leave_copy);
6427 // If we are a reference, we loaded on the stack a pointer
6428 // Now lets load the real value
6430 ec.EmitLoadFromPtr (type);
6434 ec.Emit (OpCodes.Dup);
6437 temp = new LocalTemporary (Type);
6443 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6444 bool prepare_for_load)
6446 HoistedVariable hv = GetHoistedVariable (ec);
6448 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6452 New n_source = source as New;
6453 if (n_source != null) {
6454 if (!n_source.Emit (ec, this)) {
6458 ec.EmitLoadFromPtr (type);
6470 ec.Emit (OpCodes.Dup);
6472 temp = new LocalTemporary (Type);
6478 ec.EmitStoreFromPtr (type);
6480 Variable.EmitAssign (ec);
6488 public override Expression EmitToField (EmitContext ec)
6490 HoistedVariable hv = GetHoistedVariable (ec);
6492 return hv.EmitToField (ec);
6495 return base.EmitToField (ec);
6498 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6500 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6503 public HoistedVariable GetHoistedVariable (EmitContext ec)
6505 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6508 public override string GetSignatureForError ()
6513 public bool IsHoisted {
6514 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6519 // Resolved reference to a local variable
6521 public class LocalVariableReference : VariableReference
6523 public LocalVariable local_info;
6525 public LocalVariableReference (LocalVariable li, Location l)
6527 this.local_info = li;
6531 public override VariableInfo VariableInfo {
6532 get { return local_info.VariableInfo; }
6535 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6537 return local_info.HoistedVariant;
6543 // A local variable is always fixed
6545 public override bool IsFixed {
6551 public override bool IsLockedByStatement {
6553 return local_info.IsLocked;
6556 local_info.IsLocked = value;
6560 public override bool IsRef {
6561 get { return false; }
6564 public override string Name {
6565 get { return local_info.Name; }
6570 public override void FlowAnalysis (FlowAnalysisContext fc)
6572 VariableInfo variable_info = VariableInfo;
6573 if (variable_info == null)
6576 if (fc.IsDefinitelyAssigned (variable_info))
6579 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6580 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6583 public override void SetHasAddressTaken ()
6585 local_info.SetHasAddressTaken ();
6588 void DoResolveBase (ResolveContext ec)
6590 eclass = ExprClass.Variable;
6591 type = local_info.Type;
6594 // If we are referencing a variable from the external block
6595 // flag it for capturing
6597 if (ec.MustCaptureVariable (local_info)) {
6598 if (local_info.AddressTaken) {
6599 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6600 } else if (local_info.IsFixed) {
6601 ec.Report.Error (1764, loc,
6602 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6603 GetSignatureForError ());
6606 if (ec.IsVariableCapturingRequired) {
6607 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6608 storey.CaptureLocalVariable (ec, local_info);
6613 protected override Expression DoResolve (ResolveContext ec)
6615 local_info.SetIsUsed ();
6619 if (local_info.Type == InternalType.VarOutType) {
6620 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6621 GetSignatureForError ());
6623 type = InternalType.ErrorType;
6629 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6632 // Don't be too pedantic when variable is used as out param or for some broken code
6633 // which uses property/indexer access to run some initialization
6635 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6636 local_info.SetIsUsed ();
6638 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6639 if (rhs == EmptyExpression.LValueMemberAccess) {
6640 // CS1654 already reported
6644 if (rhs == EmptyExpression.OutAccess) {
6645 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6646 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6647 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6648 } else if (rhs == EmptyExpression.UnaryAddress) {
6649 code = 459; msg = "Cannot take the address of {1} `{0}'";
6651 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6653 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6657 if (eclass == ExprClass.Unresolved)
6660 return base.DoResolveLValue (ec, rhs);
6663 public override int GetHashCode ()
6665 return local_info.GetHashCode ();
6668 public override bool Equals (object obj)
6670 LocalVariableReference lvr = obj as LocalVariableReference;
6674 return local_info == lvr.local_info;
6677 protected override ILocalVariable Variable {
6678 get { return local_info; }
6681 public override string ToString ()
6683 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6686 protected override void CloneTo (CloneContext clonectx, Expression t)
6693 /// This represents a reference to a parameter in the intermediate
6696 public class ParameterReference : VariableReference
6698 protected ParametersBlock.ParameterInfo pi;
6700 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6708 public override bool IsLockedByStatement {
6713 pi.IsLocked = value;
6717 public override bool IsRef {
6718 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6721 bool HasOutModifier {
6722 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6725 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6727 return pi.Parameter.HoistedVariant;
6731 // A ref or out parameter is classified as a moveable variable, even
6732 // if the argument given for the parameter is a fixed variable
6734 public override bool IsFixed {
6735 get { return !IsRef; }
6738 public override string Name {
6739 get { return Parameter.Name; }
6742 public Parameter Parameter {
6743 get { return pi.Parameter; }
6746 public override VariableInfo VariableInfo {
6747 get { return pi.VariableInfo; }
6750 protected override ILocalVariable Variable {
6751 get { return Parameter; }
6756 public override void AddressOf (EmitContext ec, AddressOp mode)
6759 // ParameterReferences might already be a reference
6766 base.AddressOf (ec, mode);
6769 public override void SetHasAddressTaken ()
6771 Parameter.HasAddressTaken = true;
6774 bool DoResolveBase (ResolveContext ec)
6776 if (eclass != ExprClass.Unresolved)
6779 type = pi.ParameterType;
6780 eclass = ExprClass.Variable;
6783 // If we are referencing a parameter from the external block
6784 // flag it for capturing
6786 if (ec.MustCaptureVariable (pi)) {
6787 if (Parameter.HasAddressTaken)
6788 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6791 ec.Report.Error (1628, loc,
6792 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6793 Name, ec.CurrentAnonymousMethod.ContainerType);
6796 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6797 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6798 storey.CaptureParameter (ec, pi, this);
6805 public override int GetHashCode ()
6807 return Name.GetHashCode ();
6810 public override bool Equals (object obj)
6812 ParameterReference pr = obj as ParameterReference;
6816 return Name == pr.Name;
6819 protected override void CloneTo (CloneContext clonectx, Expression target)
6825 public override Expression CreateExpressionTree (ResolveContext ec)
6827 HoistedVariable hv = GetHoistedVariable (ec);
6829 return hv.CreateExpressionTree ();
6831 return Parameter.ExpressionTreeVariableReference ();
6834 protected override Expression DoResolve (ResolveContext ec)
6836 if (!DoResolveBase (ec))
6842 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6844 if (!DoResolveBase (ec))
6847 if (Parameter.HoistedVariant != null)
6848 Parameter.HoistedVariant.IsAssigned = true;
6850 return base.DoResolveLValue (ec, right_side);
6853 public override void FlowAnalysis (FlowAnalysisContext fc)
6855 VariableInfo variable_info = VariableInfo;
6856 if (variable_info == null)
6859 if (fc.IsDefinitelyAssigned (variable_info))
6862 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6863 fc.SetVariableAssigned (variable_info);
6868 /// Invocation of methods or delegates.
6870 public class Invocation : ExpressionStatement
6872 public class Predefined : Invocation
6874 public Predefined (MethodGroupExpr expr, Arguments arguments)
6875 : base (expr, arguments)
6880 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6882 if (!rc.IsObsolete) {
6883 var member = mg.BestCandidate;
6884 ObsoleteAttribute oa = member.GetAttributeObsolete ();
6886 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
6893 protected Arguments arguments;
6894 protected Expression expr;
6895 protected MethodGroupExpr mg;
6896 bool conditional_access_receiver;
6898 public Invocation (Expression expr, Arguments arguments)
6901 this.arguments = arguments;
6903 loc = expr.Location;
6908 public Arguments Arguments {
6914 public Expression Exp {
6920 public MethodGroupExpr MethodGroup {
6926 public override Location StartLocation {
6928 return expr.StartLocation;
6934 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6936 if (MethodGroup == null)
6939 var candidate = MethodGroup.BestCandidate;
6940 if (candidate == null || !(candidate.IsStatic || Exp is This))
6943 var args_count = arguments == null ? 0 : arguments.Count;
6944 if (args_count != body.Parameters.Count)
6947 var lambda_parameters = body.Block.Parameters.FixedParameters;
6948 for (int i = 0; i < args_count; ++i) {
6949 var pr = arguments[i].Expr as ParameterReference;
6953 if (lambda_parameters[i] != pr.Parameter)
6956 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6960 var emg = MethodGroup as ExtensionMethodGroupExpr;
6962 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6963 if (candidate.IsGeneric) {
6964 var targs = new TypeExpression [candidate.Arity];
6965 for (int i = 0; i < targs.Length; ++i) {
6966 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6969 mg.SetTypeArguments (null, new TypeArguments (targs));
6978 protected override void CloneTo (CloneContext clonectx, Expression t)
6980 Invocation target = (Invocation) t;
6982 if (arguments != null)
6983 target.arguments = arguments.Clone (clonectx);
6985 target.expr = expr.Clone (clonectx);
6988 public override bool ContainsEmitWithAwait ()
6990 if (arguments != null && arguments.ContainsEmitWithAwait ())
6993 return mg.ContainsEmitWithAwait ();
6996 public override Expression CreateExpressionTree (ResolveContext ec)
6998 Expression instance = mg.IsInstance ?
6999 mg.InstanceExpression.CreateExpressionTree (ec) :
7000 new NullLiteral (loc);
7002 var args = Arguments.CreateForExpressionTree (ec, arguments,
7004 mg.CreateExpressionTree (ec));
7006 return CreateExpressionFactoryCall (ec, "Call", args);
7009 protected override Expression DoResolve (ResolveContext rc)
7011 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
7012 if (expr.HasConditionalAccess ()) {
7013 conditional_access_receiver = true;
7014 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
7015 return DoResolveInvocation (rc);
7020 return DoResolveInvocation (rc);
7023 Expression DoResolveInvocation (ResolveContext ec)
7025 Expression member_expr;
7026 var atn = expr as ATypeNameExpression;
7028 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7029 if (member_expr != null) {
7030 var name_of = member_expr as NameOf;
7031 if (name_of != null) {
7032 return name_of.ResolveOverload (ec, arguments);
7035 member_expr = member_expr.Resolve (ec);
7038 member_expr = expr.Resolve (ec);
7041 if (member_expr == null)
7045 // Next, evaluate all the expressions in the argument list
7047 bool dynamic_arg = false;
7048 if (arguments != null)
7049 arguments.Resolve (ec, out dynamic_arg);
7051 TypeSpec expr_type = member_expr.Type;
7052 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7053 return DoResolveDynamic (ec, member_expr);
7055 mg = member_expr as MethodGroupExpr;
7056 Expression invoke = null;
7059 if (expr_type != null && expr_type.IsDelegate) {
7060 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7061 invoke = invoke.Resolve (ec);
7062 if (invoke == null || !dynamic_arg)
7065 if (member_expr is RuntimeValueExpression) {
7066 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7067 member_expr.Type.GetSignatureForError ());
7071 MemberExpr me = member_expr as MemberExpr;
7073 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7077 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7078 member_expr.GetSignatureForError ());
7083 if (invoke == null) {
7084 mg = DoResolveOverload (ec);
7090 return DoResolveDynamic (ec, member_expr);
7092 var method = mg.BestCandidate;
7093 type = mg.BestCandidateReturnType;
7094 if (conditional_access_receiver)
7095 type = LiftMemberType (ec, type);
7097 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7099 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7101 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7105 IsSpecialMethodInvocation (ec, method, loc);
7107 eclass = ExprClass.Value;
7111 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7114 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7116 args = dmb.Arguments;
7117 if (arguments != null)
7118 args.AddRange (arguments);
7119 } else if (mg == null) {
7120 if (arguments == null)
7121 args = new Arguments (1);
7125 args.Insert (0, new Argument (memberExpr));
7129 ec.Report.Error (1971, loc,
7130 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7135 if (arguments == null)
7136 args = new Arguments (1);
7140 MemberAccess ma = expr as MemberAccess;
7142 var inst = mg.InstanceExpression;
7143 var left_type = inst as TypeExpr;
7144 if (left_type != null) {
7145 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7146 } else if (inst != null) {
7148 // Any value type has to be pass as by-ref to get back the same
7149 // instance on which the member was called
7151 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7152 Argument.AType.Ref : Argument.AType.None;
7153 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7155 } else { // is SimpleName
7157 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7159 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7164 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7167 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7169 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7172 public override void FlowAnalysis (FlowAnalysisContext fc)
7174 if (mg.IsConditionallyExcluded)
7177 mg.FlowAnalysis (fc);
7179 if (arguments != null)
7180 arguments.FlowAnalysis (fc);
7182 if (conditional_access_receiver)
7183 fc.ConditionalAccessEnd ();
7186 public override string GetSignatureForError ()
7188 return mg.GetSignatureForError ();
7191 public override bool HasConditionalAccess ()
7193 return expr.HasConditionalAccess ();
7197 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7198 // or the type dynamic, then the member is invocable
7200 public static bool IsMemberInvocable (MemberSpec member)
7202 switch (member.Kind) {
7203 case MemberKind.Event:
7205 case MemberKind.Field:
7206 case MemberKind.Property:
7207 var m = member as IInterfaceMemberSpec;
7208 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7214 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7216 if (!method.IsReservedMethod)
7219 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7222 ec.Report.SymbolRelatedToPreviousError (method);
7223 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7224 method.GetSignatureForError ());
7229 public override void Emit (EmitContext ec)
7231 if (mg.IsConditionallyExcluded)
7234 if (conditional_access_receiver)
7235 mg.EmitCall (ec, arguments, type, false);
7237 mg.EmitCall (ec, arguments, false);
7240 public override void EmitStatement (EmitContext ec)
7242 if (mg.IsConditionallyExcluded)
7245 if (conditional_access_receiver)
7246 mg.EmitCall (ec, arguments, type, true);
7248 mg.EmitCall (ec, arguments, true);
7251 public override SLE.Expression MakeExpression (BuilderContext ctx)
7253 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7256 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7259 throw new NotSupportedException ();
7261 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7262 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7266 public override object Accept (StructuralVisitor visitor)
7268 return visitor.Visit (this);
7273 // Implements simple new expression
7275 public class New : ExpressionStatement, IMemoryLocation
7277 protected Arguments arguments;
7280 // During bootstrap, it contains the RequestedType,
7281 // but if `type' is not null, it *might* contain a NewDelegate
7282 // (because of field multi-initialization)
7284 protected Expression RequestedType;
7286 protected MethodSpec method;
7288 public New (Expression requested_type, Arguments arguments, Location l)
7290 RequestedType = requested_type;
7291 this.arguments = arguments;
7296 public Arguments Arguments {
7303 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7305 public bool IsGeneratedStructConstructor {
7307 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7311 public Expression TypeExpression {
7313 return RequestedType;
7320 /// Converts complex core type syntax like 'new int ()' to simple constant
7322 public static Constant Constantify (TypeSpec t, Location loc)
7324 switch (t.BuiltinType) {
7325 case BuiltinTypeSpec.Type.Int:
7326 return new IntConstant (t, 0, loc);
7327 case BuiltinTypeSpec.Type.UInt:
7328 return new UIntConstant (t, 0, loc);
7329 case BuiltinTypeSpec.Type.Long:
7330 return new LongConstant (t, 0, loc);
7331 case BuiltinTypeSpec.Type.ULong:
7332 return new ULongConstant (t, 0, loc);
7333 case BuiltinTypeSpec.Type.Float:
7334 return new FloatConstant (t, 0, loc);
7335 case BuiltinTypeSpec.Type.Double:
7336 return new DoubleConstant (t, 0, loc);
7337 case BuiltinTypeSpec.Type.Short:
7338 return new ShortConstant (t, 0, loc);
7339 case BuiltinTypeSpec.Type.UShort:
7340 return new UShortConstant (t, 0, loc);
7341 case BuiltinTypeSpec.Type.SByte:
7342 return new SByteConstant (t, 0, loc);
7343 case BuiltinTypeSpec.Type.Byte:
7344 return new ByteConstant (t, 0, loc);
7345 case BuiltinTypeSpec.Type.Char:
7346 return new CharConstant (t, '\0', loc);
7347 case BuiltinTypeSpec.Type.Bool:
7348 return new BoolConstant (t, false, loc);
7349 case BuiltinTypeSpec.Type.Decimal:
7350 return new DecimalConstant (t, 0, loc);
7354 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7356 if (t.IsNullableType)
7357 return Nullable.LiftedNull.Create (t, loc);
7362 public override bool ContainsEmitWithAwait ()
7364 return arguments != null && arguments.ContainsEmitWithAwait ();
7368 // Checks whether the type is an interface that has the
7369 // [ComImport, CoClass] attributes and must be treated
7372 public Expression CheckComImport (ResolveContext ec)
7374 if (!type.IsInterface)
7378 // Turn the call into:
7379 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7381 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7382 if (real_class == null)
7385 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7386 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7387 return cast.Resolve (ec);
7390 public override Expression CreateExpressionTree (ResolveContext ec)
7393 if (method == null) {
7394 args = new Arguments (1);
7395 args.Add (new Argument (new TypeOf (type, loc)));
7397 args = Arguments.CreateForExpressionTree (ec,
7398 arguments, new TypeOfMethod (method, loc));
7401 return CreateExpressionFactoryCall (ec, "New", args);
7404 protected override Expression DoResolve (ResolveContext ec)
7406 type = RequestedType.ResolveAsType (ec);
7410 eclass = ExprClass.Value;
7412 if (type.IsPointer) {
7413 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7414 type.GetSignatureForError ());
7418 if (arguments == null) {
7419 Constant c = Constantify (type, RequestedType.Location);
7421 return ReducedExpression.Create (c, this);
7424 if (type.IsDelegate) {
7425 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7428 var tparam = type as TypeParameterSpec;
7429 if (tparam != null) {
7431 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7432 // where type parameter constraint is inflated to struct
7434 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7435 ec.Report.Error (304, loc,
7436 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7437 type.GetSignatureForError ());
7440 if ((arguments != null) && (arguments.Count != 0)) {
7441 ec.Report.Error (417, loc,
7442 "`{0}': cannot provide arguments when creating an instance of a variable type",
7443 type.GetSignatureForError ());
7449 if (type.IsStatic) {
7450 ec.Report.SymbolRelatedToPreviousError (type);
7451 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7455 if (type.IsInterface || type.IsAbstract){
7456 if (!TypeManager.IsGenericType (type)) {
7457 RequestedType = CheckComImport (ec);
7458 if (RequestedType != null)
7459 return RequestedType;
7462 ec.Report.SymbolRelatedToPreviousError (type);
7463 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7468 if (arguments != null) {
7469 arguments.Resolve (ec, out dynamic);
7474 method = ConstructorLookup (ec, type, ref arguments, loc);
7477 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7478 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7484 void DoEmitTypeParameter (EmitContext ec)
7486 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7490 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7491 ec.Emit (OpCodes.Call, ctor_factory);
7495 // This Emit can be invoked in two contexts:
7496 // * As a mechanism that will leave a value on the stack (new object)
7497 // * As one that wont (init struct)
7499 // If we are dealing with a ValueType, we have a few
7500 // situations to deal with:
7502 // * The target is a ValueType, and we have been provided
7503 // the instance (this is easy, we are being assigned).
7505 // * The target of New is being passed as an argument,
7506 // to a boxing operation or a function that takes a
7509 // In this case, we need to create a temporary variable
7510 // that is the argument of New.
7512 // Returns whether a value is left on the stack
7514 // *** Implementation note ***
7516 // To benefit from this optimization, each assignable expression
7517 // has to manually cast to New and call this Emit.
7519 // TODO: It's worth to implement it for arrays and fields
7521 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7523 bool is_value_type = type.IsStructOrEnum;
7524 VariableReference vr = target as VariableReference;
7526 if (target != null && is_value_type && (vr != null || method == null)) {
7527 target.AddressOf (ec, AddressOp.Store);
7528 } else if (vr != null && vr.IsRef) {
7532 if (arguments != null) {
7533 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7534 arguments = arguments.Emit (ec, false, true);
7536 arguments.Emit (ec);
7539 if (is_value_type) {
7540 if (method == null) {
7541 ec.Emit (OpCodes.Initobj, type);
7546 ec.MarkCallEntry (loc);
7547 ec.Emit (OpCodes.Call, method);
7552 if (type is TypeParameterSpec) {
7553 DoEmitTypeParameter (ec);
7557 ec.MarkCallEntry (loc);
7558 ec.Emit (OpCodes.Newobj, method);
7562 public override void Emit (EmitContext ec)
7564 LocalTemporary v = null;
7565 if (method == null && type.IsStructOrEnum) {
7566 // TODO: Use temporary variable from pool
7567 v = new LocalTemporary (type);
7574 public override void EmitStatement (EmitContext ec)
7576 LocalTemporary v = null;
7577 if (method == null && TypeSpec.IsValueType (type)) {
7578 // TODO: Use temporary variable from pool
7579 v = new LocalTemporary (type);
7583 ec.Emit (OpCodes.Pop);
7586 public override void FlowAnalysis (FlowAnalysisContext fc)
7588 if (arguments != null)
7589 arguments.FlowAnalysis (fc);
7592 public void AddressOf (EmitContext ec, AddressOp mode)
7594 EmitAddressOf (ec, mode);
7597 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7599 LocalTemporary value_target = new LocalTemporary (type);
7601 if (type is TypeParameterSpec) {
7602 DoEmitTypeParameter (ec);
7603 value_target.Store (ec);
7604 value_target.AddressOf (ec, mode);
7605 return value_target;
7608 value_target.AddressOf (ec, AddressOp.Store);
7610 if (method == null) {
7611 ec.Emit (OpCodes.Initobj, type);
7613 if (arguments != null)
7614 arguments.Emit (ec);
7616 ec.Emit (OpCodes.Call, method);
7619 value_target.AddressOf (ec, mode);
7620 return value_target;
7623 protected override void CloneTo (CloneContext clonectx, Expression t)
7625 New target = (New) t;
7627 target.RequestedType = RequestedType.Clone (clonectx);
7628 if (arguments != null){
7629 target.arguments = arguments.Clone (clonectx);
7633 public override SLE.Expression MakeExpression (BuilderContext ctx)
7636 return base.MakeExpression (ctx);
7638 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7642 public override object Accept (StructuralVisitor visitor)
7644 return visitor.Visit (this);
7649 // Array initializer expression, the expression is allowed in
7650 // variable or field initialization only which makes it tricky as
7651 // the type has to be infered based on the context either from field
7652 // type or variable type (think of multiple declarators)
7654 public class ArrayInitializer : Expression
7656 List<Expression> elements;
7657 BlockVariable variable;
7659 public ArrayInitializer (List<Expression> init, Location loc)
7665 public ArrayInitializer (int count, Location loc)
7666 : this (new List<Expression> (count), loc)
7670 public ArrayInitializer (Location loc)
7678 get { return elements.Count; }
7681 public List<Expression> Elements {
7687 public Expression this [int index] {
7689 return elements [index];
7693 public BlockVariable VariableDeclaration {
7704 public void Add (Expression expr)
7706 elements.Add (expr);
7709 public override bool ContainsEmitWithAwait ()
7711 throw new NotSupportedException ();
7714 public override Expression CreateExpressionTree (ResolveContext ec)
7716 throw new NotSupportedException ("ET");
7719 protected override void CloneTo (CloneContext clonectx, Expression t)
7721 var target = (ArrayInitializer) t;
7723 target.elements = new List<Expression> (elements.Count);
7724 foreach (var element in elements)
7725 target.elements.Add (element.Clone (clonectx));
7728 protected override Expression DoResolve (ResolveContext rc)
7730 var current_field = rc.CurrentMemberDefinition as FieldBase;
7731 TypeExpression type;
7732 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7733 type = new TypeExpression (current_field.MemberType, current_field.Location);
7734 } else if (variable != null) {
7735 if (variable.TypeExpression is VarExpr) {
7736 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7737 return EmptyExpression.Null;
7740 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7742 throw new NotImplementedException ("Unexpected array initializer context");
7745 return new ArrayCreation (type, this).Resolve (rc);
7748 public override void Emit (EmitContext ec)
7750 throw new InternalErrorException ("Missing Resolve call");
7753 public override void FlowAnalysis (FlowAnalysisContext fc)
7755 throw new InternalErrorException ("Missing Resolve call");
7758 public override object Accept (StructuralVisitor visitor)
7760 return visitor.Visit (this);
7765 /// 14.5.10.2: Represents an array creation expression.
7769 /// There are two possible scenarios here: one is an array creation
7770 /// expression that specifies the dimensions and optionally the
7771 /// initialization data and the other which does not need dimensions
7772 /// specified but where initialization data is mandatory.
7774 public class ArrayCreation : Expression
7776 FullNamedExpression requested_base_type;
7777 ArrayInitializer initializers;
7780 // The list of Argument types.
7781 // This is used to construct the `newarray' or constructor signature
7783 protected List<Expression> arguments;
7785 protected TypeSpec array_element_type;
7787 protected int dimensions;
7788 protected readonly ComposedTypeSpecifier rank;
7789 Expression first_emit;
7790 LocalTemporary first_emit_temp;
7792 protected List<Expression> array_data;
7794 Dictionary<int, int> bounds;
7797 // The number of constants in array initializers
7798 int const_initializers_count;
7799 bool only_constant_initializers;
7801 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7802 : this (requested_base_type, rank, initializers, l)
7804 arguments = new List<Expression> (exprs);
7805 num_arguments = arguments.Count;
7809 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7811 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7813 this.requested_base_type = requested_base_type;
7815 this.initializers = initializers;
7819 num_arguments = rank.Dimension;
7823 // For compiler generated single dimensional arrays only
7825 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7826 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7831 // For expressions like int[] foo = { 1, 2, 3 };
7833 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7834 : this (requested_base_type, null, initializers, initializers.Location)
7838 public ComposedTypeSpecifier Rank {
7844 public FullNamedExpression TypeExpression {
7846 return this.requested_base_type;
7850 public ArrayInitializer Initializers {
7852 return this.initializers;
7856 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7858 if (initializers != null && bounds == null) {
7860 // We use this to store all the data values in the order in which we
7861 // will need to store them in the byte blob later
7863 array_data = new List<Expression> (probe.Count);
7864 bounds = new Dictionary<int, int> ();
7867 if (specified_dims) {
7868 Expression a = arguments [idx];
7873 a = ConvertExpressionToArrayIndex (ec, a);
7879 if (initializers != null) {
7880 Constant c = a as Constant;
7881 if (c == null && a is ArrayIndexCast)
7882 c = ((ArrayIndexCast) a).Child as Constant;
7885 ec.Report.Error (150, a.Location, "A constant value is expected");
7891 value = System.Convert.ToInt32 (c.GetValue ());
7893 ec.Report.Error (150, a.Location, "A constant value is expected");
7897 // TODO: probe.Count does not fit ulong in
7898 if (value != probe.Count) {
7899 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7903 bounds[idx] = value;
7907 if (initializers == null)
7910 for (int i = 0; i < probe.Count; ++i) {
7912 if (o is ArrayInitializer) {
7913 var sub_probe = o as ArrayInitializer;
7914 if (idx + 1 >= dimensions){
7915 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7919 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7920 if (!bounds.ContainsKey(idx + 1))
7921 bounds[idx + 1] = sub_probe.Count;
7923 if (bounds[idx + 1] != sub_probe.Count) {
7924 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7928 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7931 } else if (child_bounds > 1) {
7932 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7934 Expression element = ResolveArrayElement (ec, o);
7935 if (element == null)
7938 // Initializers with the default values can be ignored
7939 Constant c = element as Constant;
7941 if (!c.IsDefaultInitializer (array_element_type)) {
7942 ++const_initializers_count;
7945 only_constant_initializers = false;
7948 array_data.Add (element);
7955 public override bool ContainsEmitWithAwait ()
7957 foreach (var arg in arguments) {
7958 if (arg.ContainsEmitWithAwait ())
7962 return InitializersContainAwait ();
7965 public override Expression CreateExpressionTree (ResolveContext ec)
7969 if (array_data == null) {
7970 args = new Arguments (arguments.Count + 1);
7971 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7972 foreach (Expression a in arguments)
7973 args.Add (new Argument (a.CreateExpressionTree (ec)));
7975 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7978 if (dimensions > 1) {
7979 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7983 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7984 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7985 if (array_data != null) {
7986 for (int i = 0; i < array_data.Count; ++i) {
7987 Expression e = array_data [i];
7988 args.Add (new Argument (e.CreateExpressionTree (ec)));
7992 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7995 void UpdateIndices (ResolveContext rc)
7998 for (var probe = initializers; probe != null;) {
7999 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8001 bounds[i++] = probe.Count;
8003 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8004 probe = (ArrayInitializer) probe[0];
8005 } else if (dimensions > i) {
8013 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8015 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8018 public override void FlowAnalysis (FlowAnalysisContext fc)
8020 foreach (var arg in arguments)
8021 arg.FlowAnalysis (fc);
8023 if (array_data != null) {
8024 foreach (var ad in array_data)
8025 ad.FlowAnalysis (fc);
8029 bool InitializersContainAwait ()
8031 if (array_data == null)
8034 foreach (var expr in array_data) {
8035 if (expr.ContainsEmitWithAwait ())
8042 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8044 element = element.Resolve (ec);
8045 if (element == null)
8048 if (element is CompoundAssign.TargetExpression) {
8049 if (first_emit != null)
8050 throw new InternalErrorException ("Can only handle one mutator at a time");
8051 first_emit = element;
8052 element = first_emit_temp = new LocalTemporary (element.Type);
8055 return Convert.ImplicitConversionRequired (
8056 ec, element, array_element_type, loc);
8059 protected bool ResolveInitializers (ResolveContext ec)
8062 only_constant_initializers = true;
8065 if (arguments != null) {
8067 for (int i = 0; i < arguments.Count; ++i) {
8068 res &= CheckIndices (ec, initializers, i, true, dimensions);
8069 if (initializers != null)
8076 arguments = new List<Expression> ();
8078 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8087 // Resolved the type of the array
8089 bool ResolveArrayType (ResolveContext ec)
8094 FullNamedExpression array_type_expr;
8095 if (num_arguments > 0) {
8096 array_type_expr = new ComposedCast (requested_base_type, rank);
8098 array_type_expr = requested_base_type;
8101 type = array_type_expr.ResolveAsType (ec);
8102 if (array_type_expr == null)
8105 var ac = type as ArrayContainer;
8107 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8111 array_element_type = ac.Element;
8112 dimensions = ac.Rank;
8117 protected override Expression DoResolve (ResolveContext ec)
8122 if (!ResolveArrayType (ec))
8126 // validate the initializers and fill in any missing bits
8128 if (!ResolveInitializers (ec))
8131 eclass = ExprClass.Value;
8135 byte [] MakeByteBlob ()
8140 int count = array_data.Count;
8142 TypeSpec element_type = array_element_type;
8143 if (element_type.IsEnum)
8144 element_type = EnumSpec.GetUnderlyingType (element_type);
8146 factor = BuiltinTypeSpec.GetSize (element_type);
8148 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8150 data = new byte [(count * factor + 3) & ~3];
8153 for (int i = 0; i < count; ++i) {
8154 var c = array_data[i] as Constant;
8160 object v = c.GetValue ();
8162 switch (element_type.BuiltinType) {
8163 case BuiltinTypeSpec.Type.Long:
8164 long lval = (long) v;
8166 for (int j = 0; j < factor; ++j) {
8167 data[idx + j] = (byte) (lval & 0xFF);
8171 case BuiltinTypeSpec.Type.ULong:
8172 ulong ulval = (ulong) v;
8174 for (int j = 0; j < factor; ++j) {
8175 data[idx + j] = (byte) (ulval & 0xFF);
8176 ulval = (ulval >> 8);
8179 case BuiltinTypeSpec.Type.Float:
8180 var fval = SingleConverter.SingleToInt32Bits((float) v);
8182 data[idx] = (byte) (fval & 0xff);
8183 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8184 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8185 data[idx + 3] = (byte) (fval >> 24);
8187 case BuiltinTypeSpec.Type.Double:
8188 element = BitConverter.GetBytes ((double) v);
8190 for (int j = 0; j < factor; ++j)
8191 data[idx + j] = element[j];
8193 // FIXME: Handle the ARM float format.
8194 if (!BitConverter.IsLittleEndian)
8195 System.Array.Reverse (data, idx, 8);
8197 case BuiltinTypeSpec.Type.Char:
8198 int chval = (int) ((char) v);
8200 data[idx] = (byte) (chval & 0xff);
8201 data[idx + 1] = (byte) (chval >> 8);
8203 case BuiltinTypeSpec.Type.Short:
8204 int sval = (int) ((short) v);
8206 data[idx] = (byte) (sval & 0xff);
8207 data[idx + 1] = (byte) (sval >> 8);
8209 case BuiltinTypeSpec.Type.UShort:
8210 int usval = (int) ((ushort) v);
8212 data[idx] = (byte) (usval & 0xff);
8213 data[idx + 1] = (byte) (usval >> 8);
8215 case BuiltinTypeSpec.Type.Int:
8218 data[idx] = (byte) (val & 0xff);
8219 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8220 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8221 data[idx + 3] = (byte) (val >> 24);
8223 case BuiltinTypeSpec.Type.UInt:
8224 uint uval = (uint) v;
8226 data[idx] = (byte) (uval & 0xff);
8227 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8228 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8229 data[idx + 3] = (byte) (uval >> 24);
8231 case BuiltinTypeSpec.Type.SByte:
8232 data[idx] = (byte) (sbyte) v;
8234 case BuiltinTypeSpec.Type.Byte:
8235 data[idx] = (byte) v;
8237 case BuiltinTypeSpec.Type.Bool:
8238 data[idx] = (byte) ((bool) v ? 1 : 0);
8240 case BuiltinTypeSpec.Type.Decimal:
8241 int[] bits = Decimal.GetBits ((decimal) v);
8244 // FIXME: For some reason, this doesn't work on the MS runtime.
8245 int[] nbits = new int[4];
8251 for (int j = 0; j < 4; j++) {
8252 data[p++] = (byte) (nbits[j] & 0xff);
8253 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8254 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8255 data[p++] = (byte) (nbits[j] >> 24);
8259 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8268 #if NET_4_0 || MOBILE_DYNAMIC
8269 public override SLE.Expression MakeExpression (BuilderContext ctx)
8272 return base.MakeExpression (ctx);
8274 var initializers = new SLE.Expression [array_data.Count];
8275 for (var i = 0; i < initializers.Length; i++) {
8276 if (array_data [i] == null)
8277 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8279 initializers [i] = array_data [i].MakeExpression (ctx);
8282 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8288 // Emits the initializers for the array
8290 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8292 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8297 // First, the static data
8299 byte [] data = MakeByteBlob ();
8300 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8302 if (stackArray == null) {
8303 ec.Emit (OpCodes.Dup);
8305 stackArray.Emit (ec);
8308 ec.Emit (OpCodes.Ldtoken, fb);
8309 ec.Emit (OpCodes.Call, m);
8314 // Emits pieces of the array that can not be computed at compile
8315 // time (variables and string locations).
8317 // This always expect the top value on the stack to be the array
8319 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8321 int dims = bounds.Count;
8322 var current_pos = new int [dims];
8324 for (int i = 0; i < array_data.Count; i++){
8326 Expression e = array_data [i];
8327 var c = e as Constant;
8329 // Constant can be initialized via StaticInitializer
8330 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8334 if (stackArray != null) {
8335 if (e.ContainsEmitWithAwait ()) {
8336 e = e.EmitToField (ec);
8339 stackArray.EmitLoad (ec);
8341 ec.Emit (OpCodes.Dup);
8344 for (int idx = 0; idx < dims; idx++)
8345 ec.EmitInt (current_pos [idx]);
8348 // If we are dealing with a struct, get the
8349 // address of it, so we can store it.
8351 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8352 ec.Emit (OpCodes.Ldelema, etype);
8356 ec.EmitArrayStore ((ArrayContainer) type);
8362 for (int j = dims - 1; j >= 0; j--){
8364 if (current_pos [j] < bounds [j])
8366 current_pos [j] = 0;
8370 if (stackArray != null)
8371 stackArray.PrepareCleanup (ec);
8374 public override void Emit (EmitContext ec)
8376 var await_field = EmitToFieldSource (ec);
8377 if (await_field != null)
8378 await_field.Emit (ec);
8381 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8383 if (first_emit != null) {
8384 first_emit.Emit (ec);
8385 first_emit_temp.Store (ec);
8388 StackFieldExpr await_stack_field;
8389 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8390 await_stack_field = ec.GetTemporaryField (type);
8393 await_stack_field = null;
8396 EmitExpressionsList (ec, arguments);
8398 ec.EmitArrayNew ((ArrayContainer) type);
8400 if (initializers == null)
8401 return await_stack_field;
8403 if (await_stack_field != null)
8404 await_stack_field.EmitAssignFromStack (ec);
8408 // Emit static initializer for arrays which contain more than 2 items and
8409 // the static initializer will initialize at least 25% of array values or there
8410 // is more than 10 items to be initialized
8412 // NOTE: const_initializers_count does not contain default constant values.
8414 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8415 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8416 EmitStaticInitializers (ec, await_stack_field);
8418 if (!only_constant_initializers)
8419 EmitDynamicInitializers (ec, false, await_stack_field);
8423 EmitDynamicInitializers (ec, true, await_stack_field);
8426 if (first_emit_temp != null)
8427 first_emit_temp.Release (ec);
8429 return await_stack_field;
8432 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8434 // no multi dimensional or jagged arrays
8435 if (arguments.Count != 1 || array_element_type.IsArray) {
8436 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8440 // No array covariance, except for array -> object
8441 if (type != targetType) {
8442 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8443 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8447 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8448 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8453 // Single dimensional array of 0 size
8454 if (array_data == null) {
8455 IntConstant ic = arguments[0] as IntConstant;
8456 if (ic == null || !ic.IsDefaultValue) {
8457 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8465 enc.Encode (array_data.Count);
8466 foreach (var element in array_data) {
8467 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8471 protected override void CloneTo (CloneContext clonectx, Expression t)
8473 ArrayCreation target = (ArrayCreation) t;
8475 if (requested_base_type != null)
8476 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8478 if (arguments != null){
8479 target.arguments = new List<Expression> (arguments.Count);
8480 foreach (Expression e in arguments)
8481 target.arguments.Add (e.Clone (clonectx));
8484 if (initializers != null)
8485 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8488 public override object Accept (StructuralVisitor visitor)
8490 return visitor.Visit (this);
8495 // Represents an implicitly typed array epxression
8497 class ImplicitlyTypedArrayCreation : ArrayCreation
8499 TypeInferenceContext best_type_inference;
8501 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8502 : base (null, rank, initializers, loc)
8506 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8507 : base (null, initializers, loc)
8511 protected override Expression DoResolve (ResolveContext ec)
8516 dimensions = rank.Dimension;
8518 best_type_inference = new TypeInferenceContext ();
8520 if (!ResolveInitializers (ec))
8523 best_type_inference.FixAllTypes (ec);
8524 array_element_type = best_type_inference.InferredTypeArguments[0];
8525 best_type_inference = null;
8527 if (array_element_type == null ||
8528 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8529 arguments.Count != rank.Dimension) {
8530 ec.Report.Error (826, loc,
8531 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8536 // At this point we found common base type for all initializer elements
8537 // but we have to be sure that all static initializer elements are of
8540 UnifyInitializerElement (ec);
8542 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8543 eclass = ExprClass.Value;
8548 // Converts static initializer only
8550 void UnifyInitializerElement (ResolveContext ec)
8552 for (int i = 0; i < array_data.Count; ++i) {
8553 Expression e = array_data[i];
8555 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8559 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8561 element = element.Resolve (ec);
8562 if (element != null)
8563 best_type_inference.AddCommonTypeBound (element.Type);
8569 sealed class CompilerGeneratedThis : This
8571 public CompilerGeneratedThis (TypeSpec type, Location loc)
8577 protected override Expression DoResolve (ResolveContext rc)
8579 eclass = ExprClass.Variable;
8581 var block = rc.CurrentBlock;
8582 if (block != null) {
8583 var top = block.ParametersBlock.TopBlock;
8584 if (top.ThisVariable != null)
8585 variable_info = top.ThisVariable.VariableInfo;
8592 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8594 return DoResolve (rc);
8597 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8604 /// Represents the `this' construct
8607 public class This : VariableReference
8609 sealed class ThisVariable : ILocalVariable
8611 public static readonly ILocalVariable Instance = new ThisVariable ();
8613 public void Emit (EmitContext ec)
8618 public void EmitAssign (EmitContext ec)
8620 throw new InvalidOperationException ();
8623 public void EmitAddressOf (EmitContext ec)
8629 protected VariableInfo variable_info;
8631 public This (Location loc)
8638 public override string Name {
8639 get { return "this"; }
8642 public override bool IsLockedByStatement {
8650 public override bool IsRef {
8651 get { return type.IsStruct; }
8654 public override bool IsSideEffectFree {
8660 protected override ILocalVariable Variable {
8661 get { return ThisVariable.Instance; }
8664 public override VariableInfo VariableInfo {
8665 get { return variable_info; }
8668 public override bool IsFixed {
8669 get { return false; }
8674 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8677 // It's null for all cases when we don't need to check `this'
8678 // definitive assignment
8680 if (variable_info == null)
8683 if (fc.IsDefinitelyAssigned (variable_info))
8686 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8689 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8691 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8692 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8693 } else if (ec.CurrentAnonymousMethod != null) {
8694 ec.Report.Error (1673, loc,
8695 "Anonymous methods inside structs cannot access instance members of `this'. " +
8696 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8698 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8702 public override void FlowAnalysis (FlowAnalysisContext fc)
8704 CheckStructThisDefiniteAssignment (fc);
8707 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8712 AnonymousMethodStorey storey = ae.Storey;
8713 return storey != null ? storey.HoistedThis : null;
8716 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8718 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8721 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8724 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8730 public virtual void ResolveBase (ResolveContext ec)
8732 eclass = ExprClass.Variable;
8733 type = ec.CurrentType;
8735 if (!IsThisAvailable (ec, false)) {
8736 Error_ThisNotAvailable (ec);
8740 var block = ec.CurrentBlock;
8741 if (block != null) {
8742 var top = block.ParametersBlock.TopBlock;
8743 if (top.ThisVariable != null)
8744 variable_info = top.ThisVariable.VariableInfo;
8746 AnonymousExpression am = ec.CurrentAnonymousMethod;
8747 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8749 // Hoisted this is almost like hoisted variable but not exactly. When
8750 // there is no variable hoisted we can simply emit an instance method
8751 // without lifting this into a storey. Unfotunatelly this complicates
8752 // things in other cases because we don't know where this will be hoisted
8753 // until top-level block is fully resolved
8755 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8756 am.SetHasThisAccess ();
8761 protected override Expression DoResolve (ResolveContext ec)
8767 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8769 if (eclass == ExprClass.Unresolved)
8773 if (right_side == EmptyExpression.UnaryAddress)
8774 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8775 else if (right_side == EmptyExpression.OutAccess)
8776 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8778 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8784 public override int GetHashCode()
8786 throw new NotImplementedException ();
8789 public override bool Equals (object obj)
8791 This t = obj as This;
8798 protected override void CloneTo (CloneContext clonectx, Expression t)
8803 public override void SetHasAddressTaken ()
8808 public override object Accept (StructuralVisitor visitor)
8810 return visitor.Visit (this);
8815 /// Represents the `__arglist' construct
8817 public class ArglistAccess : Expression
8819 public ArglistAccess (Location loc)
8824 protected override void CloneTo (CloneContext clonectx, Expression target)
8829 public override bool ContainsEmitWithAwait ()
8834 public override Expression CreateExpressionTree (ResolveContext ec)
8836 throw new NotSupportedException ("ET");
8839 protected override Expression DoResolve (ResolveContext ec)
8841 eclass = ExprClass.Variable;
8842 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8844 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8845 ec.Report.Error (190, loc,
8846 "The __arglist construct is valid only within a variable argument method");
8852 public override void Emit (EmitContext ec)
8854 ec.Emit (OpCodes.Arglist);
8857 public override object Accept (StructuralVisitor visitor)
8859 return visitor.Visit (this);
8864 /// Represents the `__arglist (....)' construct
8866 public class Arglist : Expression
8868 Arguments arguments;
8870 public Arglist (Location loc)
8875 public Arglist (Arguments args, Location l)
8881 public Arguments Arguments {
8887 public MetaType[] ArgumentTypes {
8889 if (arguments == null)
8890 return MetaType.EmptyTypes;
8892 var retval = new MetaType[arguments.Count];
8893 for (int i = 0; i < retval.Length; i++)
8894 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8900 public override bool ContainsEmitWithAwait ()
8902 throw new NotImplementedException ();
8905 public override Expression CreateExpressionTree (ResolveContext ec)
8907 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8911 protected override Expression DoResolve (ResolveContext ec)
8913 eclass = ExprClass.Variable;
8914 type = InternalType.Arglist;
8915 if (arguments != null) {
8916 bool dynamic; // Can be ignored as there is always only 1 overload
8917 arguments.Resolve (ec, out dynamic);
8923 public override void Emit (EmitContext ec)
8925 if (arguments != null)
8926 arguments.Emit (ec);
8929 protected override void CloneTo (CloneContext clonectx, Expression t)
8931 Arglist target = (Arglist) t;
8933 if (arguments != null)
8934 target.arguments = arguments.Clone (clonectx);
8937 public override object Accept (StructuralVisitor visitor)
8939 return visitor.Visit (this);
8943 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8945 FullNamedExpression texpr;
8947 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8954 public FullNamedExpression TypeExpression {
8960 public override bool ContainsEmitWithAwait ()
8965 public void AddressOf (EmitContext ec, AddressOp mode)
8968 ec.Emit (OpCodes.Refanyval, type);
8971 protected override Expression DoResolve (ResolveContext rc)
8973 expr = expr.Resolve (rc);
8974 type = texpr.ResolveAsType (rc);
8975 if (expr == null || type == null)
8978 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8979 eclass = ExprClass.Variable;
8983 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8985 return DoResolve (rc);
8988 public override void Emit (EmitContext ec)
8991 ec.Emit (OpCodes.Refanyval, type);
8992 ec.EmitLoadFromPtr (type);
8995 public void Emit (EmitContext ec, bool leave_copy)
8997 throw new NotImplementedException ();
9000 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9003 ec.Emit (OpCodes.Refanyval, type);
9006 LocalTemporary temporary = null;
9008 ec.Emit (OpCodes.Dup);
9009 temporary = new LocalTemporary (source.Type);
9010 temporary.Store (ec);
9013 ec.EmitStoreFromPtr (type);
9015 if (temporary != null) {
9016 temporary.Emit (ec);
9017 temporary.Release (ec);
9021 public override object Accept (StructuralVisitor visitor)
9023 return visitor.Visit (this);
9027 public class RefTypeExpr : ShimExpression
9029 public RefTypeExpr (Expression expr, Location loc)
9035 protected override Expression DoResolve (ResolveContext rc)
9037 expr = expr.Resolve (rc);
9041 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9045 type = rc.BuiltinTypes.Type;
9046 eclass = ExprClass.Value;
9050 public override void Emit (EmitContext ec)
9053 ec.Emit (OpCodes.Refanytype);
9054 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9056 ec.Emit (OpCodes.Call, m);
9059 public override object Accept (StructuralVisitor visitor)
9061 return visitor.Visit (this);
9065 public class MakeRefExpr : ShimExpression
9067 public MakeRefExpr (Expression expr, Location loc)
9073 public override bool ContainsEmitWithAwait ()
9075 throw new NotImplementedException ();
9078 protected override Expression DoResolve (ResolveContext rc)
9080 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9081 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9082 eclass = ExprClass.Value;
9086 public override void Emit (EmitContext ec)
9088 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9089 ec.Emit (OpCodes.Mkrefany, expr.Type);
9092 public override object Accept (StructuralVisitor visitor)
9094 return visitor.Visit (this);
9099 /// Implements the typeof operator
9101 public class TypeOf : Expression {
9102 FullNamedExpression QueriedType;
9105 public TypeOf (FullNamedExpression queried_type, Location l)
9107 QueriedType = queried_type;
9112 // Use this constructor for any compiler generated typeof expression
9114 public TypeOf (TypeSpec type, Location loc)
9116 this.typearg = type;
9122 public override bool IsSideEffectFree {
9128 public TypeSpec TypeArgument {
9134 public FullNamedExpression TypeExpression {
9143 protected override void CloneTo (CloneContext clonectx, Expression t)
9145 TypeOf target = (TypeOf) t;
9146 if (QueriedType != null)
9147 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9150 public override bool ContainsEmitWithAwait ()
9155 public override Expression CreateExpressionTree (ResolveContext ec)
9157 Arguments args = new Arguments (2);
9158 args.Add (new Argument (this));
9159 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9160 return CreateExpressionFactoryCall (ec, "Constant", args);
9163 protected override Expression DoResolve (ResolveContext ec)
9165 if (eclass != ExprClass.Unresolved)
9168 if (typearg == null) {
9170 // Pointer types are allowed without explicit unsafe, they are just tokens
9172 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9173 typearg = QueriedType.ResolveAsType (ec, true);
9176 if (typearg == null)
9179 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9180 ec.Report.Error (1962, QueriedType.Location,
9181 "The typeof operator cannot be used on the dynamic type");
9185 type = ec.BuiltinTypes.Type;
9187 // Even though what is returned is a type object, it's treated as a value by the compiler.
9188 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9189 eclass = ExprClass.Value;
9193 static bool ContainsDynamicType (TypeSpec type)
9195 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9198 var element_container = type as ElementTypeSpec;
9199 if (element_container != null)
9200 return ContainsDynamicType (element_container.Element);
9202 foreach (var t in type.TypeArguments) {
9203 if (ContainsDynamicType (t)) {
9211 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9213 // Target type is not System.Type therefore must be object
9214 // and we need to use different encoding sequence
9215 if (targetType != type)
9218 if (typearg is InflatedTypeSpec) {
9221 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9222 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9223 typearg.GetSignatureForError ());
9227 gt = gt.DeclaringType;
9228 } while (gt != null);
9231 if (ContainsDynamicType (typearg)) {
9232 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9236 enc.EncodeTypeName (typearg);
9239 public override void Emit (EmitContext ec)
9241 ec.Emit (OpCodes.Ldtoken, typearg);
9242 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9244 ec.Emit (OpCodes.Call, m);
9247 public override object Accept (StructuralVisitor visitor)
9249 return visitor.Visit (this);
9253 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9255 public TypeOfMethod (MethodSpec method, Location loc)
9256 : base (method, loc)
9260 protected override Expression DoResolve (ResolveContext ec)
9262 if (member.IsConstructor) {
9263 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9265 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9271 return base.DoResolve (ec);
9274 public override void Emit (EmitContext ec)
9276 ec.Emit (OpCodes.Ldtoken, member);
9279 ec.Emit (OpCodes.Castclass, type);
9282 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9284 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9287 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9289 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9293 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9295 protected readonly T member;
9297 protected TypeOfMember (T member, Location loc)
9299 this.member = member;
9303 public override bool IsSideEffectFree {
9309 public override bool ContainsEmitWithAwait ()
9314 public override Expression CreateExpressionTree (ResolveContext ec)
9316 Arguments args = new Arguments (2);
9317 args.Add (new Argument (this));
9318 args.Add (new Argument (new TypeOf (type, loc)));
9319 return CreateExpressionFactoryCall (ec, "Constant", args);
9322 protected override Expression DoResolve (ResolveContext ec)
9324 eclass = ExprClass.Value;
9328 public override void Emit (EmitContext ec)
9330 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9331 PredefinedMember<MethodSpec> p;
9333 p = GetTypeFromHandleGeneric (ec);
9334 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9336 p = GetTypeFromHandle (ec);
9339 var mi = p.Resolve (loc);
9341 ec.Emit (OpCodes.Call, mi);
9344 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9345 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9348 sealed class TypeOfField : TypeOfMember<FieldSpec>
9350 public TypeOfField (FieldSpec field, Location loc)
9355 protected override Expression DoResolve (ResolveContext ec)
9357 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9361 return base.DoResolve (ec);
9364 public override void Emit (EmitContext ec)
9366 ec.Emit (OpCodes.Ldtoken, member);
9370 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9372 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9375 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9377 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9382 /// Implements the sizeof expression
9384 public class SizeOf : Expression {
9385 readonly Expression texpr;
9386 TypeSpec type_queried;
9388 public SizeOf (Expression queried_type, Location l)
9390 this.texpr = queried_type;
9394 public override bool IsSideEffectFree {
9400 public Expression TypeExpression {
9406 public override bool ContainsEmitWithAwait ()
9411 public override Expression CreateExpressionTree (ResolveContext ec)
9413 Error_PointerInsideExpressionTree (ec);
9417 protected override Expression DoResolve (ResolveContext ec)
9419 type_queried = texpr.ResolveAsType (ec);
9420 if (type_queried == null)
9423 if (type_queried.IsEnum)
9424 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9426 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9428 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9431 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9436 ec.Report.Error (233, loc,
9437 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9438 type_queried.GetSignatureForError ());
9441 type = ec.BuiltinTypes.Int;
9442 eclass = ExprClass.Value;
9446 public override void Emit (EmitContext ec)
9448 ec.Emit (OpCodes.Sizeof, type_queried);
9451 protected override void CloneTo (CloneContext clonectx, Expression t)
9455 public override object Accept (StructuralVisitor visitor)
9457 return visitor.Visit (this);
9462 /// Implements the qualified-alias-member (::) expression.
9464 public class QualifiedAliasMember : MemberAccess
9466 readonly string alias;
9467 public static readonly string GlobalAlias = "global";
9469 public QualifiedAliasMember (string alias, string identifier, Location l)
9470 : base (null, identifier, l)
9475 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9476 : base (null, identifier, targs, l)
9481 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9482 : base (null, identifier, arity, l)
9487 public string Alias {
9493 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9495 if (alias == GlobalAlias)
9496 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9498 int errors = mc.Module.Compiler.Report.Errors;
9499 var expr = mc.LookupNamespaceAlias (alias);
9501 if (errors == mc.Module.Compiler.Report.Errors)
9502 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9510 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9512 expr = CreateExpressionFromAlias (mc);
9516 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9519 protected override Expression DoResolve (ResolveContext rc)
9521 return ResolveAsTypeOrNamespace (rc, false);
9524 public override string GetSignatureForError ()
9527 if (targs != null) {
9528 name = Name + "<" + targs.GetSignatureForError () + ">";
9531 return alias + "::" + name;
9534 public override bool HasConditionalAccess ()
9539 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9541 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9542 rc.Module.Compiler.Report.Error (687, loc,
9543 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9544 GetSignatureForError ());
9549 return DoResolve (rc);
9552 protected override void CloneTo (CloneContext clonectx, Expression t)
9557 public override object Accept (StructuralVisitor visitor)
9559 return visitor.Visit (this);
9564 /// Implements the member access expression
9566 public class MemberAccess : ATypeNameExpression
9568 protected Expression expr;
9570 public MemberAccess (Expression expr, string id)
9571 : base (id, expr.Location)
9576 public MemberAccess (Expression expr, string identifier, Location loc)
9577 : base (identifier, loc)
9582 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9583 : base (identifier, args, loc)
9588 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9589 : base (identifier, arity, loc)
9594 public Expression LeftExpression {
9600 public override Location StartLocation {
9602 return expr == null ? loc : expr.StartLocation;
9606 protected override Expression DoResolve (ResolveContext rc)
9608 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
9610 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9615 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9617 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9619 if (e is TypeExpr) {
9620 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9625 e = e.ResolveLValue (rc, rhs);
9630 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9632 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9633 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9635 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9638 public override bool HasConditionalAccess ()
9640 return LeftExpression.HasConditionalAccess ();
9643 public static bool IsValidDotExpression (TypeSpec type)
9645 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9646 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9648 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9651 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9653 var sn = expr as SimpleName;
9654 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9657 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9660 // Resolve expression which does have type set as we need expression type
9661 // with disable flow analysis as we don't know whether left side expression
9662 // is used as variable or type
9664 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9665 expr = expr.Resolve (rc);
9666 } else if (expr is TypeParameterExpr) {
9667 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9671 bool resolved = false;
9672 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
9673 if (expr.HasConditionalAccess ()) {
9675 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
9676 expr = expr.Resolve (rc, flags);
9682 expr = expr.Resolve (rc, flags);
9688 var ns = expr as NamespaceExpression;
9690 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9692 if (retval == null) {
9693 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9698 if (HasTypeArguments)
9699 return new GenericTypeExpr (retval.Type, targs, loc);
9701 targs.Resolve (rc, false);
9708 TypeSpec expr_type = expr.Type;
9709 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9710 me = expr as MemberExpr;
9712 me.ResolveInstanceExpression (rc, null);
9714 Arguments args = new Arguments (1);
9715 args.Add (new Argument (expr));
9716 return new DynamicMemberBinder (Name, args, loc);
9719 var cma = this as ConditionalMemberAccess;
9721 if (!IsNullPropagatingValid (expr.Type)) {
9722 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9726 if (expr_type.IsNullableType) {
9727 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9728 expr_type = expr.Type;
9732 if (!IsValidDotExpression (expr_type)) {
9733 Error_OperatorCannotBeApplied (rc, expr_type);
9737 var lookup_arity = Arity;
9738 bool errorMode = false;
9739 Expression member_lookup;
9741 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9742 if (member_lookup == null) {
9744 // Try to look for extension method when member lookup failed
9746 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9747 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9748 if (methods != null) {
9749 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9750 if (HasTypeArguments) {
9751 if (!targs.Resolve (rc, false))
9754 emg.SetTypeArguments (rc, targs);
9758 emg.ConditionalAccess = true;
9760 // TODO: it should really skip the checks bellow
9761 return emg.Resolve (rc);
9767 if (member_lookup == null) {
9768 var dep = expr_type.GetMissingDependencies ();
9770 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9771 } else if (expr is TypeExpr) {
9772 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9774 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9780 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9781 // Leave it to overload resolution to report correct error
9782 } else if (!(member_lookup is TypeExpr)) {
9783 // TODO: rc.SymbolRelatedToPreviousError
9784 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9789 if (member_lookup != null)
9793 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9797 TypeExpr texpr = member_lookup as TypeExpr;
9798 if (texpr != null) {
9799 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9800 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9801 Name, texpr.GetSignatureForError ());
9804 if (!texpr.Type.IsAccessible (rc)) {
9805 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9806 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9810 if (HasTypeArguments) {
9811 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9814 return member_lookup;
9817 me = member_lookup as MemberExpr;
9819 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9824 me.ConditionalAccess = true;
9827 me = me.ResolveMemberAccess (rc, expr, sn);
9830 if (!targs.Resolve (rc, false))
9833 me.SetTypeArguments (rc, targs);
9839 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9841 FullNamedExpression fexpr = expr as FullNamedExpression;
9842 if (fexpr == null) {
9843 expr.ResolveAsType (rc);
9847 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9849 if (expr_resolved == null)
9852 var ns = expr_resolved as NamespaceExpression;
9854 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9856 if (retval == null) {
9857 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9858 } else if (Arity > 0) {
9859 if (HasTypeArguments) {
9860 retval = new GenericTypeExpr (retval.Type, targs, loc);
9861 if (retval.ResolveAsType (rc) == null)
9864 targs.Resolve (rc, allowUnboundTypeArguments);
9866 retval = new GenericOpenTypeExpr (retval.Type, loc);
9873 var tnew_expr = expr_resolved.ResolveAsType (rc);
9874 if (tnew_expr == null)
9877 TypeSpec expr_type = tnew_expr;
9878 if (TypeManager.IsGenericParameter (expr_type)) {
9879 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9880 tnew_expr.GetSignatureForError ());
9884 var qam = this as QualifiedAliasMember;
9886 rc.Module.Compiler.Report.Error (431, loc,
9887 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9892 TypeSpec nested = null;
9893 while (expr_type != null) {
9894 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9895 if (nested == null) {
9896 if (expr_type == tnew_expr) {
9897 Error_IdentifierNotFound (rc, expr_type);
9901 expr_type = tnew_expr;
9902 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9903 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9907 if (nested.IsAccessible (rc))
9911 // Keep looking after inaccessible candidate but only if
9912 // we are not in same context as the definition itself
9914 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9917 expr_type = expr_type.BaseType;
9922 if (HasTypeArguments) {
9923 texpr = new GenericTypeExpr (nested, targs, loc);
9925 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9927 texpr = new GenericOpenTypeExpr (nested, loc);
9929 } else if (expr_resolved is GenericOpenTypeExpr) {
9930 texpr = new GenericOpenTypeExpr (nested, loc);
9932 texpr = new TypeExpression (nested, loc);
9935 if (texpr.ResolveAsType (rc) == null)
9941 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9943 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9945 if (nested != null) {
9946 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9950 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9951 if (any_other_member != null) {
9952 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9956 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9957 Name, expr_type.GetSignatureForError ());
9960 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9962 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9965 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9967 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9968 ec.Report.SymbolRelatedToPreviousError (type);
9970 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9972 // a using directive or an assembly reference
9974 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9976 missing = "an assembly reference";
9979 ec.Report.Error (1061, loc,
9980 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9981 type.GetSignatureForError (), name, missing);
9985 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9988 public override string GetSignatureForError ()
9990 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9993 protected override void CloneTo (CloneContext clonectx, Expression t)
9995 MemberAccess target = (MemberAccess) t;
9997 target.expr = expr.Clone (clonectx);
10000 public override object Accept (StructuralVisitor visitor)
10002 return visitor.Visit (this);
10006 public class ConditionalMemberAccess : MemberAccess
10008 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10009 : base (expr, identifier, args, loc)
10013 public override bool HasConditionalAccess ()
10020 /// Implements checked expressions
10022 public class CheckedExpr : Expression {
10024 public Expression Expr;
10026 public CheckedExpr (Expression e, Location l)
10032 public override bool ContainsEmitWithAwait ()
10034 return Expr.ContainsEmitWithAwait ();
10037 public override Expression CreateExpressionTree (ResolveContext ec)
10039 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10040 return Expr.CreateExpressionTree (ec);
10043 protected override Expression DoResolve (ResolveContext ec)
10045 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10046 Expr = Expr.Resolve (ec);
10051 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10054 eclass = Expr.eclass;
10059 public override void Emit (EmitContext ec)
10061 using (ec.With (EmitContext.Options.CheckedScope, true))
10065 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10067 using (ec.With (EmitContext.Options.CheckedScope, true))
10068 Expr.EmitBranchable (ec, target, on_true);
10071 public override void FlowAnalysis (FlowAnalysisContext fc)
10073 Expr.FlowAnalysis (fc);
10076 public override SLE.Expression MakeExpression (BuilderContext ctx)
10078 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10079 return Expr.MakeExpression (ctx);
10083 protected override void CloneTo (CloneContext clonectx, Expression t)
10085 CheckedExpr target = (CheckedExpr) t;
10087 target.Expr = Expr.Clone (clonectx);
10090 public override object Accept (StructuralVisitor visitor)
10092 return visitor.Visit (this);
10097 /// Implements the unchecked expression
10099 public class UnCheckedExpr : Expression {
10101 public Expression Expr;
10103 public UnCheckedExpr (Expression e, Location l)
10109 public override bool ContainsEmitWithAwait ()
10111 return Expr.ContainsEmitWithAwait ();
10114 public override Expression CreateExpressionTree (ResolveContext ec)
10116 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10117 return Expr.CreateExpressionTree (ec);
10120 protected override Expression DoResolve (ResolveContext ec)
10122 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10123 Expr = Expr.Resolve (ec);
10128 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10131 eclass = Expr.eclass;
10136 public override void Emit (EmitContext ec)
10138 using (ec.With (EmitContext.Options.CheckedScope, false))
10142 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10144 using (ec.With (EmitContext.Options.CheckedScope, false))
10145 Expr.EmitBranchable (ec, target, on_true);
10148 public override void FlowAnalysis (FlowAnalysisContext fc)
10150 Expr.FlowAnalysis (fc);
10153 protected override void CloneTo (CloneContext clonectx, Expression t)
10155 UnCheckedExpr target = (UnCheckedExpr) t;
10157 target.Expr = Expr.Clone (clonectx);
10160 public override object Accept (StructuralVisitor visitor)
10162 return visitor.Visit (this);
10167 /// An Element Access expression.
10169 /// During semantic analysis these are transformed into
10170 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10172 public class ElementAccess : Expression
10174 public Arguments Arguments;
10175 public Expression Expr;
10177 public ElementAccess (Expression e, Arguments args, Location loc)
10181 this.Arguments = args;
10184 public bool ConditionalAccess { get; set; }
10186 public override Location StartLocation {
10188 return Expr.StartLocation;
10192 public override bool ContainsEmitWithAwait ()
10194 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10198 // We perform some simple tests, and then to "split" the emit and store
10199 // code we create an instance of a different class, and return that.
10201 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10203 Expr = Expr.Resolve (ec);
10209 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10210 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10215 return new ArrayAccess (this, loc) {
10216 ConditionalAccess = ConditionalAccess,
10217 ConditionalAccessReceiver = conditionalAccessReceiver
10220 if (type.IsPointer)
10221 return Expr.MakePointerAccess (ec, type, Arguments);
10223 FieldExpr fe = Expr as FieldExpr;
10225 var ff = fe.Spec as FixedFieldSpec;
10227 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10231 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10232 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10233 var indexer = new IndexerExpr (indexers, type, this) {
10234 ConditionalAccess = ConditionalAccess
10237 if (conditionalAccessReceiver)
10238 indexer.SetConditionalAccessReceiver ();
10243 Error_CannotApplyIndexing (ec, type, loc);
10248 public override Expression CreateExpressionTree (ResolveContext ec)
10250 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10251 Expr.CreateExpressionTree (ec));
10253 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10256 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10258 if (type != InternalType.ErrorType) {
10259 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10260 type.GetSignatureForError ());
10264 public override bool HasConditionalAccess ()
10266 return ConditionalAccess || Expr.HasConditionalAccess ();
10269 protected override Expression DoResolve (ResolveContext rc)
10272 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
10273 if (HasConditionalAccess ()) {
10274 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
10275 expr = CreateAccessExpression (rc, true);
10279 return expr.Resolve (rc);
10284 expr = CreateAccessExpression (rc, false);
10288 return expr.Resolve (rc);
10291 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10293 var res = CreateAccessExpression (ec, false);
10297 return res.ResolveLValue (ec, rhs);
10300 public override void Emit (EmitContext ec)
10302 throw new Exception ("Should never be reached");
10305 public override void FlowAnalysis (FlowAnalysisContext fc)
10307 Expr.FlowAnalysis (fc);
10309 if (ConditionalAccess)
10310 fc.BranchConditionalAccessDefiniteAssignment ();
10312 Arguments.FlowAnalysis (fc);
10315 public override string GetSignatureForError ()
10317 return Expr.GetSignatureForError ();
10320 protected override void CloneTo (CloneContext clonectx, Expression t)
10322 ElementAccess target = (ElementAccess) t;
10324 target.Expr = Expr.Clone (clonectx);
10325 if (Arguments != null)
10326 target.Arguments = Arguments.Clone (clonectx);
10329 public override object Accept (StructuralVisitor visitor)
10331 return visitor.Visit (this);
10336 /// Implements array access
10338 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10340 // Points to our "data" repository
10344 LocalTemporary temp;
10346 bool? has_await_args;
10348 public ArrayAccess (ElementAccess ea_data, Location l)
10354 public bool ConditionalAccess { get; set; }
10356 public bool ConditionalAccessReceiver { get; set; }
10358 public void AddressOf (EmitContext ec, AddressOp mode)
10360 var ac = (ArrayContainer) ea.Expr.Type;
10362 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10363 LoadInstanceAndArguments (ec, false, true);
10366 LoadInstanceAndArguments (ec, false, false);
10368 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10369 ec.Emit (OpCodes.Readonly);
10371 ec.EmitArrayAddress (ac);
10374 public override Expression CreateExpressionTree (ResolveContext ec)
10376 if (ConditionalAccess)
10377 Error_NullShortCircuitInsideExpressionTree (ec);
10379 return ea.CreateExpressionTree (ec);
10382 public override bool ContainsEmitWithAwait ()
10384 return ea.ContainsEmitWithAwait ();
10387 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10389 if (HasConditionalAccess ())
10390 Error_NullPropagatingLValue (ec);
10392 return DoResolve (ec);
10395 protected override Expression DoResolve (ResolveContext ec)
10397 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10399 ea.Arguments.Resolve (ec, out dynamic);
10401 var ac = ea.Expr.Type as ArrayContainer;
10402 int rank = ea.Arguments.Count;
10403 if (ac.Rank != rank) {
10404 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10405 rank.ToString (), ac.Rank.ToString ());
10410 if (type.IsPointer && !ec.IsUnsafe) {
10411 UnsafeError (ec, ea.Location);
10414 if (ConditionalAccessReceiver)
10415 type = LiftMemberType (ec, type);
10417 foreach (Argument a in ea.Arguments) {
10418 var na = a as NamedArgument;
10420 ElementAccess.Error_NamedArgument (na, ec.Report);
10422 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10425 eclass = ExprClass.Variable;
10430 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10432 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10435 public override void FlowAnalysis (FlowAnalysisContext fc)
10437 ea.FlowAnalysis (fc);
10440 public override bool HasConditionalAccess ()
10442 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10446 // Load the array arguments into the stack.
10448 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10450 if (prepareAwait) {
10451 ea.Expr = ea.Expr.EmitToField (ec);
10453 var ie = new InstanceEmitter (ea.Expr, false);
10454 ie.Emit (ec, ConditionalAccess);
10456 if (duplicateArguments) {
10457 ec.Emit (OpCodes.Dup);
10459 var copy = new LocalTemporary (ea.Expr.Type);
10465 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10466 if (dup_args != null)
10467 ea.Arguments = dup_args;
10470 public void Emit (EmitContext ec, bool leave_copy)
10473 ec.EmitLoadFromPtr (type);
10475 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10476 LoadInstanceAndArguments (ec, false, true);
10479 if (ConditionalAccessReceiver)
10480 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10482 var ac = (ArrayContainer) ea.Expr.Type;
10483 LoadInstanceAndArguments (ec, false, false);
10484 ec.EmitArrayLoad (ac);
10486 if (ConditionalAccessReceiver)
10487 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10491 ec.Emit (OpCodes.Dup);
10492 temp = new LocalTemporary (this.type);
10497 public override void Emit (EmitContext ec)
10502 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10504 var ac = (ArrayContainer) ea.Expr.Type;
10505 TypeSpec t = source.Type;
10507 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10510 // When we are dealing with a struct, get the address of it to avoid value copy
10511 // Same cannot be done for reference type because array covariance and the
10512 // check in ldelema requires to specify the type of array element stored at the index
10514 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10515 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10517 if (has_await_args.Value) {
10518 if (source.ContainsEmitWithAwait ()) {
10519 source = source.EmitToField (ec);
10520 isCompound = false;
10524 LoadInstanceAndArguments (ec, isCompound, false);
10529 ec.EmitArrayAddress (ac);
10532 ec.Emit (OpCodes.Dup);
10536 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10538 if (has_await_args.Value) {
10539 if (source.ContainsEmitWithAwait ())
10540 source = source.EmitToField (ec);
10542 LoadInstanceAndArguments (ec, false, false);
10549 var lt = ea.Expr as LocalTemporary;
10555 ec.Emit (OpCodes.Dup);
10556 temp = new LocalTemporary (this.type);
10561 ec.EmitStoreFromPtr (t);
10563 ec.EmitArrayStore (ac);
10566 if (temp != null) {
10572 public override Expression EmitToField (EmitContext ec)
10575 // Have to be specialized for arrays to get access to
10576 // underlying element. Instead of another result copy we
10577 // need direct access to element
10581 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10583 ea.Expr = ea.Expr.EmitToField (ec);
10584 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10588 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10590 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10593 public override SLE.Expression MakeExpression (BuilderContext ctx)
10595 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10598 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10600 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10601 return Arguments.MakeExpression (ea.Arguments, ctx);
10607 // Indexer access expression
10609 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10611 IList<MemberSpec> indexers;
10612 Arguments arguments;
10613 TypeSpec queried_type;
10615 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10616 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10620 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10623 this.indexers = indexers;
10624 this.queried_type = queriedType;
10625 this.InstanceExpression = instance;
10626 this.arguments = args;
10631 protected override Arguments Arguments {
10640 protected override TypeSpec DeclaringType {
10642 return best_candidate.DeclaringType;
10646 public override bool IsInstance {
10652 public override bool IsStatic {
10658 public override string KindName {
10659 get { return "indexer"; }
10662 public override string Name {
10670 public override bool ContainsEmitWithAwait ()
10672 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10675 public override Expression CreateExpressionTree (ResolveContext ec)
10677 if (ConditionalAccess) {
10678 Error_NullShortCircuitInsideExpressionTree (ec);
10681 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10682 InstanceExpression.CreateExpressionTree (ec),
10683 new TypeOfMethod (Getter, loc));
10685 return CreateExpressionFactoryCall (ec, "Call", args);
10688 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10690 LocalTemporary await_source_arg = null;
10693 emitting_compound_assignment = true;
10694 if (source is DynamicExpressionStatement) {
10699 emitting_compound_assignment = false;
10701 if (has_await_arguments) {
10702 await_source_arg = new LocalTemporary (Type);
10703 await_source_arg.Store (ec);
10705 arguments.Add (new Argument (await_source_arg));
10708 temp = await_source_arg;
10711 has_await_arguments = false;
10716 ec.Emit (OpCodes.Dup);
10717 temp = new LocalTemporary (Type);
10723 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10724 source = source.EmitToField (ec);
10726 temp = new LocalTemporary (Type);
10733 arguments.Add (new Argument (source));
10736 var call = new CallEmitter ();
10737 call.InstanceExpression = InstanceExpression;
10738 if (arguments == null)
10739 call.InstanceExpressionOnStack = true;
10741 call.Emit (ec, Setter, arguments, loc);
10743 if (temp != null) {
10746 } else if (leave_copy) {
10750 if (await_source_arg != null) {
10751 await_source_arg.Release (ec);
10755 public override void FlowAnalysis (FlowAnalysisContext fc)
10757 base.FlowAnalysis (fc);
10758 arguments.FlowAnalysis (fc);
10760 if (conditional_access_receiver)
10761 fc.ConditionalAccessEnd ();
10764 public override string GetSignatureForError ()
10766 return best_candidate.GetSignatureForError ();
10769 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10772 throw new NotSupportedException ();
10774 var value = new[] { source.MakeExpression (ctx) };
10775 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10776 #if NET_4_0 || MOBILE_DYNAMIC
10777 return SLE.Expression.Block (
10778 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10781 return args.First ();
10786 public override SLE.Expression MakeExpression (BuilderContext ctx)
10789 return base.MakeExpression (ctx);
10791 var args = Arguments.MakeExpression (arguments, ctx);
10792 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10796 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10798 if (best_candidate != null)
10801 eclass = ExprClass.IndexerAccess;
10804 arguments.Resolve (rc, out dynamic);
10806 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10809 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10810 res.BaseMembersProvider = this;
10811 res.InstanceQualifier = this;
10813 // TODO: Do I need 2 argument sets?
10814 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10815 if (best_candidate != null)
10816 type = res.BestCandidateReturnType;
10817 else if (!res.BestCandidateIsDynamic)
10822 // It has dynamic arguments
10825 Arguments args = new Arguments (arguments.Count + 1);
10827 rc.Report.Error (1972, loc,
10828 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10830 args.Add (new Argument (InstanceExpression));
10832 args.AddRange (arguments);
10834 best_candidate = null;
10835 return new DynamicIndexBinder (args, loc);
10839 // Try to avoid resolving left expression again
10841 if (right_side != null)
10842 ResolveInstanceExpression (rc, right_side);
10847 protected override void CloneTo (CloneContext clonectx, Expression t)
10849 IndexerExpr target = (IndexerExpr) t;
10851 if (arguments != null)
10852 target.arguments = arguments.Clone (clonectx);
10855 public void SetConditionalAccessReceiver ()
10857 conditional_access_receiver = true;
10860 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10862 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10865 #region IBaseMembersProvider Members
10867 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10869 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10872 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10874 if (queried_type == member.DeclaringType)
10877 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10878 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10881 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10890 // A base access expression
10892 public class BaseThis : This
10894 public BaseThis (Location loc)
10899 public BaseThis (TypeSpec type, Location loc)
10903 eclass = ExprClass.Variable;
10908 public override string Name {
10916 public override Expression CreateExpressionTree (ResolveContext ec)
10918 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10919 return base.CreateExpressionTree (ec);
10922 public override void Emit (EmitContext ec)
10926 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10927 var context_type = ec.CurrentType;
10928 ec.Emit (OpCodes.Ldobj, context_type);
10929 ec.Emit (OpCodes.Box, context_type);
10933 protected override void Error_ThisNotAvailable (ResolveContext ec)
10936 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10938 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10942 public override void ResolveBase (ResolveContext ec)
10944 base.ResolveBase (ec);
10945 type = ec.CurrentType.BaseType;
10948 public override object Accept (StructuralVisitor visitor)
10950 return visitor.Visit (this);
10955 /// This class exists solely to pass the Type around and to be a dummy
10956 /// that can be passed to the conversion functions (this is used by
10957 /// foreach implementation to typecast the object return value from
10958 /// get_Current into the proper type. All code has been generated and
10959 /// we only care about the side effect conversions to be performed
10961 /// This is also now used as a placeholder where a no-action expression
10962 /// is needed (the `New' class).
10964 public class EmptyExpression : Expression
10966 sealed class OutAccessExpression : EmptyExpression
10968 public OutAccessExpression (TypeSpec t)
10973 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10975 rc.Report.Error (206, right_side.Location,
10976 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
10982 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
10983 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
10984 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
10985 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
10986 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
10987 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
10988 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
10989 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
10991 public EmptyExpression (TypeSpec t)
10994 eclass = ExprClass.Value;
10995 loc = Location.Null;
10998 protected override void CloneTo (CloneContext clonectx, Expression target)
11002 public override bool ContainsEmitWithAwait ()
11007 public override Expression CreateExpressionTree (ResolveContext ec)
11009 throw new NotSupportedException ("ET");
11012 protected override Expression DoResolve (ResolveContext ec)
11017 public override void Emit (EmitContext ec)
11019 // nothing, as we only exist to not do anything.
11022 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11026 public override void EmitSideEffect (EmitContext ec)
11030 public override object Accept (StructuralVisitor visitor)
11032 return visitor.Visit (this);
11036 sealed class EmptyAwaitExpression : EmptyExpression
11038 public EmptyAwaitExpression (TypeSpec type)
11043 public override bool ContainsEmitWithAwait ()
11050 // Empty statement expression
11052 public sealed class EmptyExpressionStatement : ExpressionStatement
11054 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11056 private EmptyExpressionStatement ()
11058 loc = Location.Null;
11061 public override bool ContainsEmitWithAwait ()
11066 public override Expression CreateExpressionTree (ResolveContext ec)
11071 public override void EmitStatement (EmitContext ec)
11076 protected override Expression DoResolve (ResolveContext ec)
11078 eclass = ExprClass.Value;
11079 type = ec.BuiltinTypes.Object;
11083 public override void Emit (EmitContext ec)
11088 public override object Accept (StructuralVisitor visitor)
11090 return visitor.Visit (this);
11094 public class ErrorExpression : EmptyExpression
11096 public static readonly ErrorExpression Instance = new ErrorExpression ();
11098 private ErrorExpression ()
11099 : base (InternalType.ErrorType)
11103 public override Expression CreateExpressionTree (ResolveContext ec)
11108 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11113 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11117 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11121 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11125 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11129 public override object Accept (StructuralVisitor visitor)
11131 return visitor.Visit (this);
11135 public class UserCast : Expression {
11139 public UserCast (MethodSpec method, Expression source, Location l)
11141 if (source == null)
11142 throw new ArgumentNullException ("source");
11144 this.method = method;
11145 this.source = source;
11146 type = method.ReturnType;
11150 public Expression Source {
11159 public override bool ContainsEmitWithAwait ()
11161 return source.ContainsEmitWithAwait ();
11164 public override Expression CreateExpressionTree (ResolveContext ec)
11166 Arguments args = new Arguments (3);
11167 args.Add (new Argument (source.CreateExpressionTree (ec)));
11168 args.Add (new Argument (new TypeOf (type, loc)));
11169 args.Add (new Argument (new TypeOfMethod (method, loc)));
11170 return CreateExpressionFactoryCall (ec, "Convert", args);
11173 protected override Expression DoResolve (ResolveContext ec)
11175 ObsoleteAttribute oa = method.GetAttributeObsolete ();
11177 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
11179 eclass = ExprClass.Value;
11183 public override void Emit (EmitContext ec)
11186 ec.MarkCallEntry (loc);
11187 ec.Emit (OpCodes.Call, method);
11190 public override void FlowAnalysis (FlowAnalysisContext fc)
11192 source.FlowAnalysis (fc);
11195 public override string GetSignatureForError ()
11197 return TypeManager.CSharpSignature (method);
11200 public override SLE.Expression MakeExpression (BuilderContext ctx)
11203 return base.MakeExpression (ctx);
11205 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11211 // Holds additional type specifiers like ?, *, []
11213 public class ComposedTypeSpecifier
11215 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11217 public readonly int Dimension;
11218 public readonly Location Location;
11220 public ComposedTypeSpecifier (int specifier, Location loc)
11222 this.Dimension = specifier;
11223 this.Location = loc;
11227 public bool IsNullable {
11229 return Dimension == -1;
11233 public bool IsPointer {
11235 return Dimension == -2;
11239 public ComposedTypeSpecifier Next { get; set; }
11243 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11245 return new ComposedTypeSpecifier (dimension, loc);
11248 public static ComposedTypeSpecifier CreateNullable (Location loc)
11250 return new ComposedTypeSpecifier (-1, loc);
11253 public static ComposedTypeSpecifier CreatePointer (Location loc)
11255 return new ComposedTypeSpecifier (-2, loc);
11258 public string GetSignatureForError ()
11263 ArrayContainer.GetPostfixSignature (Dimension);
11265 return Next != null ? s + Next.GetSignatureForError () : s;
11270 // This class is used to "construct" the type during a typecast
11271 // operation. Since the Type.GetType class in .NET can parse
11272 // the type specification, we just use this to construct the type
11273 // one bit at a time.
11275 public class ComposedCast : TypeExpr {
11276 FullNamedExpression left;
11277 ComposedTypeSpecifier spec;
11279 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11282 throw new ArgumentNullException ("spec");
11286 this.loc = left.Location;
11289 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11291 type = left.ResolveAsType (ec);
11295 eclass = ExprClass.Type;
11297 var single_spec = spec;
11299 if (single_spec.IsNullable) {
11300 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11304 single_spec = single_spec.Next;
11305 } else if (single_spec.IsPointer) {
11306 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11309 if (!ec.IsUnsafe) {
11310 UnsafeError (ec.Module.Compiler.Report, loc);
11314 type = PointerContainer.MakeType (ec.Module, type);
11315 single_spec = single_spec.Next;
11316 } while (single_spec != null && single_spec.IsPointer);
11319 if (single_spec != null && single_spec.Dimension > 0) {
11320 if (type.IsSpecialRuntimeType) {
11321 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11322 } else if (type.IsStatic) {
11323 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11324 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11325 type.GetSignatureForError ());
11327 MakeArray (ec.Module, single_spec);
11334 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11336 if (spec.Next != null)
11337 MakeArray (module, spec.Next);
11339 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11342 public override string GetSignatureForError ()
11344 return left.GetSignatureForError () + spec.GetSignatureForError ();
11347 public override object Accept (StructuralVisitor visitor)
11349 return visitor.Visit (this);
11353 class FixedBufferPtr : Expression
11355 readonly Expression array;
11357 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11359 this.type = array_type;
11360 this.array = array;
11364 public override bool ContainsEmitWithAwait ()
11366 throw new NotImplementedException ();
11369 public override Expression CreateExpressionTree (ResolveContext ec)
11371 Error_PointerInsideExpressionTree (ec);
11375 public override void Emit(EmitContext ec)
11380 protected override Expression DoResolve (ResolveContext ec)
11382 type = PointerContainer.MakeType (ec.Module, type);
11383 eclass = ExprClass.Value;
11390 // This class is used to represent the address of an array, used
11391 // only by the Fixed statement, this generates "&a [0]" construct
11392 // for fixed (char *pa = a)
11394 class ArrayPtr : FixedBufferPtr
11396 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11397 base (array, array_type, l)
11401 public override void Emit (EmitContext ec)
11406 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11411 // Encapsulates a conversion rules required for array indexes
11413 public class ArrayIndexCast : TypeCast
11415 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11416 : base (expr, returnType)
11418 if (expr.Type == returnType) // int -> int
11419 throw new ArgumentException ("unnecessary array index conversion");
11422 public override Expression CreateExpressionTree (ResolveContext ec)
11424 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11425 return base.CreateExpressionTree (ec);
11429 public override void Emit (EmitContext ec)
11433 switch (child.Type.BuiltinType) {
11434 case BuiltinTypeSpec.Type.UInt:
11435 ec.Emit (OpCodes.Conv_U);
11437 case BuiltinTypeSpec.Type.Long:
11438 ec.Emit (OpCodes.Conv_Ovf_I);
11440 case BuiltinTypeSpec.Type.ULong:
11441 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11444 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11450 // Implements the `stackalloc' keyword
11452 public class StackAlloc : Expression {
11457 public StackAlloc (Expression type, Expression count, Location l)
11460 this.count = count;
11464 public Expression TypeExpression {
11470 public Expression CountExpression {
11476 public override bool ContainsEmitWithAwait ()
11481 public override Expression CreateExpressionTree (ResolveContext ec)
11483 throw new NotSupportedException ("ET");
11486 protected override Expression DoResolve (ResolveContext ec)
11488 count = count.Resolve (ec);
11492 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11493 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11498 Constant c = count as Constant;
11499 if (c != null && c.IsNegative) {
11500 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11503 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11504 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11507 otype = texpr.ResolveAsType (ec);
11511 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11514 type = PointerContainer.MakeType (ec.Module, otype);
11515 eclass = ExprClass.Value;
11520 public override void Emit (EmitContext ec)
11522 int size = BuiltinTypeSpec.GetSize (otype);
11527 ec.Emit (OpCodes.Sizeof, otype);
11531 ec.Emit (OpCodes.Mul_Ovf_Un);
11532 ec.Emit (OpCodes.Localloc);
11535 protected override void CloneTo (CloneContext clonectx, Expression t)
11537 StackAlloc target = (StackAlloc) t;
11538 target.count = count.Clone (clonectx);
11539 target.texpr = texpr.Clone (clonectx);
11542 public override object Accept (StructuralVisitor visitor)
11544 return visitor.Visit (this);
11549 // An object initializer expression
11551 public class ElementInitializer : Assign
11553 public readonly string Name;
11555 public ElementInitializer (string name, Expression initializer, Location loc)
11556 : base (null, initializer, loc)
11561 public bool IsDictionaryInitializer {
11563 return Name == null;
11567 protected override void CloneTo (CloneContext clonectx, Expression t)
11569 ElementInitializer target = (ElementInitializer) t;
11570 target.source = source.Clone (clonectx);
11573 public override Expression CreateExpressionTree (ResolveContext ec)
11575 Arguments args = new Arguments (2);
11576 FieldExpr fe = target as FieldExpr;
11578 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11580 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11583 Expression arg_expr;
11584 var cinit = source as CollectionOrObjectInitializers;
11585 if (cinit == null) {
11587 arg_expr = source.CreateExpressionTree (ec);
11589 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11590 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11593 args.Add (new Argument (arg_expr));
11594 return CreateExpressionFactoryCall (ec, mname, args);
11597 protected override Expression DoResolve (ResolveContext ec)
11599 if (source == null)
11600 return EmptyExpressionStatement.Instance;
11602 if (!ResolveElement (ec))
11605 if (source is CollectionOrObjectInitializers) {
11606 Expression previous = ec.CurrentInitializerVariable;
11607 ec.CurrentInitializerVariable = target;
11608 source = source.Resolve (ec);
11609 ec.CurrentInitializerVariable = previous;
11610 if (source == null)
11613 eclass = source.eclass;
11614 type = source.Type;
11618 return base.DoResolve (ec);
11621 public override void EmitStatement (EmitContext ec)
11623 if (source is CollectionOrObjectInitializers)
11626 base.EmitStatement (ec);
11629 protected virtual bool ResolveElement (ResolveContext rc)
11631 var t = rc.CurrentInitializerVariable.Type;
11632 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11633 Arguments args = new Arguments (1);
11634 args.Add (new Argument (rc.CurrentInitializerVariable));
11635 target = new DynamicMemberBinder (Name, args, loc);
11638 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11639 if (member == null) {
11640 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11642 if (member != null) {
11643 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11644 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11649 if (member == null) {
11650 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11654 var me = member as MemberExpr;
11655 if (me is EventExpr) {
11656 me = me.ResolveMemberAccess (rc, null, null);
11657 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11658 rc.Report.Error (1913, loc,
11659 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11660 member.GetSignatureForError ());
11666 rc.Report.Error (1914, loc,
11667 "Static field or property `{0}' cannot be assigned in an object initializer",
11668 me.GetSignatureForError ());
11672 me.InstanceExpression = rc.CurrentInitializerVariable;
11680 // A collection initializer expression
11682 class CollectionElementInitializer : Invocation
11684 public class ElementInitializerArgument : Argument
11686 public ElementInitializerArgument (Expression e)
11692 sealed class AddMemberAccess : MemberAccess
11694 public AddMemberAccess (Expression expr, Location loc)
11695 : base (expr, "Add", loc)
11699 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11701 if (TypeManager.HasElementType (type))
11704 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11708 public CollectionElementInitializer (Expression argument)
11709 : base (null, new Arguments (1))
11711 base.arguments.Add (new ElementInitializerArgument (argument));
11712 this.loc = argument.Location;
11715 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11716 : base (null, new Arguments (arguments.Count))
11718 foreach (Expression e in arguments)
11719 base.arguments.Add (new ElementInitializerArgument (e));
11724 public CollectionElementInitializer (Location loc)
11725 : base (null, null)
11730 public override Expression CreateExpressionTree (ResolveContext ec)
11732 Arguments args = new Arguments (2);
11733 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11735 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11736 foreach (Argument a in arguments)
11737 expr_initializers.Add (a.CreateExpressionTree (ec));
11739 args.Add (new Argument (new ArrayCreation (
11740 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11741 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11744 protected override void CloneTo (CloneContext clonectx, Expression t)
11746 CollectionElementInitializer target = (CollectionElementInitializer) t;
11747 if (arguments != null)
11748 target.arguments = arguments.Clone (clonectx);
11751 protected override Expression DoResolve (ResolveContext ec)
11753 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11755 return base.DoResolve (ec);
11759 class DictionaryElementInitializer : ElementInitializer
11761 readonly Arguments args;
11763 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11764 : base (null, initializer, loc)
11766 this.args = arguments;
11769 public override Expression CreateExpressionTree (ResolveContext ec)
11771 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11775 protected override bool ResolveElement (ResolveContext rc)
11777 var init = rc.CurrentInitializerVariable;
11778 var type = init.Type;
11780 if (type.IsArray) {
11781 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11785 if (type.IsPointer) {
11786 target = init.MakePointerAccess (rc, type, args);
11790 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11791 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11792 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11796 target = new IndexerExpr (indexers, type, init, args, loc).Resolve (rc);
11802 // A block of object or collection initializers
11804 public class CollectionOrObjectInitializers : ExpressionStatement
11806 IList<Expression> initializers;
11807 bool is_collection_initialization;
11809 public CollectionOrObjectInitializers (Location loc)
11810 : this (new Expression[0], loc)
11814 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11816 this.initializers = initializers;
11820 public IList<Expression> Initializers {
11822 return initializers;
11826 public bool IsEmpty {
11828 return initializers.Count == 0;
11832 public bool IsCollectionInitializer {
11834 return is_collection_initialization;
11838 protected override void CloneTo (CloneContext clonectx, Expression target)
11840 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11842 t.initializers = new List<Expression> (initializers.Count);
11843 foreach (var e in initializers)
11844 t.initializers.Add (e.Clone (clonectx));
11847 public override bool ContainsEmitWithAwait ()
11849 foreach (var e in initializers) {
11850 if (e.ContainsEmitWithAwait ())
11857 public override Expression CreateExpressionTree (ResolveContext ec)
11859 return CreateExpressionTree (ec, false);
11862 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11864 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11865 foreach (Expression e in initializers) {
11866 Expression expr = e.CreateExpressionTree (ec);
11868 expr_initializers.Add (expr);
11872 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11874 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11877 protected override Expression DoResolve (ResolveContext ec)
11879 List<string> element_names = null;
11880 for (int i = 0; i < initializers.Count; ++i) {
11881 Expression initializer = initializers [i];
11882 ElementInitializer element_initializer = initializer as ElementInitializer;
11885 if (element_initializer != null) {
11886 element_names = new List<string> (initializers.Count);
11887 if (!element_initializer.IsDictionaryInitializer)
11888 element_names.Add (element_initializer.Name);
11889 } else if (initializer is CompletingExpression) {
11890 initializer.Resolve (ec);
11891 throw new InternalErrorException ("This line should never be reached");
11893 var t = ec.CurrentInitializerVariable.Type;
11894 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11895 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11896 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11897 "object initializer because type `{1}' does not implement `{2}' interface",
11898 ec.CurrentInitializerVariable.GetSignatureForError (),
11899 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11900 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11903 is_collection_initialization = true;
11906 if (is_collection_initialization != (element_initializer == null)) {
11907 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11908 is_collection_initialization ? "collection initializer" : "object initializer");
11912 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11913 if (element_names.Contains (element_initializer.Name)) {
11914 ec.Report.Error (1912, element_initializer.Location,
11915 "An object initializer includes more than one member `{0}' initialization",
11916 element_initializer.Name);
11918 element_names.Add (element_initializer.Name);
11923 Expression e = initializer.Resolve (ec);
11924 if (e == EmptyExpressionStatement.Instance)
11925 initializers.RemoveAt (i--);
11927 initializers [i] = e;
11930 type = ec.CurrentInitializerVariable.Type;
11931 if (is_collection_initialization) {
11932 if (TypeManager.HasElementType (type)) {
11933 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11934 type.GetSignatureForError ());
11938 eclass = ExprClass.Variable;
11942 public override void Emit (EmitContext ec)
11944 EmitStatement (ec);
11947 public override void EmitStatement (EmitContext ec)
11949 foreach (ExpressionStatement e in initializers) {
11950 // TODO: need location region
11951 ec.Mark (e.Location);
11952 e.EmitStatement (ec);
11956 public override void FlowAnalysis (FlowAnalysisContext fc)
11958 foreach (var initializer in initializers) {
11959 if (initializer != null)
11960 initializer.FlowAnalysis (fc);
11966 // New expression with element/object initializers
11968 public class NewInitialize : New
11971 // This class serves as a proxy for variable initializer target instances.
11972 // A real variable is assigned later when we resolve left side of an
11975 sealed class InitializerTargetExpression : Expression, IMemoryLocation
11977 NewInitialize new_instance;
11979 public InitializerTargetExpression (NewInitialize newInstance)
11981 this.type = newInstance.type;
11982 this.loc = newInstance.loc;
11983 this.eclass = newInstance.eclass;
11984 this.new_instance = newInstance;
11987 public override bool ContainsEmitWithAwait ()
11992 public override Expression CreateExpressionTree (ResolveContext ec)
11994 // Should not be reached
11995 throw new NotSupportedException ("ET");
11998 protected override Expression DoResolve (ResolveContext ec)
12003 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12008 public override void Emit (EmitContext ec)
12010 Expression e = (Expression) new_instance.instance;
12014 public override Expression EmitToField (EmitContext ec)
12016 return (Expression) new_instance.instance;
12019 #region IMemoryLocation Members
12021 public void AddressOf (EmitContext ec, AddressOp mode)
12023 new_instance.instance.AddressOf (ec, mode);
12029 CollectionOrObjectInitializers initializers;
12030 IMemoryLocation instance;
12031 DynamicExpressionStatement dynamic;
12033 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12034 : base (requested_type, arguments, l)
12036 this.initializers = initializers;
12039 public CollectionOrObjectInitializers Initializers {
12041 return initializers;
12045 protected override void CloneTo (CloneContext clonectx, Expression t)
12047 base.CloneTo (clonectx, t);
12049 NewInitialize target = (NewInitialize) t;
12050 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12053 public override bool ContainsEmitWithAwait ()
12055 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12058 public override Expression CreateExpressionTree (ResolveContext ec)
12060 Arguments args = new Arguments (2);
12061 args.Add (new Argument (base.CreateExpressionTree (ec)));
12062 if (!initializers.IsEmpty)
12063 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12065 return CreateExpressionFactoryCall (ec,
12066 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12070 protected override Expression DoResolve (ResolveContext ec)
12072 Expression e = base.DoResolve (ec);
12076 if (type.IsDelegate) {
12077 ec.Report.Error (1958, Initializers.Location,
12078 "Object and collection initializers cannot be used to instantiate a delegate");
12081 Expression previous = ec.CurrentInitializerVariable;
12082 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12083 initializers.Resolve (ec);
12084 ec.CurrentInitializerVariable = previous;
12086 dynamic = e as DynamicExpressionStatement;
12087 if (dynamic != null)
12093 public override void Emit (EmitContext ec)
12095 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12096 var fe = ec.GetTemporaryField (type);
12098 if (!Emit (ec, fe))
12107 public override bool Emit (EmitContext ec, IMemoryLocation target)
12110 // Expression is initialized into temporary target then moved
12111 // to real one for atomicity
12113 IMemoryLocation temp_target = target;
12115 LocalTemporary temp = null;
12116 bool by_ref = false;
12117 if (!initializers.IsEmpty) {
12118 temp_target = target as LocalTemporary;
12119 if (temp_target == null)
12120 temp_target = target as StackFieldExpr;
12122 if (temp_target == null) {
12123 var vr = target as VariableReference;
12124 if (vr != null && vr.IsRef) {
12130 if (temp_target == null)
12131 temp_target = temp = new LocalTemporary (type);
12134 bool left_on_stack;
12135 if (dynamic != null) {
12137 left_on_stack = true;
12139 left_on_stack = base.Emit (ec, temp_target);
12142 if (initializers.IsEmpty)
12143 return left_on_stack;
12145 StackFieldExpr sf = null;
12147 // Move a new instance (reference-type) to local temporary variable
12148 if (left_on_stack) {
12150 temp_target = temp = new LocalTemporary (type);
12156 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12158 throw new NotImplementedException ();
12160 sf = ec.GetTemporaryField (type);
12161 sf.EmitAssign (ec, temp, false, false);
12164 left_on_stack = false;
12168 instance = temp_target;
12170 initializers.Emit (ec);
12172 ((Expression)temp_target).Emit (ec);
12178 sf.IsAvailableForReuse = true;
12183 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12185 instance = base.EmitAddressOf (ec, Mode);
12187 if (!initializers.IsEmpty)
12188 initializers.Emit (ec);
12193 public override void FlowAnalysis (FlowAnalysisContext fc)
12195 base.FlowAnalysis (fc);
12196 initializers.FlowAnalysis (fc);
12199 public override object Accept (StructuralVisitor visitor)
12201 return visitor.Visit (this);
12205 public class NewAnonymousType : New
12207 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12209 List<AnonymousTypeParameter> parameters;
12210 readonly TypeContainer parent;
12211 AnonymousTypeClass anonymous_type;
12213 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12214 : base (null, null, loc)
12216 this.parameters = parameters;
12217 this.parent = parent;
12220 public List<AnonymousTypeParameter> Parameters {
12222 return this.parameters;
12226 protected override void CloneTo (CloneContext clonectx, Expression target)
12228 if (parameters == null)
12231 NewAnonymousType t = (NewAnonymousType) target;
12232 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12233 foreach (AnonymousTypeParameter atp in parameters)
12234 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12237 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12239 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12243 type = AnonymousTypeClass.Create (parent, parameters, loc);
12247 int errors = ec.Report.Errors;
12248 type.CreateContainer ();
12249 type.DefineContainer ();
12251 if ((ec.Report.Errors - errors) == 0) {
12252 parent.Module.AddAnonymousType (type);
12253 type.PrepareEmit ();
12259 public override Expression CreateExpressionTree (ResolveContext ec)
12261 if (parameters == null)
12262 return base.CreateExpressionTree (ec);
12264 var init = new ArrayInitializer (parameters.Count, loc);
12265 foreach (var m in anonymous_type.Members) {
12266 var p = m as Property;
12268 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12271 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12272 foreach (Argument a in arguments)
12273 ctor_args.Add (a.CreateExpressionTree (ec));
12275 Arguments args = new Arguments (3);
12276 args.Add (new Argument (new TypeOfMethod (method, loc)));
12277 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12278 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12280 return CreateExpressionFactoryCall (ec, "New", args);
12283 protected override Expression DoResolve (ResolveContext ec)
12285 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12286 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12290 if (parameters == null) {
12291 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12292 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12293 return base.DoResolve (ec);
12296 bool error = false;
12297 arguments = new Arguments (parameters.Count);
12298 var t_args = new TypeSpec [parameters.Count];
12299 for (int i = 0; i < parameters.Count; ++i) {
12300 Expression e = parameters [i].Resolve (ec);
12306 arguments.Add (new Argument (e));
12307 t_args [i] = e.Type;
12313 anonymous_type = CreateAnonymousType (ec, parameters);
12314 if (anonymous_type == null)
12317 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12318 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12319 eclass = ExprClass.Value;
12323 public override object Accept (StructuralVisitor visitor)
12325 return visitor.Visit (this);
12329 public class AnonymousTypeParameter : ShimExpression
12331 public readonly string Name;
12333 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12334 : base (initializer)
12340 public AnonymousTypeParameter (Parameter parameter)
12341 : base (new SimpleName (parameter.Name, parameter.Location))
12343 this.Name = parameter.Name;
12344 this.loc = parameter.Location;
12347 public override bool Equals (object o)
12349 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12350 return other != null && Name == other.Name;
12353 public override int GetHashCode ()
12355 return Name.GetHashCode ();
12358 protected override Expression DoResolve (ResolveContext ec)
12360 Expression e = expr.Resolve (ec);
12364 if (e.eclass == ExprClass.MethodGroup) {
12365 Error_InvalidInitializer (ec, e.ExprClassName);
12370 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12371 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12378 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12380 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12381 Name, initializer);
12385 public class CatchFilterExpression : BooleanExpression
12387 public CatchFilterExpression (Expression expr, Location loc)
12394 public class InterpolatedString : Expression
12396 readonly StringLiteral start, end;
12397 List<Expression> interpolations;
12398 Arguments arguments;
12400 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12402 this.start = start;
12404 this.interpolations = interpolations;
12405 loc = start.Location;
12408 protected override void CloneTo (CloneContext clonectx, Expression t)
12410 InterpolatedString target = (InterpolatedString) t;
12412 if (interpolations != null) {
12413 target.interpolations = new List<Expression> ();
12414 foreach (var interpolation in interpolations) {
12415 target.interpolations.Add (interpolation.Clone (clonectx));
12420 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12422 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12423 if (factory == null)
12426 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12427 var res = new Invocation (ma, arguments).Resolve (rc);
12428 if (res != null && res.Type != type)
12429 res = Convert.ExplicitConversion (rc, res, type, loc);
12434 public override bool ContainsEmitWithAwait ()
12436 if (interpolations == null)
12439 foreach (var expr in interpolations) {
12440 if (expr.ContainsEmitWithAwait ())
12447 public override Expression CreateExpressionTree (ResolveContext rc)
12449 var best = ResolveBestFormatOverload (rc);
12453 Expression instance = new NullLiteral (loc);
12454 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12455 return CreateExpressionFactoryCall (rc, "Call", args);
12458 protected override Expression DoResolve (ResolveContext rc)
12462 if (interpolations == null) {
12464 arguments = new Arguments (1);
12466 for (int i = 0; i < interpolations.Count; i += 2) {
12467 var ipi = (InterpolatedStringInsert)interpolations [i];
12471 arguments = new Arguments (interpolations.Count);
12473 var sb = new StringBuilder (start.Value);
12474 for (int i = 0; i < interpolations.Count; ++i) {
12476 sb.Append ('{').Append (i / 2);
12477 var isi = (InterpolatedStringInsert)interpolations [i];
12478 if (isi.Alignment != null) {
12480 var value = isi.ResolveAligment (rc);
12482 sb.Append (value.Value);
12485 if (isi.Format != null) {
12487 sb.Append (isi.Format);
12491 arguments.Add (new Argument (interpolations [i]));
12493 sb.Append (((StringLiteral)interpolations [i]).Value);
12497 sb.Append (end.Value);
12498 str = sb.ToString ();
12501 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12503 eclass = ExprClass.Value;
12504 type = rc.BuiltinTypes.String;
12508 public override void Emit (EmitContext ec)
12510 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12511 if (interpolations == null) {
12512 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12513 if (str != start.Value)
12514 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12521 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12525 var ca = new CallEmitter ();
12526 ca.Emit (ec, best, arguments, loc);
12529 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12531 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12532 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12533 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12537 public class InterpolatedStringInsert : CompositeExpression
12539 public InterpolatedStringInsert (Expression expr)
12544 public Expression Alignment { get; set; }
12545 public string Format { get; set; }
12547 protected override void CloneTo (CloneContext clonectx, Expression t)
12549 var target = (InterpolatedStringInsert)t;
12550 if (Alignment != null)
12551 target.Alignment = Alignment.Clone (clonectx);
12554 protected override Expression DoResolve (ResolveContext rc)
12556 var expr = base.DoResolve (rc);
12561 // For better error reporting, assumes the built-in implementation uses object
12564 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12567 public int? ResolveAligment (ResolveContext rc)
12569 var c = Alignment.ResolveLabelConstant (rc);
12573 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12577 var value = (int) c.GetValueAsLong ();
12578 if (value > 32767 || value < -32767) {
12579 rc.Report.Warning (8094, 1, Alignment.Location,
12580 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");