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 #if NET_4_0 || MOBILE_DYNAMIC
705 case Operator.OnesComplement:
706 return SLE.Expression.OnesComplement (expr);
709 throw new NotImplementedException (Oper.ToString ());
713 Expression ResolveAddressOf (ResolveContext ec)
716 UnsafeError (ec, loc);
718 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
719 if (Expr == null || Expr.eclass != ExprClass.Variable) {
720 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
724 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
728 IVariableReference vr = Expr as IVariableReference;
731 is_fixed = vr.IsFixed;
732 vr.SetHasAddressTaken ();
735 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
738 IFixedExpression fe = Expr as IFixedExpression;
739 is_fixed = fe != null && fe.IsFixed;
742 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
743 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
746 type = PointerContainer.MakeType (ec.Module, Expr.Type);
747 eclass = ExprClass.Value;
751 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
753 expr = DoNumericPromotion (rc, Oper, expr);
754 TypeSpec expr_type = expr.Type;
755 foreach (TypeSpec t in predefined) {
763 // Perform user-operator overload resolution
765 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
767 CSharp.Operator.OpType op_type;
769 case Operator.LogicalNot:
770 op_type = CSharp.Operator.OpType.LogicalNot; break;
771 case Operator.OnesComplement:
772 op_type = CSharp.Operator.OpType.OnesComplement; break;
773 case Operator.UnaryNegation:
774 op_type = CSharp.Operator.OpType.UnaryNegation; break;
775 case Operator.UnaryPlus:
776 op_type = CSharp.Operator.OpType.UnaryPlus; break;
778 throw new InternalErrorException (Oper.ToString ());
781 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
785 Arguments args = new Arguments (1);
786 args.Add (new Argument (expr));
788 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
789 var oper = res.ResolveOperator (ec, ref args);
794 Expr = args [0].Expr;
795 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
799 // Unary user type overload resolution
801 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
803 Expression best_expr = ResolveUserOperator (ec, expr);
804 if (best_expr != null)
807 foreach (TypeSpec t in predefined) {
808 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
809 if (oper_expr == null)
812 if (oper_expr == ErrorExpression.Instance)
816 // decimal type is predefined but has user-operators
818 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
819 oper_expr = ResolveUserType (ec, oper_expr, predefined);
821 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
823 if (oper_expr == null)
826 if (best_expr == null) {
827 best_expr = oper_expr;
831 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
833 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
834 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
836 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
843 best_expr = oper_expr;
846 if (best_expr == null)
850 // HACK: Decimal user-operator is included in standard operators
852 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
856 type = best_expr.Type;
860 protected override void CloneTo (CloneContext clonectx, Expression t)
862 Unary target = (Unary) t;
864 target.Expr = Expr.Clone (clonectx);
867 public override object Accept (StructuralVisitor visitor)
869 return visitor.Visit (this);
875 // Unary operators are turned into Indirection expressions
876 // after semantic analysis (this is so we can take the address
877 // of an indirection).
879 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
881 LocalTemporary temporary;
884 public Indirection (Expression expr, Location l)
890 public Expression Expr {
896 public bool IsFixed {
900 public override Location StartLocation {
902 return expr.StartLocation;
906 protected override void CloneTo (CloneContext clonectx, Expression t)
908 Indirection target = (Indirection) t;
909 target.expr = expr.Clone (clonectx);
912 public override bool ContainsEmitWithAwait ()
914 throw new NotImplementedException ();
917 public override Expression CreateExpressionTree (ResolveContext ec)
919 Error_PointerInsideExpressionTree (ec);
923 public override void Emit (EmitContext ec)
928 ec.EmitLoadFromPtr (Type);
931 public void Emit (EmitContext ec, bool leave_copy)
935 ec.Emit (OpCodes.Dup);
936 temporary = new LocalTemporary (expr.Type);
937 temporary.Store (ec);
941 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
943 prepared = isCompound;
948 ec.Emit (OpCodes.Dup);
952 ec.Emit (OpCodes.Dup);
953 temporary = new LocalTemporary (source.Type);
954 temporary.Store (ec);
957 ec.EmitStoreFromPtr (type);
959 if (temporary != null) {
961 temporary.Release (ec);
965 public void AddressOf (EmitContext ec, AddressOp Mode)
970 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
972 return DoResolve (ec);
975 protected override Expression DoResolve (ResolveContext ec)
977 expr = expr.Resolve (ec);
982 UnsafeError (ec, loc);
984 var pc = expr.Type as PointerContainer;
987 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
993 if (type.Kind == MemberKind.Void) {
994 Error_VoidPointerOperation (ec);
998 eclass = ExprClass.Variable;
1002 public override object Accept (StructuralVisitor visitor)
1004 return visitor.Visit (this);
1009 /// Unary Mutator expressions (pre and post ++ and --)
1013 /// UnaryMutator implements ++ and -- expressions. It derives from
1014 /// ExpressionStatement becuase the pre/post increment/decrement
1015 /// operators can be used in a statement context.
1017 /// FIXME: Idea, we could split this up in two classes, one simpler
1018 /// for the common case, and one with the extra fields for more complex
1019 /// classes (indexers require temporary access; overloaded require method)
1022 public class UnaryMutator : ExpressionStatement
1024 class DynamicPostMutator : Expression, IAssignMethod
1026 LocalTemporary temp;
1029 public DynamicPostMutator (Expression expr)
1032 this.type = expr.Type;
1033 this.loc = expr.Location;
1036 public override Expression CreateExpressionTree (ResolveContext ec)
1038 throw new NotImplementedException ("ET");
1041 protected override Expression DoResolve (ResolveContext rc)
1043 eclass = expr.eclass;
1047 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1049 expr.DoResolveLValue (ec, right_side);
1050 return DoResolve (ec);
1053 public override void Emit (EmitContext ec)
1058 public void Emit (EmitContext ec, bool leave_copy)
1060 throw new NotImplementedException ();
1064 // Emits target assignment using unmodified source value
1066 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1069 // Allocate temporary variable to keep original value before it's modified
1071 temp = new LocalTemporary (type);
1075 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1086 public enum Mode : byte {
1093 PreDecrement = IsDecrement,
1094 PostIncrement = IsPost,
1095 PostDecrement = IsPost | IsDecrement
1099 bool is_expr, recurse;
1101 protected Expression expr;
1103 // Holds the real operation
1104 Expression operation;
1106 public UnaryMutator (Mode m, Expression e, Location loc)
1113 public Mode UnaryMutatorMode {
1119 public Expression Expr {
1125 public override Location StartLocation {
1127 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1131 public override bool ContainsEmitWithAwait ()
1133 return expr.ContainsEmitWithAwait ();
1136 public override Expression CreateExpressionTree (ResolveContext ec)
1138 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1141 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1144 // Predefined ++ and -- operators exist for the following types:
1145 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1147 return new TypeSpec[] {
1163 protected override Expression DoResolve (ResolveContext ec)
1165 expr = expr.Resolve (ec);
1167 if (expr == null || expr.Type == InternalType.ErrorType)
1170 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1172 // Handle postfix unary operators using local
1173 // temporary variable
1175 if ((mode & Mode.IsPost) != 0)
1176 expr = new DynamicPostMutator (expr);
1178 Arguments args = new Arguments (1);
1179 args.Add (new Argument (expr));
1180 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1183 if (expr.Type.IsNullableType)
1184 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1186 return DoResolveOperation (ec);
1189 protected Expression DoResolveOperation (ResolveContext ec)
1191 eclass = ExprClass.Value;
1194 if (expr is RuntimeValueExpression) {
1197 // Use itself at the top of the stack
1198 operation = new EmptyExpression (type);
1202 // The operand of the prefix/postfix increment decrement operators
1203 // should be an expression that is classified as a variable,
1204 // a property access or an indexer access
1206 // TODO: Move to parser, expr is ATypeNameExpression
1207 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1208 expr = expr.ResolveLValue (ec, expr);
1210 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1214 // Step 1: Try to find a user operator, it has priority over predefined ones
1216 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1217 var methods = MemberCache.GetUserOperator (type, user_op, false);
1219 if (methods != null) {
1220 Arguments args = new Arguments (1);
1221 args.Add (new Argument (expr));
1223 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1224 var method = res.ResolveOperator (ec, ref args);
1228 args[0].Expr = operation;
1229 operation = new UserOperatorCall (method, args, null, loc);
1230 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1235 // Step 2: Try predefined types
1238 Expression source = null;
1239 bool primitive_type;
1242 // Predefined without user conversion first for speed-up
1244 // Predefined ++ and -- operators exist for the following types:
1245 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1247 switch (type.BuiltinType) {
1248 case BuiltinTypeSpec.Type.Byte:
1249 case BuiltinTypeSpec.Type.SByte:
1250 case BuiltinTypeSpec.Type.Short:
1251 case BuiltinTypeSpec.Type.UShort:
1252 case BuiltinTypeSpec.Type.Int:
1253 case BuiltinTypeSpec.Type.UInt:
1254 case BuiltinTypeSpec.Type.Long:
1255 case BuiltinTypeSpec.Type.ULong:
1256 case BuiltinTypeSpec.Type.Char:
1257 case BuiltinTypeSpec.Type.Float:
1258 case BuiltinTypeSpec.Type.Double:
1259 case BuiltinTypeSpec.Type.Decimal:
1261 primitive_type = true;
1264 primitive_type = false;
1266 // ++/-- on pointer variables of all types except void*
1267 if (type.IsPointer) {
1268 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1269 Error_VoidPointerOperation (ec);
1275 Expression best_source = null;
1276 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1277 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1279 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1283 if (best_source == null) {
1284 best_source = source;
1288 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1293 best_source = source;
1297 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1301 source = best_source;
1304 // ++/-- on enum types
1305 if (source == null && type.IsEnum)
1308 if (source == null) {
1309 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1316 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1317 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1318 operation = new Binary (op, source, one);
1319 operation = operation.Resolve (ec);
1320 if (operation == null)
1321 throw new NotImplementedException ("should not be reached");
1323 if (operation.Type != type) {
1325 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1327 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1333 void EmitCode (EmitContext ec, bool is_expr)
1336 this.is_expr = is_expr;
1337 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1340 public override void Emit (EmitContext ec)
1343 // We use recurse to allow ourselfs to be the source
1344 // of an assignment. This little hack prevents us from
1345 // having to allocate another expression
1348 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1356 EmitCode (ec, true);
1359 protected virtual void EmitOperation (EmitContext ec)
1361 operation.Emit (ec);
1364 public override void EmitStatement (EmitContext ec)
1366 EmitCode (ec, false);
1369 public override void FlowAnalysis (FlowAnalysisContext fc)
1371 expr.FlowAnalysis (fc);
1375 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1377 string GetOperatorExpressionTypeName ()
1379 return IsDecrement ? "Decrement" : "Increment";
1383 get { return (mode & Mode.IsDecrement) != 0; }
1387 #if NET_4_0 || MOBILE_DYNAMIC
1388 public override SLE.Expression MakeExpression (BuilderContext ctx)
1390 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1391 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1392 return SLE.Expression.Assign (target, source);
1396 public static string OperName (Mode oper)
1398 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1401 protected override void CloneTo (CloneContext clonectx, Expression t)
1403 UnaryMutator target = (UnaryMutator) t;
1405 target.expr = expr.Clone (clonectx);
1408 public override object Accept (StructuralVisitor visitor)
1410 return visitor.Visit (this);
1416 // Base class for the `is' and `as' operators
1418 public abstract class Probe : Expression
1420 public Expression ProbeType;
1421 protected Expression expr;
1422 protected TypeSpec probe_type_expr;
1424 protected Probe (Expression expr, Expression probe_type, Location l)
1426 ProbeType = probe_type;
1431 public Expression Expr {
1437 public override bool ContainsEmitWithAwait ()
1439 return expr.ContainsEmitWithAwait ();
1442 protected Expression ResolveCommon (ResolveContext rc)
1444 expr = expr.Resolve (rc);
1448 ResolveProbeType (rc);
1449 if (probe_type_expr == null)
1452 if (probe_type_expr.IsStatic) {
1453 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1454 probe_type_expr.GetSignatureForError ());
1458 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1459 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1464 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1465 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1473 protected virtual void ResolveProbeType (ResolveContext rc)
1475 probe_type_expr = ProbeType.ResolveAsType (rc);
1478 public override void EmitSideEffect (EmitContext ec)
1480 expr.EmitSideEffect (ec);
1483 public override void FlowAnalysis (FlowAnalysisContext fc)
1485 expr.FlowAnalysis (fc);
1488 protected abstract string OperatorName { get; }
1490 protected override void CloneTo (CloneContext clonectx, Expression t)
1492 Probe target = (Probe) t;
1494 target.expr = expr.Clone (clonectx);
1495 target.ProbeType = ProbeType.Clone (clonectx);
1501 /// Implementation of the `is' operator.
1503 public class Is : Probe
1505 Nullable.Unwrap expr_unwrap;
1506 MethodSpec number_mg;
1507 Arguments number_args;
1509 public Is (Expression expr, Expression probe_type, Location l)
1510 : base (expr, probe_type, l)
1514 protected override string OperatorName {
1515 get { return "is"; }
1518 public LocalVariable Variable { get; set; }
1520 public override Expression CreateExpressionTree (ResolveContext ec)
1522 if (Variable != null)
1523 throw new NotSupportedException ();
1525 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1526 expr.CreateExpressionTree (ec),
1527 new TypeOf (probe_type_expr, loc));
1529 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1532 Expression CreateConstantResult (ResolveContext rc, bool result)
1535 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1536 probe_type_expr.GetSignatureForError ());
1538 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1539 probe_type_expr.GetSignatureForError ());
1541 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1542 return expr.IsSideEffectFree ?
1543 ReducedExpression.Create (c, this) :
1544 new SideEffectConstant (c, this, loc);
1547 public override void Emit (EmitContext ec)
1549 if (probe_type_expr == null) {
1550 if (ProbeType is WildcardPattern) {
1551 expr.EmitSideEffect (ec);
1552 ProbeType.Emit (ec);
1554 EmitPatternMatch (ec);
1561 if (expr_unwrap == null) {
1563 ec.Emit (OpCodes.Cgt_Un);
1567 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1569 if (probe_type_expr == null) {
1570 EmitPatternMatch (ec);
1575 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1578 void EmitPatternMatch (EmitContext ec)
1580 var no_match = ec.DefineLabel ();
1581 var end = ec.DefineLabel ();
1583 if (expr_unwrap != null) {
1584 expr_unwrap.EmitCheck (ec);
1586 if (ProbeType.IsNull) {
1588 ec.Emit (OpCodes.Ceq);
1592 ec.Emit (OpCodes.Brfalse_S, no_match);
1593 expr_unwrap.Emit (ec);
1594 ProbeType.Emit (ec);
1595 ec.Emit (OpCodes.Ceq);
1596 ec.Emit (OpCodes.Br_S, end);
1597 ec.MarkLabel (no_match);
1603 if (number_args != null && number_args.Count == 3) {
1604 var ce = new CallEmitter ();
1605 ce.Emit (ec, number_mg, number_args, loc);
1609 var probe_type = ProbeType.Type;
1612 ec.Emit (OpCodes.Isinst, probe_type);
1613 ec.Emit (OpCodes.Dup);
1614 ec.Emit (OpCodes.Brfalse, no_match);
1616 bool complex_pattern = ProbeType is ComplexPatternExpression;
1617 Label prev = ec.RecursivePatternLabel;
1618 if (complex_pattern)
1619 ec.RecursivePatternLabel = ec.DefineLabel ();
1621 if (number_mg != null) {
1622 var ce = new CallEmitter ();
1623 ce.Emit (ec, number_mg, number_args, loc);
1625 if (TypeSpec.IsValueType (probe_type))
1626 ec.Emit (OpCodes.Unbox_Any, probe_type);
1628 ProbeType.Emit (ec);
1629 if (complex_pattern) {
1632 ec.Emit (OpCodes.Ceq);
1635 ec.Emit (OpCodes.Br_S, end);
1636 ec.MarkLabel (no_match);
1638 ec.Emit (OpCodes.Pop);
1640 if (complex_pattern)
1641 ec.MarkLabel (ec.RecursivePatternLabel);
1643 ec.RecursivePatternLabel = prev;
1649 void EmitLoad (EmitContext ec)
1651 Label no_value_label = new Label ();
1653 if (expr_unwrap != null) {
1654 expr_unwrap.EmitCheck (ec);
1656 if (Variable == null)
1659 ec.Emit (OpCodes.Dup);
1660 no_value_label = ec.DefineLabel ();
1661 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1662 expr_unwrap.Emit (ec);
1666 // Only to make verifier happy
1667 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1668 ec.Emit (OpCodes.Box, expr.Type);
1670 ec.Emit (OpCodes.Isinst, probe_type_expr);
1673 if (Variable != null) {
1674 bool value_on_stack;
1675 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1676 ec.Emit (OpCodes.Dup);
1677 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1678 value_on_stack = true;
1680 value_on_stack = false;
1683 Variable.CreateBuilder (ec);
1684 Variable.EmitAssign (ec);
1686 if (expr_unwrap != null) {
1687 ec.MarkLabel (no_value_label);
1688 } else if (!value_on_stack) {
1694 protected override Expression DoResolve (ResolveContext rc)
1696 if (ResolveCommon (rc) == null)
1699 type = rc.BuiltinTypes.Bool;
1700 eclass = ExprClass.Value;
1702 if (probe_type_expr == null)
1703 return ResolveMatchingExpression (rc);
1705 var res = ResolveResultExpression (rc);
1706 if (Variable != null) {
1707 if (res is Constant)
1708 throw new NotImplementedException ("constant in type pattern matching");
1710 Variable.Type = probe_type_expr;
1711 var bc = rc as BlockContext;
1713 Variable.PrepareAssignmentAnalysis (bc);
1719 public override void FlowAnalysis (FlowAnalysisContext fc)
1721 base.FlowAnalysis (fc);
1723 if (Variable != null)
1724 fc.SetVariableAssigned (Variable.VariableInfo, true);
1727 protected override void ResolveProbeType (ResolveContext rc)
1729 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1730 if (ProbeType is PatternExpression) {
1731 ProbeType.Resolve (rc);
1736 // Have to use session recording because we don't have reliable type probing
1737 // mechanism (similar issue as in attributes resolving)
1739 // TODO: This is still wrong because ResolveAsType can be destructive
1741 var type_printer = new SessionReportPrinter ();
1742 var prev_recorder = rc.Report.SetPrinter (type_printer);
1744 probe_type_expr = ProbeType.ResolveAsType (rc);
1745 type_printer.EndSession ();
1747 if (probe_type_expr != null) {
1748 type_printer.Merge (rc.Report.Printer);
1749 rc.Report.SetPrinter (prev_recorder);
1753 var vexpr = ProbeType as VarExpr;
1754 if (vexpr != null && vexpr.InferType (rc, expr)) {
1755 probe_type_expr = vexpr.Type;
1756 rc.Report.SetPrinter (prev_recorder);
1760 var expr_printer = new SessionReportPrinter ();
1761 rc.Report.SetPrinter (expr_printer);
1762 ProbeType = ProbeType.Resolve (rc);
1763 expr_printer.EndSession ();
1765 if (ProbeType != null) {
1766 expr_printer.Merge (rc.Report.Printer);
1768 type_printer.Merge (rc.Report.Printer);
1771 rc.Report.SetPrinter (prev_recorder);
1775 base.ResolveProbeType (rc);
1778 Expression ResolveMatchingExpression (ResolveContext rc)
1780 var mc = ProbeType as Constant;
1782 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1783 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1788 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1790 var c = Expr as Constant;
1792 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1797 if (Expr.Type.IsNullableType) {
1798 expr_unwrap = new Nullable.Unwrap (Expr);
1799 expr_unwrap.Resolve (rc);
1800 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1801 } else if (ProbeType.Type == Expr.Type) {
1802 // TODO: Better error handling
1803 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1804 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1805 var helper = rc.Module.CreatePatterMatchingHelper ();
1806 number_mg = helper.NumberMatcher.Spec;
1809 // There are actually 3 arguments but the first one is already on the stack
1811 number_args = new Arguments (3);
1812 if (!ProbeType.Type.IsEnum)
1813 number_args.Add (new Argument (Expr));
1815 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1816 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1822 if (ProbeType is PatternExpression) {
1823 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1824 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1830 // TODO: Better error message
1831 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1835 Expression ResolveResultExpression (ResolveContext ec)
1837 TypeSpec d = expr.Type;
1838 bool d_is_nullable = false;
1841 // If E is a method group or the null literal, or if the type of E is a reference
1842 // type or a nullable type and the value of E is null, the result is false
1844 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1845 return CreateConstantResult (ec, false);
1847 if (d.IsNullableType) {
1848 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1849 if (!ut.IsGenericParameter) {
1851 d_is_nullable = true;
1855 TypeSpec t = probe_type_expr;
1856 bool t_is_nullable = false;
1857 if (t.IsNullableType) {
1858 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1859 if (!ut.IsGenericParameter) {
1861 t_is_nullable = true;
1868 // D and T are the same value types but D can be null
1870 if (d_is_nullable && !t_is_nullable) {
1871 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1876 // The result is true if D and T are the same value types
1878 return CreateConstantResult (ec, true);
1881 var tp = d as TypeParameterSpec;
1883 return ResolveGenericParameter (ec, t, tp);
1886 // An unboxing conversion exists
1888 if (Convert.ExplicitReferenceConversionExists (d, t))
1892 // open generic type
1894 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1897 var tps = t as TypeParameterSpec;
1899 return ResolveGenericParameter (ec, d, tps);
1901 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1902 ec.Report.Warning (1981, 3, loc,
1903 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1904 OperatorName, t.GetSignatureForError ());
1907 if (TypeManager.IsGenericParameter (d))
1908 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1910 if (TypeSpec.IsValueType (d)) {
1911 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1912 if (d_is_nullable && !t_is_nullable) {
1913 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1917 return CreateConstantResult (ec, true);
1920 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1921 var c = expr as Constant;
1923 return CreateConstantResult (ec, !c.IsNull);
1926 // Do not optimize for imported type or dynamic type
1928 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1929 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1933 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1937 // Turn is check into simple null check for implicitly convertible reference types
1939 return ReducedExpression.Create (
1940 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
1944 if (Convert.ExplicitReferenceConversionExists (d, t))
1948 // open generic type
1950 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1955 return CreateConstantResult (ec, false);
1958 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1960 if (t.IsReferenceType) {
1962 return CreateConstantResult (ec, false);
1965 if (expr.Type.IsGenericParameter) {
1966 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1967 return CreateConstantResult (ec, true);
1969 expr = new BoxedCast (expr, d);
1975 public override object Accept (StructuralVisitor visitor)
1977 return visitor.Visit (this);
1981 class WildcardPattern : PatternExpression
1983 public WildcardPattern (Location loc)
1988 protected override Expression DoResolve (ResolveContext rc)
1990 eclass = ExprClass.Value;
1991 type = rc.BuiltinTypes.Object;
1995 public override void Emit (EmitContext ec)
2001 class RecursivePattern : ComplexPatternExpression
2003 MethodGroupExpr operator_mg;
2004 Arguments operator_args;
2006 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2007 : base (typeExpresion, loc)
2009 Arguments = arguments;
2012 public Arguments Arguments { get; private set; }
2014 protected override Expression DoResolve (ResolveContext rc)
2016 type = TypeExpression.ResolveAsType (rc);
2020 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2021 if (operators == null) {
2022 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2026 var ops = FindMatchingOverloads (operators);
2028 // TODO: better error message
2029 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2034 Arguments.Resolve (rc, out dynamic_args);
2036 throw new NotImplementedException ("dynamic argument");
2038 var op = FindBestOverload (rc, ops);
2040 // TODO: better error message
2041 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2045 var op_types = op.Parameters.Types;
2046 operator_args = new Arguments (op_types.Length);
2047 operator_args.Add (new Argument (new EmptyExpression (type)));
2049 for (int i = 0; i < Arguments.Count; ++i) {
2050 // TODO: Needs releasing optimization
2051 var lt = new LocalTemporary (op_types [i + 1]);
2052 operator_args.Add (new Argument (lt, Argument.AType.Out));
2054 if (comparisons == null)
2055 comparisons = new Expression[Arguments.Count];
2060 var arg = Arguments [i];
2061 var named = arg as NamedArgument;
2062 if (named != null) {
2063 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2064 expr = Arguments [arg_comp_index].Expr;
2070 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2073 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2075 eclass = ExprClass.Value;
2079 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2081 int arg_count = Arguments.Count + 1;
2082 List<MethodSpec> best = null;
2083 foreach (MethodSpec method in members) {
2084 var pm = method.Parameters;
2085 if (pm.Count != arg_count)
2088 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2090 for (int ii = 1; ii < pm.Count; ++ii) {
2091 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2101 best = new List<MethodSpec> ();
2109 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2111 for (int ii = 0; ii < Arguments.Count; ++ii) {
2112 var arg = Arguments [ii];
2113 var expr = arg.Expr;
2114 if (expr is WildcardPattern)
2117 var na = arg as NamedArgument;
2118 for (int i = 0; i < methods.Count; ++i) {
2119 var pd = methods [i].Parameters;
2123 index = pd.GetParameterIndexByName (na.Name);
2125 methods.RemoveAt (i--);
2132 var m = pd.Types [index];
2133 if (!Convert.ImplicitConversionExists (rc, expr, m))
2134 methods.RemoveAt (i--);
2138 if (methods.Count != 1)
2144 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2146 operator_mg.EmitCall (ec, operator_args, false);
2147 ec.Emit (OpCodes.Brfalse, target);
2149 base.EmitBranchable (ec, target, on_true);
2152 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2154 if (expr is WildcardPattern)
2155 return new EmptyExpression (expr.Type);
2157 var recursive = expr as RecursivePattern;
2158 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2162 if (recursive != null) {
2163 recursive.SetParentInstance (lt);
2167 // TODO: Better error handling
2168 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2171 public void SetParentInstance (Expression instance)
2173 operator_args [0] = new Argument (instance);
2177 class PropertyPattern : ComplexPatternExpression
2179 LocalTemporary instance;
2181 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2182 : base (typeExpresion, loc)
2187 public List<PropertyPatternMember> Members { get; private set; }
2189 protected override Expression DoResolve (ResolveContext rc)
2191 type = TypeExpression.ResolveAsType (rc);
2195 comparisons = new Expression[Members.Count];
2197 // TODO: optimize when source is VariableReference, it'd save dup+pop
2198 instance = new LocalTemporary (type);
2200 for (int i = 0; i < Members.Count; i++) {
2201 var lookup = Members [i];
2203 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2204 if (member == null) {
2205 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2206 if (member != null) {
2207 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2212 if (member == null) {
2213 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2217 var pe = member as PropertyExpr;
2218 if (pe == null || member is FieldExpr) {
2219 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2223 // TODO: Obsolete checks
2224 // TODO: check accessibility
2225 if (pe != null && !pe.PropertyInfo.HasGet) {
2226 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2230 var expr = lookup.Expr.Resolve (rc);
2234 var me = (MemberExpr)member;
2235 me.InstanceExpression = instance;
2237 comparisons [i] = ResolveComparison (rc, expr, me);
2240 eclass = ExprClass.Value;
2244 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2246 if (expr is WildcardPattern)
2247 return new EmptyExpression (expr.Type);
2249 return new Is (instance, expr, expr.Location).Resolve (rc);
2252 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2254 instance.Store (ec);
2256 base.EmitBranchable (ec, target, on_true);
2260 class PropertyPatternMember
2262 public PropertyPatternMember (string name, Expression expr, Location loc)
2269 public string Name { get; private set; }
2270 public Expression Expr { get; private set; }
2271 public Location Location { get; private set; }
2274 abstract class PatternExpression : Expression
2276 protected PatternExpression (Location loc)
2281 public override Expression CreateExpressionTree (ResolveContext ec)
2283 throw new NotImplementedException ();
2287 abstract class ComplexPatternExpression : PatternExpression
2289 protected Expression[] comparisons;
2291 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2294 TypeExpression = typeExpresion;
2297 public ATypeNameExpression TypeExpression { get; private set; }
2299 public override void Emit (EmitContext ec)
2301 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2304 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2306 if (comparisons != null) {
2307 foreach (var comp in comparisons) {
2308 comp.EmitBranchable (ec, target, false);
2315 /// Implementation of the `as' operator.
2317 public class As : Probe {
2319 public As (Expression expr, Expression probe_type, Location l)
2320 : base (expr, probe_type, l)
2324 protected override string OperatorName {
2325 get { return "as"; }
2328 public override Expression CreateExpressionTree (ResolveContext ec)
2330 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2331 expr.CreateExpressionTree (ec),
2332 new TypeOf (probe_type_expr, loc));
2334 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2337 public override void Emit (EmitContext ec)
2341 ec.Emit (OpCodes.Isinst, type);
2343 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2344 ec.Emit (OpCodes.Unbox_Any, type);
2347 protected override Expression DoResolve (ResolveContext ec)
2349 if (ResolveCommon (ec) == null)
2352 type = probe_type_expr;
2353 eclass = ExprClass.Value;
2354 TypeSpec etype = expr.Type;
2356 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2357 if (TypeManager.IsGenericParameter (type)) {
2358 ec.Report.Error (413, loc,
2359 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2360 probe_type_expr.GetSignatureForError ());
2362 ec.Report.Error (77, loc,
2363 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2364 type.GetSignatureForError ());
2369 if (expr.IsNull && type.IsNullableType) {
2370 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2373 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2374 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2378 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2380 e = EmptyCast.Create (e, type);
2381 return ReducedExpression.Create (e, this).Resolve (ec);
2384 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2385 if (TypeManager.IsGenericParameter (etype))
2386 expr = new BoxedCast (expr, etype);
2391 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2392 expr = new BoxedCast (expr, etype);
2396 if (etype != InternalType.ErrorType) {
2397 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2398 etype.GetSignatureForError (), type.GetSignatureForError ());
2404 public override object Accept (StructuralVisitor visitor)
2406 return visitor.Visit (this);
2411 // This represents a typecast in the source language.
2413 public class Cast : ShimExpression {
2414 Expression target_type;
2416 public Cast (Expression cast_type, Expression expr, Location loc)
2419 this.target_type = cast_type;
2423 public Expression TargetType {
2424 get { return target_type; }
2427 protected override Expression DoResolve (ResolveContext ec)
2429 expr = expr.Resolve (ec);
2433 type = target_type.ResolveAsType (ec);
2437 if (type.IsStatic) {
2438 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2442 if (type.IsPointer && !ec.IsUnsafe) {
2443 UnsafeError (ec, loc);
2446 eclass = ExprClass.Value;
2448 Constant c = expr as Constant;
2450 c = c.Reduce (ec, type);
2455 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2457 return EmptyCast.Create (res, type);
2462 protected override void CloneTo (CloneContext clonectx, Expression t)
2464 Cast target = (Cast) t;
2466 target.target_type = target_type.Clone (clonectx);
2467 target.expr = expr.Clone (clonectx);
2470 public override object Accept (StructuralVisitor visitor)
2472 return visitor.Visit (this);
2476 public class ImplicitCast : ShimExpression
2480 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2483 this.loc = expr.Location;
2485 this.arrayAccess = arrayAccess;
2488 protected override Expression DoResolve (ResolveContext ec)
2490 expr = expr.Resolve (ec);
2495 expr = ConvertExpressionToArrayIndex (ec, expr);
2497 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2503 public class DeclarationExpression : Expression, IMemoryLocation
2505 LocalVariableReference lvr;
2507 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2509 VariableType = variableType;
2510 Variable = variable;
2511 this.loc = variable.Location;
2514 public LocalVariable Variable { get; set; }
2515 public Expression Initializer { get; set; }
2516 public FullNamedExpression VariableType { get; set; }
2518 public void AddressOf (EmitContext ec, AddressOp mode)
2520 Variable.CreateBuilder (ec);
2522 if (Initializer != null) {
2523 lvr.EmitAssign (ec, Initializer, false, false);
2526 lvr.AddressOf (ec, mode);
2529 protected override void CloneTo (CloneContext clonectx, Expression t)
2531 var target = (DeclarationExpression) t;
2533 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2535 if (Initializer != null)
2536 target.Initializer = Initializer.Clone (clonectx);
2539 public override Expression CreateExpressionTree (ResolveContext rc)
2541 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2545 bool DoResolveCommon (ResolveContext rc)
2547 var var_expr = VariableType as VarExpr;
2548 if (var_expr != null) {
2549 type = InternalType.VarOutType;
2551 type = VariableType.ResolveAsType (rc);
2556 if (Initializer != null) {
2557 Initializer = Initializer.Resolve (rc);
2559 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2560 type = var_expr.Type;
2564 Variable.Type = type;
2565 lvr = new LocalVariableReference (Variable, loc);
2567 eclass = ExprClass.Variable;
2571 protected override Expression DoResolve (ResolveContext rc)
2573 if (DoResolveCommon (rc))
2579 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2581 if (lvr == null && DoResolveCommon (rc))
2582 lvr.ResolveLValue (rc, right_side);
2587 public override void Emit (EmitContext ec)
2589 throw new NotImplementedException ();
2594 // C# 2.0 Default value expression
2596 public class DefaultValueExpression : Expression
2600 public DefaultValueExpression (Expression expr, Location loc)
2606 public Expression Expr {
2612 public override bool IsSideEffectFree {
2618 public override bool ContainsEmitWithAwait ()
2623 public override Expression CreateExpressionTree (ResolveContext ec)
2625 Arguments args = new Arguments (2);
2626 args.Add (new Argument (this));
2627 args.Add (new Argument (new TypeOf (type, loc)));
2628 return CreateExpressionFactoryCall (ec, "Constant", args);
2631 protected override Expression DoResolve (ResolveContext ec)
2633 type = expr.ResolveAsType (ec);
2637 if (type.IsStatic) {
2638 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2642 return new NullLiteral (Location).ConvertImplicitly (type);
2644 if (TypeSpec.IsReferenceType (type))
2645 return new NullConstant (type, loc);
2647 Constant c = New.Constantify (type, expr.Location);
2651 eclass = ExprClass.Variable;
2655 public override void Emit (EmitContext ec)
2657 LocalTemporary temp_storage = new LocalTemporary(type);
2659 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2660 ec.Emit(OpCodes.Initobj, type);
2661 temp_storage.Emit(ec);
2662 temp_storage.Release (ec);
2665 #if (NET_4_0 || MOBILE_DYNAMIC) && !STATIC
2666 public override SLE.Expression MakeExpression (BuilderContext ctx)
2668 return SLE.Expression.Default (type.GetMetaInfo ());
2672 protected override void CloneTo (CloneContext clonectx, Expression t)
2674 DefaultValueExpression target = (DefaultValueExpression) t;
2676 target.expr = expr.Clone (clonectx);
2679 public override object Accept (StructuralVisitor visitor)
2681 return visitor.Visit (this);
2686 /// Binary operators
2688 public class Binary : Expression, IDynamicBinder
2690 public class PredefinedOperator
2692 protected readonly TypeSpec left;
2693 protected readonly TypeSpec right;
2694 protected readonly TypeSpec left_unwrap;
2695 protected readonly TypeSpec right_unwrap;
2696 public readonly Operator OperatorsMask;
2697 public TypeSpec ReturnType;
2699 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2700 : this (ltype, rtype, op_mask, ltype)
2704 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2705 : this (type, type, op_mask, return_type)
2709 public PredefinedOperator (TypeSpec type, Operator op_mask)
2710 : this (type, type, op_mask, type)
2714 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2716 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2717 throw new InternalErrorException ("Only masked values can be used");
2719 if ((op_mask & Operator.NullableMask) != 0) {
2720 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2721 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2723 left_unwrap = ltype;
2724 right_unwrap = rtype;
2729 this.OperatorsMask = op_mask;
2730 this.ReturnType = return_type;
2733 public bool IsLifted {
2735 return (OperatorsMask & Operator.NullableMask) != 0;
2739 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2743 var left_expr = b.left;
2744 var right_expr = b.right;
2746 b.type = ReturnType;
2749 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2750 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2751 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2754 if (right_expr.IsNull) {
2755 if ((b.oper & Operator.EqualityMask) != 0) {
2756 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2757 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2758 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2759 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2760 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2762 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2763 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2765 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2766 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2768 return b.CreateLiftedValueTypeResult (rc, left);
2770 } else if (left_expr.IsNull) {
2771 if ((b.oper & Operator.EqualityMask) != 0) {
2772 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2773 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2774 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2775 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2776 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2778 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2779 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2781 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2782 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2784 return b.CreateLiftedValueTypeResult (rc, right);
2790 // A user operators does not support multiple user conversions, but decimal type
2791 // is considered to be predefined type therefore we apply predefined operators rules
2792 // and then look for decimal user-operator implementation
2794 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2795 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2796 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2798 return b.ResolveUserOperator (rc, b.left, b.right);
2801 c = right_expr as Constant;
2803 if (c.IsDefaultValue) {
2807 // (expr + 0) to expr
2808 // (expr - 0) to expr
2809 // (bool? | false) to bool?
2811 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2812 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2813 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2814 return ReducedExpression.Create (b.left, b).Resolve (rc);
2818 // Optimizes (value &/&& 0) to 0
2820 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2821 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2822 return ReducedExpression.Create (side_effect, b);
2826 // Optimizes (bool? & true) to bool?
2828 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2829 return ReducedExpression.Create (b.left, b).Resolve (rc);
2833 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2834 return ReducedExpression.Create (b.left, b).Resolve (rc);
2836 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2837 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2841 c = b.left as Constant;
2843 if (c.IsDefaultValue) {
2847 // (0 + expr) to expr
2848 // (false | bool?) to bool?
2850 if (b.oper == Operator.Addition ||
2851 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2852 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2853 return ReducedExpression.Create (b.right, b).Resolve (rc);
2857 // Optimizes (false && expr) to false
2859 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2860 // No rhs side-effects
2861 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2862 return ReducedExpression.Create (c, b);
2866 // Optimizes (0 & value) to 0
2868 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2869 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2870 return ReducedExpression.Create (side_effect, b);
2874 // Optimizes (true & bool?) to bool?
2876 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2877 return ReducedExpression.Create (b.right, b).Resolve (rc);
2881 // Optimizes (true || expr) to true
2883 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2884 // No rhs side-effects
2885 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2886 return ReducedExpression.Create (c, b);
2890 if (b.oper == Operator.Multiply && c.IsOneInteger)
2891 return ReducedExpression.Create (b.right, b).Resolve (rc);
2895 var lifted = new Nullable.LiftedBinaryOperator (b);
2897 TypeSpec ltype, rtype;
2898 if (b.left.Type.IsNullableType) {
2899 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2900 ltype = left_unwrap;
2905 if (b.right.Type.IsNullableType) {
2906 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2907 rtype = right_unwrap;
2912 lifted.Left = b.left.IsNull ?
2914 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2916 lifted.Right = b.right.IsNull ?
2918 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2920 return lifted.Resolve (rc);
2923 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2924 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2929 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2932 // We are dealing with primitive types only
2934 return left == ltype && ltype == rtype;
2937 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2940 if (left == lexpr.Type && right == rexpr.Type)
2943 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2944 Convert.ImplicitConversionExists (ec, rexpr, right);
2947 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2949 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2950 return best_operator;
2952 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2956 if (left != null && best_operator.left != null) {
2957 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2961 // When second argument is same as the first one, the result is same
2963 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2964 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2967 if (result == 0 || result > 2)
2970 return result == 1 ? best_operator : this;
2974 sealed class PredefinedStringOperator : PredefinedOperator
2976 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2977 : base (type, type, op_mask, retType)
2981 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2982 : base (ltype, rtype, op_mask, retType)
2986 public override Expression ConvertResult (ResolveContext ec, Binary b)
2989 // Use original expression for nullable arguments
2991 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2993 b.left = unwrap.Original;
2995 unwrap = b.right as Nullable.Unwrap;
2997 b.right = unwrap.Original;
2999 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3000 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3003 // Start a new concat expression using converted expression
3005 return StringConcat.Create (ec, b.left, b.right, b.loc);
3009 sealed class PredefinedEqualityOperator : PredefinedOperator
3011 MethodSpec equal_method, inequal_method;
3013 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3014 : base (arg, arg, Operator.EqualityMask, retType)
3018 public override Expression ConvertResult (ResolveContext ec, Binary b)
3020 b.type = ReturnType;
3022 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3023 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3025 Arguments args = new Arguments (2);
3026 args.Add (new Argument (b.left));
3027 args.Add (new Argument (b.right));
3030 if (b.oper == Operator.Equality) {
3031 if (equal_method == null) {
3032 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3033 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3034 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3035 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3037 throw new NotImplementedException (left.GetSignatureForError ());
3040 method = equal_method;
3042 if (inequal_method == null) {
3043 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3044 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3045 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3046 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3048 throw new NotImplementedException (left.GetSignatureForError ());
3051 method = inequal_method;
3054 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3058 class PredefinedPointerOperator : PredefinedOperator
3060 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3061 : base (ltype, rtype, op_mask)
3065 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3066 : base (ltype, rtype, op_mask, retType)
3070 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3071 : base (type, op_mask, return_type)
3075 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3078 if (!lexpr.Type.IsPointer)
3081 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3085 if (right == null) {
3086 if (!rexpr.Type.IsPointer)
3089 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3096 public override Expression ConvertResult (ResolveContext ec, Binary b)
3099 b.left = EmptyCast.Create (b.left, left);
3100 } else if (right != null) {
3101 b.right = EmptyCast.Create (b.right, right);
3104 TypeSpec r_type = ReturnType;
3105 Expression left_arg, right_arg;
3106 if (r_type == null) {
3109 right_arg = b.right;
3110 r_type = b.left.Type;
3114 r_type = b.right.Type;
3118 right_arg = b.right;
3121 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3126 public enum Operator {
3127 Multiply = 0 | ArithmeticMask,
3128 Division = 1 | ArithmeticMask,
3129 Modulus = 2 | ArithmeticMask,
3130 Addition = 3 | ArithmeticMask | AdditionMask,
3131 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3133 LeftShift = 5 | ShiftMask,
3134 RightShift = 6 | ShiftMask,
3136 LessThan = 7 | ComparisonMask | RelationalMask,
3137 GreaterThan = 8 | ComparisonMask | RelationalMask,
3138 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3139 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3140 Equality = 11 | ComparisonMask | EqualityMask,
3141 Inequality = 12 | ComparisonMask | EqualityMask,
3143 BitwiseAnd = 13 | BitwiseMask,
3144 ExclusiveOr = 14 | BitwiseMask,
3145 BitwiseOr = 15 | BitwiseMask,
3147 LogicalAnd = 16 | LogicalMask,
3148 LogicalOr = 17 | LogicalMask,
3153 ValuesOnlyMask = ArithmeticMask - 1,
3154 ArithmeticMask = 1 << 5,
3156 ComparisonMask = 1 << 7,
3157 EqualityMask = 1 << 8,
3158 BitwiseMask = 1 << 9,
3159 LogicalMask = 1 << 10,
3160 AdditionMask = 1 << 11,
3161 SubtractionMask = 1 << 12,
3162 RelationalMask = 1 << 13,
3164 DecomposedMask = 1 << 19,
3165 NullableMask = 1 << 20
3169 public enum State : byte
3173 UserOperatorsExcluded = 1 << 2
3176 readonly Operator oper;
3177 Expression left, right;
3179 ConvCast.Mode enum_conversion;
3181 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3182 : this (oper, left, right, State.Compound)
3186 public Binary (Operator oper, Expression left, Expression right, State state)
3187 : this (oper, left, right)
3192 public Binary (Operator oper, Expression left, Expression right)
3193 : this (oper, left, right, left.Location)
3197 public Binary (Operator oper, Expression left, Expression right, Location loc)
3207 public bool IsCompound {
3209 return (state & State.Compound) != 0;
3213 public Operator Oper {
3219 public Expression Left {
3225 public Expression Right {
3231 public override Location StartLocation {
3233 return left.StartLocation;
3240 /// Returns a stringified representation of the Operator
3242 string OperName (Operator oper)
3246 case Operator.Multiply:
3249 case Operator.Division:
3252 case Operator.Modulus:
3255 case Operator.Addition:
3258 case Operator.Subtraction:
3261 case Operator.LeftShift:
3264 case Operator.RightShift:
3267 case Operator.LessThan:
3270 case Operator.GreaterThan:
3273 case Operator.LessThanOrEqual:
3276 case Operator.GreaterThanOrEqual:
3279 case Operator.Equality:
3282 case Operator.Inequality:
3285 case Operator.BitwiseAnd:
3288 case Operator.BitwiseOr:
3291 case Operator.ExclusiveOr:
3294 case Operator.LogicalOr:
3297 case Operator.LogicalAnd:
3301 s = oper.ToString ();
3311 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3313 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3316 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3318 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3322 l = left.Type.GetSignatureForError ();
3323 r = right.Type.GetSignatureForError ();
3325 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3329 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3331 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3334 public override void FlowAnalysis (FlowAnalysisContext fc)
3337 // Optimized version when on-true/on-false data are not needed
3339 if ((oper & Operator.LogicalMask) == 0) {
3340 left.FlowAnalysis (fc);
3341 right.FlowAnalysis (fc);
3345 left.FlowAnalysisConditional (fc);
3346 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3347 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3349 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3350 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3351 right.FlowAnalysisConditional (fc);
3353 if (oper == Operator.LogicalOr)
3354 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3356 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3359 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3361 if ((oper & Operator.LogicalMask) == 0) {
3362 base.FlowAnalysisConditional (fc);
3366 left.FlowAnalysisConditional (fc);
3367 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3368 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3370 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3371 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3372 right.FlowAnalysisConditional (fc);
3374 var lc = left as Constant;
3375 if (oper == Operator.LogicalOr) {
3376 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3377 if (lc != null && lc.IsDefaultValue)
3378 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3380 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3382 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3383 if (lc != null && !lc.IsDefaultValue)
3384 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3386 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3391 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3393 string GetOperatorExpressionTypeName ()
3396 case Operator.Addition:
3397 return IsCompound ? "AddAssign" : "Add";
3398 case Operator.BitwiseAnd:
3399 return IsCompound ? "AndAssign" : "And";
3400 case Operator.BitwiseOr:
3401 return IsCompound ? "OrAssign" : "Or";
3402 case Operator.Division:
3403 return IsCompound ? "DivideAssign" : "Divide";
3404 case Operator.ExclusiveOr:
3405 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3406 case Operator.Equality:
3408 case Operator.GreaterThan:
3409 return "GreaterThan";
3410 case Operator.GreaterThanOrEqual:
3411 return "GreaterThanOrEqual";
3412 case Operator.Inequality:
3414 case Operator.LeftShift:
3415 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3416 case Operator.LessThan:
3418 case Operator.LessThanOrEqual:
3419 return "LessThanOrEqual";
3420 case Operator.LogicalAnd:
3422 case Operator.LogicalOr:
3424 case Operator.Modulus:
3425 return IsCompound ? "ModuloAssign" : "Modulo";
3426 case Operator.Multiply:
3427 return IsCompound ? "MultiplyAssign" : "Multiply";
3428 case Operator.RightShift:
3429 return IsCompound ? "RightShiftAssign" : "RightShift";
3430 case Operator.Subtraction:
3431 return IsCompound ? "SubtractAssign" : "Subtract";
3433 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3437 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3440 case Operator.Addition:
3441 return CSharp.Operator.OpType.Addition;
3442 case Operator.BitwiseAnd:
3443 case Operator.LogicalAnd:
3444 return CSharp.Operator.OpType.BitwiseAnd;
3445 case Operator.BitwiseOr:
3446 case Operator.LogicalOr:
3447 return CSharp.Operator.OpType.BitwiseOr;
3448 case Operator.Division:
3449 return CSharp.Operator.OpType.Division;
3450 case Operator.Equality:
3451 return CSharp.Operator.OpType.Equality;
3452 case Operator.ExclusiveOr:
3453 return CSharp.Operator.OpType.ExclusiveOr;
3454 case Operator.GreaterThan:
3455 return CSharp.Operator.OpType.GreaterThan;
3456 case Operator.GreaterThanOrEqual:
3457 return CSharp.Operator.OpType.GreaterThanOrEqual;
3458 case Operator.Inequality:
3459 return CSharp.Operator.OpType.Inequality;
3460 case Operator.LeftShift:
3461 return CSharp.Operator.OpType.LeftShift;
3462 case Operator.LessThan:
3463 return CSharp.Operator.OpType.LessThan;
3464 case Operator.LessThanOrEqual:
3465 return CSharp.Operator.OpType.LessThanOrEqual;
3466 case Operator.Modulus:
3467 return CSharp.Operator.OpType.Modulus;
3468 case Operator.Multiply:
3469 return CSharp.Operator.OpType.Multiply;
3470 case Operator.RightShift:
3471 return CSharp.Operator.OpType.RightShift;
3472 case Operator.Subtraction:
3473 return CSharp.Operator.OpType.Subtraction;
3475 throw new InternalErrorException (op.ToString ());
3479 public override bool ContainsEmitWithAwait ()
3481 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3484 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3489 case Operator.Multiply:
3490 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3491 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3492 opcode = OpCodes.Mul_Ovf;
3493 else if (!IsFloat (l))
3494 opcode = OpCodes.Mul_Ovf_Un;
3496 opcode = OpCodes.Mul;
3498 opcode = OpCodes.Mul;
3502 case Operator.Division:
3504 opcode = OpCodes.Div_Un;
3506 opcode = OpCodes.Div;
3509 case Operator.Modulus:
3511 opcode = OpCodes.Rem_Un;
3513 opcode = OpCodes.Rem;
3516 case Operator.Addition:
3517 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3518 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3519 opcode = OpCodes.Add_Ovf;
3520 else if (!IsFloat (l))
3521 opcode = OpCodes.Add_Ovf_Un;
3523 opcode = OpCodes.Add;
3525 opcode = OpCodes.Add;
3528 case Operator.Subtraction:
3529 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3530 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3531 opcode = OpCodes.Sub_Ovf;
3532 else if (!IsFloat (l))
3533 opcode = OpCodes.Sub_Ovf_Un;
3535 opcode = OpCodes.Sub;
3537 opcode = OpCodes.Sub;
3540 case Operator.RightShift:
3541 if (!(right is IntConstant)) {
3542 ec.EmitInt (GetShiftMask (l));
3543 ec.Emit (OpCodes.And);
3547 opcode = OpCodes.Shr_Un;
3549 opcode = OpCodes.Shr;
3552 case Operator.LeftShift:
3553 if (!(right is IntConstant)) {
3554 ec.EmitInt (GetShiftMask (l));
3555 ec.Emit (OpCodes.And);
3558 opcode = OpCodes.Shl;
3561 case Operator.Equality:
3562 opcode = OpCodes.Ceq;
3565 case Operator.Inequality:
3566 ec.Emit (OpCodes.Ceq);
3569 opcode = OpCodes.Ceq;
3572 case Operator.LessThan:
3574 opcode = OpCodes.Clt_Un;
3576 opcode = OpCodes.Clt;
3579 case Operator.GreaterThan:
3581 opcode = OpCodes.Cgt_Un;
3583 opcode = OpCodes.Cgt;
3586 case Operator.LessThanOrEqual:
3587 if (IsUnsigned (l) || IsFloat (l))
3588 ec.Emit (OpCodes.Cgt_Un);
3590 ec.Emit (OpCodes.Cgt);
3593 opcode = OpCodes.Ceq;
3596 case Operator.GreaterThanOrEqual:
3597 if (IsUnsigned (l) || IsFloat (l))
3598 ec.Emit (OpCodes.Clt_Un);
3600 ec.Emit (OpCodes.Clt);
3604 opcode = OpCodes.Ceq;
3607 case Operator.BitwiseOr:
3608 opcode = OpCodes.Or;
3611 case Operator.BitwiseAnd:
3612 opcode = OpCodes.And;
3615 case Operator.ExclusiveOr:
3616 opcode = OpCodes.Xor;
3620 throw new InternalErrorException (oper.ToString ());
3626 static int GetShiftMask (TypeSpec type)
3628 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3631 static bool IsUnsigned (TypeSpec t)
3633 switch (t.BuiltinType) {
3634 case BuiltinTypeSpec.Type.Char:
3635 case BuiltinTypeSpec.Type.UInt:
3636 case BuiltinTypeSpec.Type.ULong:
3637 case BuiltinTypeSpec.Type.UShort:
3638 case BuiltinTypeSpec.Type.Byte:
3645 static bool IsFloat (TypeSpec t)
3647 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3650 public Expression ResolveOperator (ResolveContext rc)
3652 eclass = ExprClass.Value;
3654 TypeSpec l = left.Type;
3655 TypeSpec r = right.Type;
3657 bool primitives_only = false;
3660 // Handles predefined primitive types
3662 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3663 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3664 if ((oper & Operator.ShiftMask) == 0) {
3665 if (!DoBinaryOperatorPromotion (rc))
3668 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3672 if (l.IsPointer || r.IsPointer)
3673 return ResolveOperatorPointer (rc, l, r);
3676 if ((state & State.UserOperatorsExcluded) == 0) {
3677 expr = ResolveUserOperator (rc, left, right);
3682 bool lenum = l.IsEnum;
3683 bool renum = r.IsEnum;
3684 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3688 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3689 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3694 if ((oper & Operator.BitwiseMask) != 0) {
3695 expr = EmptyCast.Create (expr, type);
3696 enum_conversion = GetEnumResultCast (type);
3698 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3699 expr = OptimizeAndOperation (expr);
3703 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3704 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3707 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3708 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3712 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3715 // We cannot break here there is also Enum + String possible match
3716 // which is not ambiguous with predefined enum operators
3719 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3720 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3724 } else if (l.IsDelegate || r.IsDelegate) {
3728 expr = ResolveOperatorDelegate (rc, l, r);
3730 // TODO: Can this be ambiguous
3738 // Equality operators are more complicated
3740 if ((oper & Operator.EqualityMask) != 0) {
3741 return ResolveEquality (rc, l, r, primitives_only);
3744 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3748 if (primitives_only)
3752 // Lifted operators have lower priority
3754 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3757 static bool IsEnumOrNullableEnum (TypeSpec type)
3759 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3763 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3764 // if 'left' is not an enumeration constant, create one from the type of 'right'
3765 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3768 case Operator.BitwiseOr:
3769 case Operator.BitwiseAnd:
3770 case Operator.ExclusiveOr:
3771 case Operator.Equality:
3772 case Operator.Inequality:
3773 case Operator.LessThan:
3774 case Operator.LessThanOrEqual:
3775 case Operator.GreaterThan:
3776 case Operator.GreaterThanOrEqual:
3777 if (left.Type.IsEnum)
3780 if (left.IsZeroInteger)
3781 return left.Reduce (ec, right.Type);
3785 case Operator.Addition:
3786 case Operator.Subtraction:
3789 case Operator.Multiply:
3790 case Operator.Division:
3791 case Operator.Modulus:
3792 case Operator.LeftShift:
3793 case Operator.RightShift:
3794 if (right.Type.IsEnum || left.Type.IsEnum)
3803 // The `|' operator used on types which were extended is dangerous
3805 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3807 OpcodeCast lcast = left as OpcodeCast;
3808 if (lcast != null) {
3809 if (IsUnsigned (lcast.UnderlyingType))
3813 OpcodeCast rcast = right as OpcodeCast;
3814 if (rcast != null) {
3815 if (IsUnsigned (rcast.UnderlyingType))
3819 if (lcast == null && rcast == null)
3822 // FIXME: consider constants
3824 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3825 ec.Report.Warning (675, 3, loc,
3826 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3827 ltype.GetSignatureForError ());
3830 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3832 return new PredefinedOperator[] {
3834 // Pointer arithmetic:
3836 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3837 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3838 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3839 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3841 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3842 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3843 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3844 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3847 // T* operator + (int y, T* x);
3848 // T* operator + (uint y, T *x);
3849 // T* operator + (long y, T *x);
3850 // T* operator + (ulong y, T *x);
3852 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3853 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3854 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3855 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3858 // long operator - (T* x, T *y)
3860 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3864 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3866 TypeSpec bool_type = types.Bool;
3869 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3870 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3871 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3872 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3873 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3874 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3875 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3877 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3878 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3879 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3880 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3881 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3882 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3883 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3885 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3886 // Remaining string operators are in lifted tables
3888 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3890 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3891 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3892 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3896 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3898 var types = module.Compiler.BuiltinTypes;
3901 // Not strictly lifted but need to be in second group otherwise expressions like
3902 // int + null would resolve to +(object, string) instead of +(int?, int?)
3904 var string_operators = new [] {
3905 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3906 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3909 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3910 if (nullable == null)
3911 return string_operators;
3913 var bool_type = types.Bool;
3915 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3916 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3917 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3918 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3919 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3920 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3921 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3922 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3925 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3926 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3927 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3928 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3929 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3930 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3931 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3933 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3934 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3935 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3936 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3937 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3938 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3939 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3941 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3943 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3944 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3945 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3947 string_operators [0],
3948 string_operators [1]
3952 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3954 TypeSpec bool_type = types.Bool;
3957 new PredefinedEqualityOperator (types.String, bool_type),
3958 new PredefinedEqualityOperator (types.Delegate, bool_type),
3959 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3960 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3961 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3962 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3963 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3964 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3965 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3966 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3970 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3972 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3974 if (nullable == null)
3975 return new PredefinedOperator [0];
3977 var types = module.Compiler.BuiltinTypes;
3978 var bool_type = types.Bool;
3979 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3980 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3981 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3982 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3983 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3984 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3985 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3986 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3989 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3990 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3991 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3992 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3993 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3994 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3995 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3996 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4001 // 7.2.6.2 Binary numeric promotions
4003 bool DoBinaryOperatorPromotion (ResolveContext rc)
4005 TypeSpec ltype = left.Type;
4006 if (ltype.IsNullableType) {
4007 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4011 // This is numeric promotion code only
4013 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4016 TypeSpec rtype = right.Type;
4017 if (rtype.IsNullableType) {
4018 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4021 var lb = ltype.BuiltinType;
4022 var rb = rtype.BuiltinType;
4026 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4027 type = rc.BuiltinTypes.Decimal;
4028 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4029 type = rc.BuiltinTypes.Double;
4030 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4031 type = rc.BuiltinTypes.Float;
4032 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4033 type = rc.BuiltinTypes.ULong;
4035 if (IsSignedType (lb)) {
4036 expr = ConvertSignedConstant (left, type);
4040 } else if (IsSignedType (rb)) {
4041 expr = ConvertSignedConstant (right, type);
4047 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4048 type = rc.BuiltinTypes.Long;
4049 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4050 type = rc.BuiltinTypes.UInt;
4052 if (IsSignedType (lb)) {
4053 expr = ConvertSignedConstant (left, type);
4055 type = rc.BuiltinTypes.Long;
4056 } else if (IsSignedType (rb)) {
4057 expr = ConvertSignedConstant (right, type);
4059 type = rc.BuiltinTypes.Long;
4062 type = rc.BuiltinTypes.Int;
4065 if (ltype != type) {
4066 expr = PromoteExpression (rc, left, type);
4073 if (rtype != type) {
4074 expr = PromoteExpression (rc, right, type);
4084 static bool IsSignedType (BuiltinTypeSpec.Type type)
4087 case BuiltinTypeSpec.Type.Int:
4088 case BuiltinTypeSpec.Type.Short:
4089 case BuiltinTypeSpec.Type.SByte:
4090 case BuiltinTypeSpec.Type.Long:
4097 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4099 var c = expr as Constant;
4103 return c.ConvertImplicitly (type);
4106 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4108 if (expr.Type.IsNullableType) {
4109 return Convert.ImplicitConversionStandard (rc, expr,
4110 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4113 var c = expr as Constant;
4115 return c.ConvertImplicitly (type);
4117 return Convert.ImplicitNumericConversion (expr, type);
4120 protected override Expression DoResolve (ResolveContext ec)
4125 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4126 left = ((ParenthesizedExpression) left).Expr;
4127 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4131 if (left.eclass == ExprClass.Type) {
4132 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4136 left = left.Resolve (ec);
4141 right = right.Resolve (ec);
4145 Constant lc = left as Constant;
4146 Constant rc = right as Constant;
4148 // The conversion rules are ignored in enum context but why
4149 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4150 lc = EnumLiftUp (ec, lc, rc);
4152 rc = EnumLiftUp (ec, rc, lc);
4155 if (rc != null && lc != null) {
4156 int prev_e = ec.Report.Errors;
4157 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4158 if (e != null || ec.Report.Errors != prev_e)
4162 // Comparison warnings
4163 if ((oper & Operator.ComparisonMask) != 0) {
4164 if (left.Equals (right)) {
4165 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4167 CheckOutOfRangeComparison (ec, lc, right.Type);
4168 CheckOutOfRangeComparison (ec, rc, left.Type);
4171 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4172 return DoResolveDynamic (ec);
4174 return DoResolveCore (ec, left, right);
4177 Expression DoResolveDynamic (ResolveContext rc)
4180 var rt = right.Type;
4181 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4182 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4183 Error_OperatorCannotBeApplied (rc, left, right);
4190 // Special handling for logical boolean operators which require rhs not to be
4191 // evaluated based on lhs value
4193 if ((oper & Operator.LogicalMask) != 0) {
4194 Expression cond_left, cond_right, expr;
4196 args = new Arguments (2);
4198 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4199 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4201 var cond_args = new Arguments (1);
4202 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4205 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4206 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4208 left = temp.CreateReferenceExpression (rc, loc);
4209 if (oper == Operator.LogicalAnd) {
4210 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4213 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4217 args.Add (new Argument (left));
4218 args.Add (new Argument (right));
4219 cond_right = new DynamicExpressionStatement (this, args, loc);
4221 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4223 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4224 rc.Report.Error (7083, left.Location,
4225 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4226 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4230 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4231 args.Add (new Argument (right));
4232 right = new DynamicExpressionStatement (this, args, loc);
4235 // bool && dynamic => (temp = left) ? temp && right : temp;
4236 // bool || dynamic => (temp = left) ? temp : temp || right;
4238 if (oper == Operator.LogicalAnd) {
4240 cond_right = temp.CreateReferenceExpression (rc, loc);
4242 cond_left = temp.CreateReferenceExpression (rc, loc);
4246 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4249 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4252 args = new Arguments (2);
4253 args.Add (new Argument (left));
4254 args.Add (new Argument (right));
4255 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4258 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4260 Expression expr = ResolveOperator (ec);
4262 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4264 if (left == null || right == null)
4265 throw new InternalErrorException ("Invalid conversion");
4267 if (oper == Operator.BitwiseOr)
4268 CheckBitwiseOrOnSignExtended (ec);
4273 public override SLE.Expression MakeExpression (BuilderContext ctx)
4275 return MakeExpression (ctx, left, right);
4278 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4280 var le = left.MakeExpression (ctx);
4281 var re = right.MakeExpression (ctx);
4282 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4285 case Operator.Addition:
4286 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4287 case Operator.BitwiseAnd:
4288 return SLE.Expression.And (le, re);
4289 case Operator.BitwiseOr:
4290 return SLE.Expression.Or (le, re);
4291 case Operator.Division:
4292 return SLE.Expression.Divide (le, re);
4293 case Operator.Equality:
4294 return SLE.Expression.Equal (le, re);
4295 case Operator.ExclusiveOr:
4296 return SLE.Expression.ExclusiveOr (le, re);
4297 case Operator.GreaterThan:
4298 return SLE.Expression.GreaterThan (le, re);
4299 case Operator.GreaterThanOrEqual:
4300 return SLE.Expression.GreaterThanOrEqual (le, re);
4301 case Operator.Inequality:
4302 return SLE.Expression.NotEqual (le, re);
4303 case Operator.LeftShift:
4304 return SLE.Expression.LeftShift (le, re);
4305 case Operator.LessThan:
4306 return SLE.Expression.LessThan (le, re);
4307 case Operator.LessThanOrEqual:
4308 return SLE.Expression.LessThanOrEqual (le, re);
4309 case Operator.LogicalAnd:
4310 return SLE.Expression.AndAlso (le, re);
4311 case Operator.LogicalOr:
4312 return SLE.Expression.OrElse (le, re);
4313 case Operator.Modulus:
4314 return SLE.Expression.Modulo (le, re);
4315 case Operator.Multiply:
4316 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4317 case Operator.RightShift:
4318 return SLE.Expression.RightShift (le, re);
4319 case Operator.Subtraction:
4320 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4322 throw new NotImplementedException (oper.ToString ());
4327 // D operator + (D x, D y)
4328 // D operator - (D x, D y)
4330 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4332 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4334 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4335 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4340 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4341 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4351 MethodSpec method = null;
4352 Arguments args = new Arguments (2);
4353 args.Add (new Argument (left));
4354 args.Add (new Argument (right));
4356 if (oper == Operator.Addition) {
4357 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4358 } else if (oper == Operator.Subtraction) {
4359 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4363 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4365 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4366 return new ClassCast (expr, l);
4370 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4372 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4375 // bool operator == (E x, E y);
4376 // bool operator != (E x, E y);
4377 // bool operator < (E x, E y);
4378 // bool operator > (E x, E y);
4379 // bool operator <= (E x, E y);
4380 // bool operator >= (E x, E y);
4382 // E operator & (E x, E y);
4383 // E operator | (E x, E y);
4384 // E operator ^ (E x, E y);
4387 if ((oper & Operator.ComparisonMask) != 0) {
4388 type = rc.BuiltinTypes.Bool;
4394 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4400 if (ltype == rtype) {
4404 var lifted = new Nullable.LiftedBinaryOperator (this);
4406 lifted.Right = right;
4407 return lifted.Resolve (rc);
4410 if (renum && !ltype.IsNullableType) {
4411 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4416 } else if (lenum && !rtype.IsNullableType) {
4417 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4425 // Now try lifted version of predefined operator
4427 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4428 if (nullable_type != null) {
4429 if (renum && !ltype.IsNullableType) {
4430 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4432 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4435 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4438 if ((oper & Operator.BitwiseMask) != 0)
4442 if ((oper & Operator.BitwiseMask) != 0)
4443 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4445 return CreateLiftedValueTypeResult (rc, rtype);
4449 var lifted = new Nullable.LiftedBinaryOperator (this);
4451 lifted.Right = right;
4452 return lifted.Resolve (rc);
4454 } else if (lenum && !rtype.IsNullableType) {
4455 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4457 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4460 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4463 if ((oper & Operator.BitwiseMask) != 0)
4467 if ((oper & Operator.BitwiseMask) != 0)
4468 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4470 return CreateLiftedValueTypeResult (rc, ltype);
4474 var lifted = new Nullable.LiftedBinaryOperator (this);
4476 lifted.Right = expr;
4477 return lifted.Resolve (rc);
4479 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4480 Nullable.Unwrap unwrap = null;
4481 if (left.IsNull || right.IsNull) {
4482 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4483 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4485 if ((oper & Operator.RelationalMask) != 0)
4486 return CreateLiftedValueTypeResult (rc, rtype);
4488 if ((oper & Operator.BitwiseMask) != 0)
4489 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4492 return CreateLiftedValueTypeResult (rc, left.Type);
4494 // Equality operators are valid between E? and null
4496 unwrap = new Nullable.Unwrap (right);
4498 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4504 var lifted = new Nullable.LiftedBinaryOperator (this);
4506 lifted.Right = right;
4507 lifted.UnwrapRight = unwrap;
4508 return lifted.Resolve (rc);
4510 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4511 Nullable.Unwrap unwrap = null;
4512 if (right.IsNull || left.IsNull) {
4513 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4514 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4516 if ((oper & Operator.RelationalMask) != 0)
4517 return CreateLiftedValueTypeResult (rc, ltype);
4519 if ((oper & Operator.BitwiseMask) != 0)
4520 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4523 return CreateLiftedValueTypeResult (rc, right.Type);
4525 // Equality operators are valid between E? and null
4527 unwrap = new Nullable.Unwrap (left);
4529 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4535 var lifted = new Nullable.LiftedBinaryOperator (this);
4537 lifted.UnwrapLeft = unwrap;
4538 lifted.Right = expr;
4539 return lifted.Resolve (rc);
4547 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4549 TypeSpec underlying_type;
4550 if (expr.Type.IsNullableType) {
4551 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4553 underlying_type = EnumSpec.GetUnderlyingType (nt);
4555 underlying_type = nt;
4556 } else if (expr.Type.IsEnum) {
4557 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4559 underlying_type = expr.Type;
4562 switch (underlying_type.BuiltinType) {
4563 case BuiltinTypeSpec.Type.SByte:
4564 case BuiltinTypeSpec.Type.Byte:
4565 case BuiltinTypeSpec.Type.Short:
4566 case BuiltinTypeSpec.Type.UShort:
4567 underlying_type = rc.BuiltinTypes.Int;
4571 if (expr.Type.IsNullableType || liftType)
4572 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4574 if (expr.Type == underlying_type)
4577 return EmptyCast.Create (expr, underlying_type);
4580 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4583 // U operator - (E e, E f)
4584 // E operator - (E e, U x) // Internal decomposition operator
4585 // E operator - (U x, E e) // Internal decomposition operator
4587 // E operator + (E e, U x)
4588 // E operator + (U x, E e)
4597 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4603 if (!enum_type.IsNullableType) {
4604 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4606 if (oper == Operator.Subtraction)
4607 expr = ConvertEnumSubtractionResult (rc, expr);
4609 expr = ConvertEnumAdditionalResult (expr, enum_type);
4611 enum_conversion = GetEnumResultCast (expr.Type);
4616 var nullable = rc.Module.PredefinedTypes.Nullable;
4619 // Don't try nullable version when nullable type is undefined
4621 if (!nullable.IsDefined)
4624 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4627 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4629 if (oper == Operator.Subtraction)
4630 expr = ConvertEnumSubtractionResult (rc, expr);
4632 expr = ConvertEnumAdditionalResult (expr, enum_type);
4634 enum_conversion = GetEnumResultCast (expr.Type);
4640 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4642 return EmptyCast.Create (expr, enumType);
4645 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4648 // Enumeration subtraction has different result type based on
4651 TypeSpec result_type;
4652 if (left.Type == right.Type) {
4653 var c = right as EnumConstant;
4654 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4656 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4657 // E which is not what expressions E - 1 or 0 - E return
4659 result_type = left.Type;
4661 result_type = left.Type.IsNullableType ?
4662 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4663 EnumSpec.GetUnderlyingType (left.Type);
4666 if (IsEnumOrNullableEnum (left.Type)) {
4667 result_type = left.Type;
4669 result_type = right.Type;
4672 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4673 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4676 return EmptyCast.Create (expr, result_type);
4679 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4681 if (type.IsNullableType)
4682 type = Nullable.NullableInfo.GetUnderlyingType (type);
4685 type = EnumSpec.GetUnderlyingType (type);
4687 switch (type.BuiltinType) {
4688 case BuiltinTypeSpec.Type.SByte:
4689 return ConvCast.Mode.I4_I1;
4690 case BuiltinTypeSpec.Type.Byte:
4691 return ConvCast.Mode.I4_U1;
4692 case BuiltinTypeSpec.Type.Short:
4693 return ConvCast.Mode.I4_I2;
4694 case BuiltinTypeSpec.Type.UShort:
4695 return ConvCast.Mode.I4_U2;
4702 // Equality operators rules
4704 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4707 type = ec.BuiltinTypes.Bool;
4708 bool no_arg_conv = false;
4710 if (!primitives_only) {
4713 // a, Both operands are reference-type values or the value null
4714 // b, One operand is a value of type T where T is a type-parameter and
4715 // the other operand is the value null. Furthermore T does not have the
4716 // value type constraint
4718 // LAMESPEC: Very confusing details in the specification, basically any
4719 // reference like type-parameter is allowed
4721 var tparam_l = l as TypeParameterSpec;
4722 var tparam_r = r as TypeParameterSpec;
4723 if (tparam_l != null) {
4724 if (right is NullLiteral) {
4725 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4728 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4732 if (!tparam_l.IsReferenceType)
4735 l = tparam_l.GetEffectiveBase ();
4736 left = new BoxedCast (left, l);
4737 } else if (left is NullLiteral && tparam_r == null) {
4738 if (TypeSpec.IsReferenceType (r))
4741 if (r.Kind == MemberKind.InternalCompilerType)
4745 if (tparam_r != null) {
4746 if (left is NullLiteral) {
4747 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4750 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4754 if (!tparam_r.IsReferenceType)
4757 r = tparam_r.GetEffectiveBase ();
4758 right = new BoxedCast (right, r);
4759 } else if (right is NullLiteral) {
4760 if (TypeSpec.IsReferenceType (l))
4763 if (l.Kind == MemberKind.InternalCompilerType)
4768 // LAMESPEC: method groups can be compared when they convert to other side delegate
4771 if (right.eclass == ExprClass.MethodGroup) {
4772 result = Convert.ImplicitConversion (ec, right, l, loc);
4778 } else if (r.IsDelegate && l != r) {
4781 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4782 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4789 no_arg_conv = l == r && !l.IsStruct;
4794 // bool operator != (string a, string b)
4795 // bool operator == (string a, string b)
4797 // bool operator != (Delegate a, Delegate b)
4798 // bool operator == (Delegate a, Delegate b)
4800 // bool operator != (bool a, bool b)
4801 // bool operator == (bool a, bool b)
4803 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4804 // they implement an implicit conversion to any of types above. This does
4805 // not apply when both operands are of same reference type
4807 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4808 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4813 // Now try lifted version of predefined operators
4815 if (no_arg_conv && !l.IsNullableType) {
4817 // Optimizes cases which won't match
4820 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4826 // The == and != operators permit one operand to be a value of a nullable
4827 // type and the other to be the null literal, even if no predefined or user-defined
4828 // operator (in unlifted or lifted form) exists for the operation.
4830 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4831 var lifted = new Nullable.LiftedBinaryOperator (this);
4833 lifted.Right = right;
4834 return lifted.Resolve (ec);
4839 // bool operator != (object a, object b)
4840 // bool operator == (object a, object b)
4842 // An explicit reference conversion exists from the
4843 // type of either operand to the type of the other operand.
4846 // Optimize common path
4848 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4851 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4852 !Convert.ExplicitReferenceConversionExists (r, l))
4855 // Reject allowed explicit conversions like int->object
4856 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4859 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4860 ec.Report.Warning (253, 2, loc,
4861 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4862 l.GetSignatureForError ());
4864 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4865 ec.Report.Warning (252, 2, loc,
4866 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4867 r.GetSignatureForError ());
4873 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4876 // bool operator == (void* x, void* y);
4877 // bool operator != (void* x, void* y);
4878 // bool operator < (void* x, void* y);
4879 // bool operator > (void* x, void* y);
4880 // bool operator <= (void* x, void* y);
4881 // bool operator >= (void* x, void* y);
4883 if ((oper & Operator.ComparisonMask) != 0) {
4886 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4893 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4899 type = ec.BuiltinTypes.Bool;
4903 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4907 // Build-in operators method overloading
4909 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4911 PredefinedOperator best_operator = null;
4912 TypeSpec l = left.Type;
4913 TypeSpec r = right.Type;
4914 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4916 foreach (PredefinedOperator po in operators) {
4917 if ((po.OperatorsMask & oper_mask) == 0)
4920 if (primitives_only) {
4921 if (!po.IsPrimitiveApplicable (l, r))
4924 if (!po.IsApplicable (ec, left, right))
4928 if (best_operator == null) {
4930 if (primitives_only)
4936 best_operator = po.ResolveBetterOperator (ec, best_operator);
4938 if (best_operator == null) {
4939 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4940 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4947 if (best_operator == null)
4950 return best_operator.ConvertResult (ec, this);
4954 // Optimize & constant expressions with 0 value
4956 Expression OptimizeAndOperation (Expression expr)
4958 Constant rc = right as Constant;
4959 Constant lc = left as Constant;
4960 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4962 // The result is a constant with side-effect
4964 Constant side_effect = rc == null ?
4965 new SideEffectConstant (lc, right, loc) :
4966 new SideEffectConstant (rc, left, loc);
4968 return ReducedExpression.Create (side_effect, expr);
4975 // Value types can be compared with the null literal because of the lifting
4976 // language rules. However the result is always true or false.
4978 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4980 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4981 type = rc.BuiltinTypes.Bool;
4985 // FIXME: Handle side effect constants
4986 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4988 if ((Oper & Operator.EqualityMask) != 0) {
4989 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4990 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4992 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4993 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5000 // Performs user-operator overloading
5002 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5004 Expression oper_expr;
5006 var op = ConvertBinaryToUserOperator (oper);
5008 if (l.IsNullableType)
5009 l = Nullable.NullableInfo.GetUnderlyingType (l);
5011 if (r.IsNullableType)
5012 r = Nullable.NullableInfo.GetUnderlyingType (r);
5014 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5015 IList<MemberSpec> right_operators = null;
5018 right_operators = MemberCache.GetUserOperator (r, op, false);
5019 if (right_operators == null && left_operators == null)
5021 } else if (left_operators == null) {
5025 Arguments args = new Arguments (2);
5026 Argument larg = new Argument (left);
5028 Argument rarg = new Argument (right);
5032 // User-defined operator implementations always take precedence
5033 // over predefined operator implementations
5035 if (left_operators != null && right_operators != null) {
5036 left_operators = CombineUserOperators (left_operators, right_operators);
5037 } else if (right_operators != null) {
5038 left_operators = right_operators;
5041 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5042 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5044 var res = new OverloadResolver (left_operators, restr, loc);
5046 var oper_method = res.ResolveOperator (rc, ref args);
5047 if (oper_method == null) {
5049 // Logical && and || cannot be lifted
5051 if ((oper & Operator.LogicalMask) != 0)
5055 // Apply lifted user operators only for liftable types. Implicit conversion
5056 // to nullable types is not allowed
5058 if (!IsLiftedOperatorApplicable ())
5061 // TODO: Cache the result in module container
5062 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5063 if (lifted_methods == null)
5066 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5068 oper_method = res.ResolveOperator (rc, ref args);
5069 if (oper_method == null)
5072 MethodSpec best_original = null;
5073 foreach (MethodSpec ms in left_operators) {
5074 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5080 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5082 // Expression trees use lifted notation in this case
5084 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5085 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5088 var ptypes = best_original.Parameters.Types;
5090 if (left.IsNull || right.IsNull) {
5092 // The lifted operator produces a null value if one or both operands are null
5094 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5095 type = oper_method.ReturnType;
5096 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5100 // The lifted operator produces the value false if one or both operands are null for
5101 // relational operators.
5103 if ((oper & Operator.RelationalMask) != 0) {
5105 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5106 // because return type is actually bool
5108 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5111 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5112 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5116 type = oper_method.ReturnType;
5117 var lifted = new Nullable.LiftedBinaryOperator (this);
5118 lifted.UserOperator = best_original;
5120 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5121 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5124 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5125 lifted.UnwrapRight = new Nullable.Unwrap (right);
5128 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5129 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5131 return lifted.Resolve (rc);
5134 if ((oper & Operator.LogicalMask) != 0) {
5135 // TODO: CreateExpressionTree is allocated every time
5136 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5137 oper == Operator.LogicalAnd, loc).Resolve (rc);
5139 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5142 this.left = larg.Expr;
5143 this.right = rarg.Expr;
5148 bool IsLiftedOperatorApplicable ()
5150 if (left.Type.IsNullableType) {
5151 if ((oper & Operator.EqualityMask) != 0)
5152 return !right.IsNull;
5157 if (right.Type.IsNullableType) {
5158 if ((oper & Operator.EqualityMask) != 0)
5159 return !left.IsNull;
5164 if (TypeSpec.IsValueType (left.Type))
5165 return right.IsNull;
5167 if (TypeSpec.IsValueType (right.Type))
5173 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5175 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5176 if (nullable_type == null)
5180 // Lifted operators permit predefined and user-defined operators that operate
5181 // on non-nullable value types to also be used with nullable forms of those types.
5182 // Lifted operators are constructed from predefined and user-defined operators
5183 // that meet certain requirements
5185 List<MemberSpec> lifted = null;
5186 foreach (MethodSpec oper in operators) {
5188 if ((Oper & Operator.ComparisonMask) != 0) {
5190 // Result type must be of type bool for lifted comparison operators
5192 rt = oper.ReturnType;
5193 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5196 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5202 var ptypes = oper.Parameters.Types;
5203 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5207 // LAMESPEC: I am not sure why but for equality operators to be lifted
5208 // both types have to match
5210 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5214 lifted = new List<MemberSpec> ();
5217 // The lifted form is constructed by adding a single ? modifier to each operand and
5218 // result type except for comparison operators where return type is bool
5221 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5223 var parameters = ParametersCompiled.CreateFullyResolved (
5224 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5225 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5227 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5228 rt, parameters, oper.Modifiers);
5230 lifted.Add (lifted_op);
5237 // Merge two sets of user operators into one, they are mostly distinguish
5238 // except when they share base type and it contains an operator
5240 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5242 var combined = new List<MemberSpec> (left.Count + right.Count);
5243 combined.AddRange (left);
5244 foreach (var r in right) {
5246 foreach (var l in left) {
5247 if (l.DeclaringType == r.DeclaringType) {
5260 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5262 if (c is IntegralConstant || c is CharConstant) {
5264 c.ConvertExplicitly (true, type);
5265 } catch (OverflowException) {
5266 ec.Report.Warning (652, 2, loc,
5267 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5268 type.GetSignatureForError ());
5274 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5275 /// context of a conditional bool expression. This function will return
5276 /// false if it is was possible to use EmitBranchable, or true if it was.
5278 /// The expression's code is generated, and we will generate a branch to `target'
5279 /// if the resulting expression value is equal to isTrue
5281 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5283 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5284 left = left.EmitToField (ec);
5286 if ((oper & Operator.LogicalMask) == 0) {
5287 right = right.EmitToField (ec);
5292 // This is more complicated than it looks, but its just to avoid
5293 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5294 // but on top of that we want for == and != to use a special path
5295 // if we are comparing against null
5297 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5298 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5301 // put the constant on the rhs, for simplicity
5303 if (left is Constant) {
5304 Expression swap = right;
5310 // brtrue/brfalse works with native int only
5312 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5313 left.EmitBranchable (ec, target, my_on_true);
5316 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5317 // right is a boolean, and it's not 'false' => it is 'true'
5318 left.EmitBranchable (ec, target, !my_on_true);
5322 } else if (oper == Operator.LogicalAnd) {
5325 Label tests_end = ec.DefineLabel ();
5327 left.EmitBranchable (ec, tests_end, false);
5328 right.EmitBranchable (ec, target, true);
5329 ec.MarkLabel (tests_end);
5332 // This optimizes code like this
5333 // if (true && i > 4)
5335 if (!(left is Constant))
5336 left.EmitBranchable (ec, target, false);
5338 if (!(right is Constant))
5339 right.EmitBranchable (ec, target, false);
5344 } else if (oper == Operator.LogicalOr){
5346 left.EmitBranchable (ec, target, true);
5347 right.EmitBranchable (ec, target, true);
5350 Label tests_end = ec.DefineLabel ();
5351 left.EmitBranchable (ec, tests_end, true);
5352 right.EmitBranchable (ec, target, false);
5353 ec.MarkLabel (tests_end);
5358 } else if ((oper & Operator.ComparisonMask) == 0) {
5359 base.EmitBranchable (ec, target, on_true);
5366 TypeSpec t = left.Type;
5367 bool is_float = IsFloat (t);
5368 bool is_unsigned = is_float || IsUnsigned (t);
5371 case Operator.Equality:
5373 ec.Emit (OpCodes.Beq, target);
5375 ec.Emit (OpCodes.Bne_Un, target);
5378 case Operator.Inequality:
5380 ec.Emit (OpCodes.Bne_Un, target);
5382 ec.Emit (OpCodes.Beq, target);
5385 case Operator.LessThan:
5387 if (is_unsigned && !is_float)
5388 ec.Emit (OpCodes.Blt_Un, target);
5390 ec.Emit (OpCodes.Blt, target);
5393 ec.Emit (OpCodes.Bge_Un, target);
5395 ec.Emit (OpCodes.Bge, target);
5398 case Operator.GreaterThan:
5400 if (is_unsigned && !is_float)
5401 ec.Emit (OpCodes.Bgt_Un, target);
5403 ec.Emit (OpCodes.Bgt, target);
5406 ec.Emit (OpCodes.Ble_Un, target);
5408 ec.Emit (OpCodes.Ble, target);
5411 case Operator.LessThanOrEqual:
5413 if (is_unsigned && !is_float)
5414 ec.Emit (OpCodes.Ble_Un, target);
5416 ec.Emit (OpCodes.Ble, target);
5419 ec.Emit (OpCodes.Bgt_Un, target);
5421 ec.Emit (OpCodes.Bgt, target);
5425 case Operator.GreaterThanOrEqual:
5427 if (is_unsigned && !is_float)
5428 ec.Emit (OpCodes.Bge_Un, target);
5430 ec.Emit (OpCodes.Bge, target);
5433 ec.Emit (OpCodes.Blt_Un, target);
5435 ec.Emit (OpCodes.Blt, target);
5438 throw new InternalErrorException (oper.ToString ());
5442 public override void Emit (EmitContext ec)
5444 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5445 left = left.EmitToField (ec);
5447 if ((oper & Operator.LogicalMask) == 0) {
5448 right = right.EmitToField (ec);
5453 // Handle short-circuit operators differently
5456 if ((oper & Operator.LogicalMask) != 0) {
5457 Label load_result = ec.DefineLabel ();
5458 Label end = ec.DefineLabel ();
5460 bool is_or = oper == Operator.LogicalOr;
5461 left.EmitBranchable (ec, load_result, is_or);
5463 ec.Emit (OpCodes.Br_S, end);
5465 ec.MarkLabel (load_result);
5466 ec.EmitInt (is_or ? 1 : 0);
5472 // Optimize zero-based operations which cannot be optimized at expression level
5474 if (oper == Operator.Subtraction) {
5475 var lc = left as IntegralConstant;
5476 if (lc != null && lc.IsDefaultValue) {
5478 ec.Emit (OpCodes.Neg);
5483 EmitOperator (ec, left, right);
5486 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5491 EmitOperatorOpcode (ec, oper, left.Type, right);
5494 // Emit result enumerable conversion this way because it's quite complicated get it
5495 // to resolved tree because expression tree cannot see it.
5497 if (enum_conversion != 0)
5498 ConvCast.Emit (ec, enum_conversion);
5501 public override void EmitSideEffect (EmitContext ec)
5503 if ((oper & Operator.LogicalMask) != 0 ||
5504 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5505 base.EmitSideEffect (ec);
5507 left.EmitSideEffect (ec);
5508 right.EmitSideEffect (ec);
5512 public override Expression EmitToField (EmitContext ec)
5514 if ((oper & Operator.LogicalMask) == 0) {
5515 var await_expr = left as Await;
5516 if (await_expr != null && right.IsSideEffectFree) {
5517 await_expr.Statement.EmitPrologue (ec);
5518 left = await_expr.Statement.GetResultExpression (ec);
5522 await_expr = right as Await;
5523 if (await_expr != null && left.IsSideEffectFree) {
5524 await_expr.Statement.EmitPrologue (ec);
5525 right = await_expr.Statement.GetResultExpression (ec);
5530 return base.EmitToField (ec);
5533 protected override void CloneTo (CloneContext clonectx, Expression t)
5535 Binary target = (Binary) t;
5537 target.left = left.Clone (clonectx);
5538 target.right = right.Clone (clonectx);
5541 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5543 Arguments binder_args = new Arguments (4);
5545 MemberAccess sle = new MemberAccess (new MemberAccess (
5546 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5548 CSharpBinderFlags flags = 0;
5549 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5550 flags = CSharpBinderFlags.CheckedContext;
5552 if ((oper & Operator.LogicalMask) != 0)
5553 flags |= CSharpBinderFlags.BinaryOperationLogical;
5555 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5556 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5557 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5558 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5560 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5563 public override Expression CreateExpressionTree (ResolveContext ec)
5565 return CreateExpressionTree (ec, null);
5568 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5571 bool lift_arg = false;
5574 case Operator.Addition:
5575 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5576 method_name = "AddChecked";
5578 method_name = "Add";
5580 case Operator.BitwiseAnd:
5581 method_name = "And";
5583 case Operator.BitwiseOr:
5586 case Operator.Division:
5587 method_name = "Divide";
5589 case Operator.Equality:
5590 method_name = "Equal";
5593 case Operator.ExclusiveOr:
5594 method_name = "ExclusiveOr";
5596 case Operator.GreaterThan:
5597 method_name = "GreaterThan";
5600 case Operator.GreaterThanOrEqual:
5601 method_name = "GreaterThanOrEqual";
5604 case Operator.Inequality:
5605 method_name = "NotEqual";
5608 case Operator.LeftShift:
5609 method_name = "LeftShift";
5611 case Operator.LessThan:
5612 method_name = "LessThan";
5615 case Operator.LessThanOrEqual:
5616 method_name = "LessThanOrEqual";
5619 case Operator.LogicalAnd:
5620 method_name = "AndAlso";
5622 case Operator.LogicalOr:
5623 method_name = "OrElse";
5625 case Operator.Modulus:
5626 method_name = "Modulo";
5628 case Operator.Multiply:
5629 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5630 method_name = "MultiplyChecked";
5632 method_name = "Multiply";
5634 case Operator.RightShift:
5635 method_name = "RightShift";
5637 case Operator.Subtraction:
5638 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5639 method_name = "SubtractChecked";
5641 method_name = "Subtract";
5645 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5648 Arguments args = new Arguments (2);
5649 args.Add (new Argument (left.CreateExpressionTree (ec)));
5650 args.Add (new Argument (right.CreateExpressionTree (ec)));
5651 if (method != null) {
5653 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5655 args.Add (new Argument (method));
5658 return CreateExpressionFactoryCall (ec, method_name, args);
5661 public override object Accept (StructuralVisitor visitor)
5663 return visitor.Visit (this);
5669 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5670 // b, c, d... may be strings or objects.
5672 public class StringConcat : Expression
5674 Arguments arguments;
5676 StringConcat (Location loc)
5679 arguments = new Arguments (2);
5682 public override bool ContainsEmitWithAwait ()
5684 return arguments.ContainsEmitWithAwait ();
5687 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5689 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5690 throw new ArgumentException ();
5692 var s = new StringConcat (loc);
5693 s.type = rc.BuiltinTypes.String;
5694 s.eclass = ExprClass.Value;
5696 s.Append (rc, left);
5697 s.Append (rc, right);
5701 public override Expression CreateExpressionTree (ResolveContext ec)
5703 Argument arg = arguments [0];
5704 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5708 // Creates nested calls tree from an array of arguments used for IL emit
5710 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5712 Arguments concat_args = new Arguments (2);
5713 Arguments add_args = new Arguments (3);
5715 concat_args.Add (left);
5716 add_args.Add (new Argument (left_etree));
5718 concat_args.Add (arguments [pos]);
5719 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5721 var methods = GetConcatMethodCandidates ();
5722 if (methods == null)
5725 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5726 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5730 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5732 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5733 if (++pos == arguments.Count)
5736 left = new Argument (new EmptyExpression (method.ReturnType));
5737 return CreateExpressionAddCall (ec, left, expr, pos);
5740 protected override Expression DoResolve (ResolveContext ec)
5745 void Append (ResolveContext rc, Expression operand)
5750 StringConstant sc = operand as StringConstant;
5752 if (arguments.Count != 0) {
5753 Argument last_argument = arguments [arguments.Count - 1];
5754 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5755 if (last_expr_constant != null) {
5756 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5762 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5764 StringConcat concat_oper = operand as StringConcat;
5765 if (concat_oper != null) {
5766 arguments.AddRange (concat_oper.arguments);
5771 arguments.Add (new Argument (operand));
5774 IList<MemberSpec> GetConcatMethodCandidates ()
5776 return MemberCache.FindMembers (type, "Concat", true);
5779 public override void Emit (EmitContext ec)
5781 // Optimize by removing any extra null arguments, they are no-op
5782 for (int i = 0; i < arguments.Count; ++i) {
5783 if (arguments[i].Expr is NullConstant)
5784 arguments.RemoveAt (i--);
5787 var members = GetConcatMethodCandidates ();
5788 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5789 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5790 if (method != null) {
5791 var call = new CallEmitter ();
5792 call.EmitPredefined (ec, method, arguments, false);
5796 public override void FlowAnalysis (FlowAnalysisContext fc)
5798 arguments.FlowAnalysis (fc);
5801 public override SLE.Expression MakeExpression (BuilderContext ctx)
5803 if (arguments.Count != 2)
5804 throw new NotImplementedException ("arguments.Count != 2");
5806 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5807 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5812 // User-defined conditional logical operator
5814 public class ConditionalLogicalOperator : UserOperatorCall
5816 readonly bool is_and;
5817 Expression oper_expr;
5819 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5820 : base (oper, arguments, expr_tree, loc)
5822 this.is_and = is_and;
5823 eclass = ExprClass.Unresolved;
5826 protected override Expression DoResolve (ResolveContext ec)
5828 AParametersCollection pd = oper.Parameters;
5829 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5830 ec.Report.Error (217, loc,
5831 "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",
5832 oper.GetSignatureForError ());
5836 Expression left_dup = new EmptyExpression (type);
5837 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5838 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5839 if (op_true == null || op_false == null) {
5840 ec.Report.Error (218, loc,
5841 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5842 type.GetSignatureForError (), oper.GetSignatureForError ());
5846 oper_expr = is_and ? op_false : op_true;
5847 eclass = ExprClass.Value;
5851 public override void Emit (EmitContext ec)
5853 Label end_target = ec.DefineLabel ();
5856 // Emit and duplicate left argument
5858 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5859 if (right_contains_await) {
5860 arguments[0] = arguments[0].EmitToField (ec, false);
5861 arguments[0].Expr.Emit (ec);
5863 arguments[0].Expr.Emit (ec);
5864 ec.Emit (OpCodes.Dup);
5865 arguments.RemoveAt (0);
5868 oper_expr.EmitBranchable (ec, end_target, true);
5872 if (right_contains_await) {
5874 // Special handling when right expression contains await and left argument
5875 // could not be left on stack before logical branch
5877 Label skip_left_load = ec.DefineLabel ();
5878 ec.Emit (OpCodes.Br_S, skip_left_load);
5879 ec.MarkLabel (end_target);
5880 arguments[0].Expr.Emit (ec);
5881 ec.MarkLabel (skip_left_load);
5883 ec.MarkLabel (end_target);
5888 public class PointerArithmetic : Expression {
5889 Expression left, right;
5890 readonly Binary.Operator op;
5893 // We assume that `l' is always a pointer
5895 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5904 public override bool ContainsEmitWithAwait ()
5906 throw new NotImplementedException ();
5909 public override Expression CreateExpressionTree (ResolveContext ec)
5911 Error_PointerInsideExpressionTree (ec);
5915 protected override Expression DoResolve (ResolveContext ec)
5917 eclass = ExprClass.Variable;
5919 var pc = left.Type as PointerContainer;
5920 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5921 Error_VoidPointerOperation (ec);
5928 public override void Emit (EmitContext ec)
5930 TypeSpec op_type = left.Type;
5932 // It must be either array or fixed buffer
5934 if (TypeManager.HasElementType (op_type)) {
5935 element = TypeManager.GetElementType (op_type);
5937 FieldExpr fe = left as FieldExpr;
5939 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5944 int size = BuiltinTypeSpec.GetSize(element);
5945 TypeSpec rtype = right.Type;
5947 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5949 // handle (pointer - pointer)
5953 ec.Emit (OpCodes.Sub);
5957 ec.Emit (OpCodes.Sizeof, element);
5960 ec.Emit (OpCodes.Div);
5962 ec.Emit (OpCodes.Conv_I8);
5965 // handle + and - on (pointer op int)
5967 Constant left_const = left as Constant;
5968 if (left_const != null) {
5970 // Optimize ((T*)null) pointer operations
5972 if (left_const.IsDefaultValue) {
5973 left = EmptyExpression.Null;
5981 var right_const = right as Constant;
5982 if (right_const != null) {
5984 // Optimize 0-based arithmetic
5986 if (right_const.IsDefaultValue)
5990 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5992 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5994 // TODO: Should be the checks resolve context sensitive?
5995 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5996 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6002 switch (rtype.BuiltinType) {
6003 case BuiltinTypeSpec.Type.SByte:
6004 case BuiltinTypeSpec.Type.Byte:
6005 case BuiltinTypeSpec.Type.Short:
6006 case BuiltinTypeSpec.Type.UShort:
6007 ec.Emit (OpCodes.Conv_I);
6009 case BuiltinTypeSpec.Type.UInt:
6010 ec.Emit (OpCodes.Conv_U);
6014 if (right_const == null && size != 1){
6016 ec.Emit (OpCodes.Sizeof, element);
6019 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6020 ec.Emit (OpCodes.Conv_I8);
6022 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6025 if (left_const == null) {
6026 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6027 ec.Emit (OpCodes.Conv_I);
6028 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6029 ec.Emit (OpCodes.Conv_U);
6031 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6038 // A boolean-expression is an expression that yields a result
6041 public class BooleanExpression : ShimExpression
6043 public BooleanExpression (Expression expr)
6046 this.loc = expr.Location;
6049 public override Expression CreateExpressionTree (ResolveContext ec)
6051 // TODO: We should emit IsTrue (v4) instead of direct user operator
6052 // call but that would break csc compatibility
6053 return base.CreateExpressionTree (ec);
6056 protected override Expression DoResolve (ResolveContext ec)
6058 // A boolean-expression is required to be of a type
6059 // that can be implicitly converted to bool or of
6060 // a type that implements operator true
6062 expr = expr.Resolve (ec);
6066 Assign ass = expr as Assign;
6067 if (ass != null && ass.Source is Constant) {
6068 ec.Report.Warning (665, 3, loc,
6069 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6072 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6075 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6076 Arguments args = new Arguments (1);
6077 args.Add (new Argument (expr));
6078 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6081 type = ec.BuiltinTypes.Bool;
6082 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6083 if (converted != null)
6087 // If no implicit conversion to bool exists, try using `operator true'
6089 converted = GetOperatorTrue (ec, expr, loc);
6090 if (converted == null) {
6091 expr.Error_ValueCannotBeConverted (ec, type, false);
6098 public override object Accept (StructuralVisitor visitor)
6100 return visitor.Visit (this);
6104 public class BooleanExpressionFalse : Unary
6106 public BooleanExpressionFalse (Expression expr)
6107 : base (Operator.LogicalNot, expr, expr.Location)
6111 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6113 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6118 /// Implements the ternary conditional operator (?:)
6120 public class Conditional : Expression {
6121 Expression expr, true_expr, false_expr;
6123 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6126 this.true_expr = true_expr;
6127 this.false_expr = false_expr;
6133 public Expression Expr {
6139 public Expression TrueExpr {
6145 public Expression FalseExpr {
6153 public override bool ContainsEmitWithAwait ()
6155 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6158 public override Expression CreateExpressionTree (ResolveContext ec)
6160 Arguments args = new Arguments (3);
6161 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6162 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6163 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6164 return CreateExpressionFactoryCall (ec, "Condition", args);
6167 protected override Expression DoResolve (ResolveContext ec)
6169 expr = expr.Resolve (ec);
6170 true_expr = true_expr.Resolve (ec);
6171 false_expr = false_expr.Resolve (ec);
6173 if (true_expr == null || false_expr == null || expr == null)
6176 eclass = ExprClass.Value;
6177 TypeSpec true_type = true_expr.Type;
6178 TypeSpec false_type = false_expr.Type;
6182 // First, if an implicit conversion exists from true_expr
6183 // to false_expr, then the result type is of type false_expr.Type
6185 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6186 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6187 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6189 // Check if both can convert implicitly to each other's type
6193 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6194 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6196 // LAMESPEC: There seems to be hardcoded promotition to int type when
6197 // both sides are numeric constants and one side is int constant and
6198 // other side is numeric constant convertible to int.
6200 // var res = condition ? (short)1 : 1;
6202 // Type of res is int even if according to the spec the conversion is
6203 // ambiguous because 1 literal can be converted to short.
6205 if (conv_false_expr != null) {
6206 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6208 conv_false_expr = null;
6209 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6210 conv_false_expr = null;
6214 if (conv_false_expr != null) {
6215 ec.Report.Error (172, true_expr.Location,
6216 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6217 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6222 if (true_expr.Type != type)
6223 true_expr = EmptyCast.Create (true_expr, type);
6224 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6227 if (false_type != InternalType.ErrorType) {
6228 ec.Report.Error (173, true_expr.Location,
6229 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6230 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6236 Constant c = expr as Constant;
6238 bool is_false = c.IsDefaultValue;
6241 // Don't issue the warning for constant expressions
6243 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6244 // CSC: Missing warning
6245 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6248 return ReducedExpression.Create (
6249 is_false ? false_expr : true_expr, this,
6250 false_expr is Constant && true_expr is Constant).Resolve (ec);
6256 public override void Emit (EmitContext ec)
6258 Label false_target = ec.DefineLabel ();
6259 Label end_target = ec.DefineLabel ();
6261 expr.EmitBranchable (ec, false_target, false);
6262 true_expr.Emit (ec);
6265 // Verifier doesn't support interface merging. When there are two types on
6266 // the stack without common type hint and the common type is an interface.
6267 // Use temporary local to give verifier hint on what type to unify the stack
6269 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6270 var temp = ec.GetTemporaryLocal (type);
6271 ec.Emit (OpCodes.Stloc, temp);
6272 ec.Emit (OpCodes.Ldloc, temp);
6273 ec.FreeTemporaryLocal (temp, type);
6276 ec.Emit (OpCodes.Br, end_target);
6277 ec.MarkLabel (false_target);
6278 false_expr.Emit (ec);
6279 ec.MarkLabel (end_target);
6282 public override void FlowAnalysis (FlowAnalysisContext fc)
6284 expr.FlowAnalysisConditional (fc);
6285 var expr_true = fc.DefiniteAssignmentOnTrue;
6286 var expr_false = fc.DefiniteAssignmentOnFalse;
6288 fc.BranchDefiniteAssignment (expr_true);
6289 true_expr.FlowAnalysis (fc);
6290 var true_fc = fc.DefiniteAssignment;
6292 fc.BranchDefiniteAssignment (expr_false);
6293 false_expr.FlowAnalysis (fc);
6295 fc.DefiniteAssignment &= true_fc;
6298 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6300 expr.FlowAnalysisConditional (fc);
6301 var expr_true = fc.DefiniteAssignmentOnTrue;
6302 var expr_false = fc.DefiniteAssignmentOnFalse;
6304 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6305 true_expr.FlowAnalysisConditional (fc);
6306 var true_fc = fc.DefiniteAssignment;
6307 var true_da_true = fc.DefiniteAssignmentOnTrue;
6308 var true_da_false = fc.DefiniteAssignmentOnFalse;
6310 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6311 false_expr.FlowAnalysisConditional (fc);
6313 fc.DefiniteAssignment &= true_fc;
6314 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6315 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6318 protected override void CloneTo (CloneContext clonectx, Expression t)
6320 Conditional target = (Conditional) t;
6322 target.expr = expr.Clone (clonectx);
6323 target.true_expr = true_expr.Clone (clonectx);
6324 target.false_expr = false_expr.Clone (clonectx);
6328 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6330 LocalTemporary temp;
6333 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6334 public abstract void SetHasAddressTaken ();
6336 public abstract bool IsLockedByStatement { get; set; }
6338 public abstract bool IsFixed { get; }
6339 public abstract bool IsRef { get; }
6340 public abstract string Name { get; }
6343 // Variable IL data, it has to be protected to encapsulate hoisted variables
6345 protected abstract ILocalVariable Variable { get; }
6348 // Variable flow-analysis data
6350 public abstract VariableInfo VariableInfo { get; }
6353 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6355 HoistedVariable hv = GetHoistedVariable (ec);
6357 hv.AddressOf (ec, mode);
6361 Variable.EmitAddressOf (ec);
6364 public override bool ContainsEmitWithAwait ()
6369 public override Expression CreateExpressionTree (ResolveContext ec)
6371 HoistedVariable hv = GetHoistedVariable (ec);
6373 return hv.CreateExpressionTree ();
6375 Arguments arg = new Arguments (1);
6376 arg.Add (new Argument (this));
6377 return CreateExpressionFactoryCall (ec, "Constant", arg);
6380 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6382 if (IsLockedByStatement) {
6383 rc.Report.Warning (728, 2, loc,
6384 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6391 public override void Emit (EmitContext ec)
6396 public override void EmitSideEffect (EmitContext ec)
6402 // This method is used by parameters that are references, that are
6403 // being passed as references: we only want to pass the pointer (that
6404 // is already stored in the parameter, not the address of the pointer,
6405 // and not the value of the variable).
6407 public void EmitLoad (EmitContext ec)
6412 public void Emit (EmitContext ec, bool leave_copy)
6414 HoistedVariable hv = GetHoistedVariable (ec);
6416 hv.Emit (ec, leave_copy);
6424 // If we are a reference, we loaded on the stack a pointer
6425 // Now lets load the real value
6427 ec.EmitLoadFromPtr (type);
6431 ec.Emit (OpCodes.Dup);
6434 temp = new LocalTemporary (Type);
6440 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6441 bool prepare_for_load)
6443 HoistedVariable hv = GetHoistedVariable (ec);
6445 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6449 New n_source = source as New;
6450 if (n_source != null) {
6451 if (!n_source.Emit (ec, this)) {
6455 ec.EmitLoadFromPtr (type);
6467 ec.Emit (OpCodes.Dup);
6469 temp = new LocalTemporary (Type);
6475 ec.EmitStoreFromPtr (type);
6477 Variable.EmitAssign (ec);
6485 public override Expression EmitToField (EmitContext ec)
6487 HoistedVariable hv = GetHoistedVariable (ec);
6489 return hv.EmitToField (ec);
6492 return base.EmitToField (ec);
6495 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6497 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6500 public HoistedVariable GetHoistedVariable (EmitContext ec)
6502 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6505 public override string GetSignatureForError ()
6510 public bool IsHoisted {
6511 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6516 // Resolved reference to a local variable
6518 public class LocalVariableReference : VariableReference
6520 public LocalVariable local_info;
6522 public LocalVariableReference (LocalVariable li, Location l)
6524 this.local_info = li;
6528 public override VariableInfo VariableInfo {
6529 get { return local_info.VariableInfo; }
6532 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6534 return local_info.HoistedVariant;
6540 // A local variable is always fixed
6542 public override bool IsFixed {
6548 public override bool IsLockedByStatement {
6550 return local_info.IsLocked;
6553 local_info.IsLocked = value;
6557 public override bool IsRef {
6558 get { return false; }
6561 public override string Name {
6562 get { return local_info.Name; }
6567 public override void FlowAnalysis (FlowAnalysisContext fc)
6569 VariableInfo variable_info = VariableInfo;
6570 if (variable_info == null)
6573 if (fc.IsDefinitelyAssigned (variable_info))
6576 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6577 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6580 public override void SetHasAddressTaken ()
6582 local_info.SetHasAddressTaken ();
6585 void DoResolveBase (ResolveContext ec)
6587 eclass = ExprClass.Variable;
6588 type = local_info.Type;
6591 // If we are referencing a variable from the external block
6592 // flag it for capturing
6594 if (ec.MustCaptureVariable (local_info)) {
6595 if (local_info.AddressTaken) {
6596 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6597 } else if (local_info.IsFixed) {
6598 ec.Report.Error (1764, loc,
6599 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6600 GetSignatureForError ());
6603 if (ec.IsVariableCapturingRequired) {
6604 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6605 storey.CaptureLocalVariable (ec, local_info);
6610 protected override Expression DoResolve (ResolveContext ec)
6612 local_info.SetIsUsed ();
6616 if (local_info.Type == InternalType.VarOutType) {
6617 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6618 GetSignatureForError ());
6620 type = InternalType.ErrorType;
6626 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6629 // Don't be too pedantic when variable is used as out param or for some broken code
6630 // which uses property/indexer access to run some initialization
6632 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6633 local_info.SetIsUsed ();
6635 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6636 if (rhs == EmptyExpression.LValueMemberAccess) {
6637 // CS1654 already reported
6641 if (rhs == EmptyExpression.OutAccess) {
6642 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6643 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6644 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6645 } else if (rhs == EmptyExpression.UnaryAddress) {
6646 code = 459; msg = "Cannot take the address of {1} `{0}'";
6648 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6650 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6654 if (eclass == ExprClass.Unresolved)
6657 return base.DoResolveLValue (ec, rhs);
6660 public override int GetHashCode ()
6662 return local_info.GetHashCode ();
6665 public override bool Equals (object obj)
6667 LocalVariableReference lvr = obj as LocalVariableReference;
6671 return local_info == lvr.local_info;
6674 protected override ILocalVariable Variable {
6675 get { return local_info; }
6678 public override string ToString ()
6680 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6683 protected override void CloneTo (CloneContext clonectx, Expression t)
6690 /// This represents a reference to a parameter in the intermediate
6693 public class ParameterReference : VariableReference
6695 protected ParametersBlock.ParameterInfo pi;
6697 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6705 public override bool IsLockedByStatement {
6710 pi.IsLocked = value;
6714 public override bool IsRef {
6715 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6718 bool HasOutModifier {
6719 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6722 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6724 return pi.Parameter.HoistedVariant;
6728 // A ref or out parameter is classified as a moveable variable, even
6729 // if the argument given for the parameter is a fixed variable
6731 public override bool IsFixed {
6732 get { return !IsRef; }
6735 public override string Name {
6736 get { return Parameter.Name; }
6739 public Parameter Parameter {
6740 get { return pi.Parameter; }
6743 public override VariableInfo VariableInfo {
6744 get { return pi.VariableInfo; }
6747 protected override ILocalVariable Variable {
6748 get { return Parameter; }
6753 public override void AddressOf (EmitContext ec, AddressOp mode)
6756 // ParameterReferences might already be a reference
6763 base.AddressOf (ec, mode);
6766 public override void SetHasAddressTaken ()
6768 Parameter.HasAddressTaken = true;
6771 bool DoResolveBase (ResolveContext ec)
6773 if (eclass != ExprClass.Unresolved)
6776 type = pi.ParameterType;
6777 eclass = ExprClass.Variable;
6780 // If we are referencing a parameter from the external block
6781 // flag it for capturing
6783 if (ec.MustCaptureVariable (pi)) {
6784 if (Parameter.HasAddressTaken)
6785 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6788 ec.Report.Error (1628, loc,
6789 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6790 Name, ec.CurrentAnonymousMethod.ContainerType);
6793 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6794 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6795 storey.CaptureParameter (ec, pi, this);
6802 public override int GetHashCode ()
6804 return Name.GetHashCode ();
6807 public override bool Equals (object obj)
6809 ParameterReference pr = obj as ParameterReference;
6813 return Name == pr.Name;
6816 protected override void CloneTo (CloneContext clonectx, Expression target)
6822 public override Expression CreateExpressionTree (ResolveContext ec)
6824 HoistedVariable hv = GetHoistedVariable (ec);
6826 return hv.CreateExpressionTree ();
6828 return Parameter.ExpressionTreeVariableReference ();
6831 protected override Expression DoResolve (ResolveContext ec)
6833 if (!DoResolveBase (ec))
6839 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6841 if (!DoResolveBase (ec))
6844 if (Parameter.HoistedVariant != null)
6845 Parameter.HoistedVariant.IsAssigned = true;
6847 return base.DoResolveLValue (ec, right_side);
6850 public override void FlowAnalysis (FlowAnalysisContext fc)
6852 VariableInfo variable_info = VariableInfo;
6853 if (variable_info == null)
6856 if (fc.IsDefinitelyAssigned (variable_info))
6859 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6860 fc.SetVariableAssigned (variable_info);
6865 /// Invocation of methods or delegates.
6867 public class Invocation : ExpressionStatement
6869 public class Predefined : Invocation
6871 public Predefined (MethodGroupExpr expr, Arguments arguments)
6872 : base (expr, arguments)
6877 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6879 if (!rc.IsObsolete) {
6880 var member = mg.BestCandidate;
6881 ObsoleteAttribute oa = member.GetAttributeObsolete ();
6883 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
6890 protected Arguments arguments;
6891 protected Expression expr;
6892 protected MethodGroupExpr mg;
6893 bool conditional_access_receiver;
6895 public Invocation (Expression expr, Arguments arguments)
6898 this.arguments = arguments;
6900 loc = expr.Location;
6905 public Arguments Arguments {
6911 public Expression Exp {
6917 public MethodGroupExpr MethodGroup {
6923 public override Location StartLocation {
6925 return expr.StartLocation;
6931 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6933 if (MethodGroup == null)
6936 var candidate = MethodGroup.BestCandidate;
6937 if (candidate == null || !(candidate.IsStatic || Exp is This))
6940 var args_count = arguments == null ? 0 : arguments.Count;
6941 if (args_count != body.Parameters.Count)
6944 var lambda_parameters = body.Block.Parameters.FixedParameters;
6945 for (int i = 0; i < args_count; ++i) {
6946 var pr = arguments[i].Expr as ParameterReference;
6950 if (lambda_parameters[i] != pr.Parameter)
6953 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6957 var emg = MethodGroup as ExtensionMethodGroupExpr;
6959 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6960 if (candidate.IsGeneric) {
6961 var targs = new TypeExpression [candidate.Arity];
6962 for (int i = 0; i < targs.Length; ++i) {
6963 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6966 mg.SetTypeArguments (null, new TypeArguments (targs));
6975 protected override void CloneTo (CloneContext clonectx, Expression t)
6977 Invocation target = (Invocation) t;
6979 if (arguments != null)
6980 target.arguments = arguments.Clone (clonectx);
6982 target.expr = expr.Clone (clonectx);
6985 public override bool ContainsEmitWithAwait ()
6987 if (arguments != null && arguments.ContainsEmitWithAwait ())
6990 return mg.ContainsEmitWithAwait ();
6993 public override Expression CreateExpressionTree (ResolveContext ec)
6995 Expression instance = mg.IsInstance ?
6996 mg.InstanceExpression.CreateExpressionTree (ec) :
6997 new NullLiteral (loc);
6999 var args = Arguments.CreateForExpressionTree (ec, arguments,
7001 mg.CreateExpressionTree (ec));
7003 return CreateExpressionFactoryCall (ec, "Call", args);
7006 protected override Expression DoResolve (ResolveContext rc)
7008 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
7009 if (expr.HasConditionalAccess ()) {
7010 conditional_access_receiver = true;
7011 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
7012 return DoResolveInvocation (rc);
7017 return DoResolveInvocation (rc);
7020 Expression DoResolveInvocation (ResolveContext ec)
7022 Expression member_expr;
7023 var atn = expr as ATypeNameExpression;
7025 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7026 if (member_expr != null) {
7027 var name_of = member_expr as NameOf;
7028 if (name_of != null) {
7029 return name_of.ResolveOverload (ec, arguments);
7032 member_expr = member_expr.Resolve (ec);
7035 member_expr = expr.Resolve (ec);
7038 if (member_expr == null)
7042 // Next, evaluate all the expressions in the argument list
7044 bool dynamic_arg = false;
7045 if (arguments != null)
7046 arguments.Resolve (ec, out dynamic_arg);
7048 TypeSpec expr_type = member_expr.Type;
7049 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7050 return DoResolveDynamic (ec, member_expr);
7052 mg = member_expr as MethodGroupExpr;
7053 Expression invoke = null;
7056 if (expr_type != null && expr_type.IsDelegate) {
7057 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7058 invoke = invoke.Resolve (ec);
7059 if (invoke == null || !dynamic_arg)
7062 if (member_expr is RuntimeValueExpression) {
7063 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7064 member_expr.Type.GetSignatureForError ());
7068 MemberExpr me = member_expr as MemberExpr;
7070 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7074 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7075 member_expr.GetSignatureForError ());
7080 if (invoke == null) {
7081 mg = DoResolveOverload (ec);
7087 return DoResolveDynamic (ec, member_expr);
7089 var method = mg.BestCandidate;
7090 type = mg.BestCandidateReturnType;
7091 if (conditional_access_receiver)
7092 type = LiftMemberType (ec, type);
7094 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7096 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7098 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7102 IsSpecialMethodInvocation (ec, method, loc);
7104 eclass = ExprClass.Value;
7108 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7111 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7113 args = dmb.Arguments;
7114 if (arguments != null)
7115 args.AddRange (arguments);
7116 } else if (mg == null) {
7117 if (arguments == null)
7118 args = new Arguments (1);
7122 args.Insert (0, new Argument (memberExpr));
7126 ec.Report.Error (1971, loc,
7127 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7132 if (arguments == null)
7133 args = new Arguments (1);
7137 MemberAccess ma = expr as MemberAccess;
7139 var inst = mg.InstanceExpression;
7140 var left_type = inst as TypeExpr;
7141 if (left_type != null) {
7142 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7143 } else if (inst != null) {
7145 // Any value type has to be pass as by-ref to get back the same
7146 // instance on which the member was called
7148 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7149 Argument.AType.Ref : Argument.AType.None;
7150 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7152 } else { // is SimpleName
7154 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7156 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7161 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7164 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7166 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7169 public override void FlowAnalysis (FlowAnalysisContext fc)
7171 if (mg.IsConditionallyExcluded)
7174 mg.FlowAnalysis (fc);
7176 if (arguments != null)
7177 arguments.FlowAnalysis (fc);
7179 if (conditional_access_receiver)
7180 fc.ConditionalAccessEnd ();
7183 public override string GetSignatureForError ()
7185 return mg.GetSignatureForError ();
7188 public override bool HasConditionalAccess ()
7190 return expr.HasConditionalAccess ();
7194 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7195 // or the type dynamic, then the member is invocable
7197 public static bool IsMemberInvocable (MemberSpec member)
7199 switch (member.Kind) {
7200 case MemberKind.Event:
7202 case MemberKind.Field:
7203 case MemberKind.Property:
7204 var m = member as IInterfaceMemberSpec;
7205 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7211 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7213 if (!method.IsReservedMethod)
7216 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7219 ec.Report.SymbolRelatedToPreviousError (method);
7220 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7221 method.GetSignatureForError ());
7226 public override void Emit (EmitContext ec)
7228 if (mg.IsConditionallyExcluded)
7231 if (conditional_access_receiver)
7232 mg.EmitCall (ec, arguments, type, false);
7234 mg.EmitCall (ec, arguments, false);
7237 public override void EmitStatement (EmitContext ec)
7239 if (mg.IsConditionallyExcluded)
7242 if (conditional_access_receiver)
7243 mg.EmitCall (ec, arguments, type, true);
7245 mg.EmitCall (ec, arguments, true);
7248 public override SLE.Expression MakeExpression (BuilderContext ctx)
7250 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7253 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7256 throw new NotSupportedException ();
7258 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7259 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7263 public override object Accept (StructuralVisitor visitor)
7265 return visitor.Visit (this);
7270 // Implements simple new expression
7272 public class New : ExpressionStatement, IMemoryLocation
7274 protected Arguments arguments;
7277 // During bootstrap, it contains the RequestedType,
7278 // but if `type' is not null, it *might* contain a NewDelegate
7279 // (because of field multi-initialization)
7281 protected Expression RequestedType;
7283 protected MethodSpec method;
7285 public New (Expression requested_type, Arguments arguments, Location l)
7287 RequestedType = requested_type;
7288 this.arguments = arguments;
7293 public Arguments Arguments {
7300 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7302 public bool IsGeneratedStructConstructor {
7304 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7308 public Expression TypeExpression {
7310 return RequestedType;
7317 /// Converts complex core type syntax like 'new int ()' to simple constant
7319 public static Constant Constantify (TypeSpec t, Location loc)
7321 switch (t.BuiltinType) {
7322 case BuiltinTypeSpec.Type.Int:
7323 return new IntConstant (t, 0, loc);
7324 case BuiltinTypeSpec.Type.UInt:
7325 return new UIntConstant (t, 0, loc);
7326 case BuiltinTypeSpec.Type.Long:
7327 return new LongConstant (t, 0, loc);
7328 case BuiltinTypeSpec.Type.ULong:
7329 return new ULongConstant (t, 0, loc);
7330 case BuiltinTypeSpec.Type.Float:
7331 return new FloatConstant (t, 0, loc);
7332 case BuiltinTypeSpec.Type.Double:
7333 return new DoubleConstant (t, 0, loc);
7334 case BuiltinTypeSpec.Type.Short:
7335 return new ShortConstant (t, 0, loc);
7336 case BuiltinTypeSpec.Type.UShort:
7337 return new UShortConstant (t, 0, loc);
7338 case BuiltinTypeSpec.Type.SByte:
7339 return new SByteConstant (t, 0, loc);
7340 case BuiltinTypeSpec.Type.Byte:
7341 return new ByteConstant (t, 0, loc);
7342 case BuiltinTypeSpec.Type.Char:
7343 return new CharConstant (t, '\0', loc);
7344 case BuiltinTypeSpec.Type.Bool:
7345 return new BoolConstant (t, false, loc);
7346 case BuiltinTypeSpec.Type.Decimal:
7347 return new DecimalConstant (t, 0, loc);
7351 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7353 if (t.IsNullableType)
7354 return Nullable.LiftedNull.Create (t, loc);
7359 public override bool ContainsEmitWithAwait ()
7361 return arguments != null && arguments.ContainsEmitWithAwait ();
7365 // Checks whether the type is an interface that has the
7366 // [ComImport, CoClass] attributes and must be treated
7369 public Expression CheckComImport (ResolveContext ec)
7371 if (!type.IsInterface)
7375 // Turn the call into:
7376 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7378 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7379 if (real_class == null)
7382 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7383 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7384 return cast.Resolve (ec);
7387 public override Expression CreateExpressionTree (ResolveContext ec)
7390 if (method == null) {
7391 args = new Arguments (1);
7392 args.Add (new Argument (new TypeOf (type, loc)));
7394 args = Arguments.CreateForExpressionTree (ec,
7395 arguments, new TypeOfMethod (method, loc));
7398 return CreateExpressionFactoryCall (ec, "New", args);
7401 protected override Expression DoResolve (ResolveContext ec)
7403 type = RequestedType.ResolveAsType (ec);
7407 eclass = ExprClass.Value;
7409 if (type.IsPointer) {
7410 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7411 type.GetSignatureForError ());
7415 if (arguments == null) {
7416 Constant c = Constantify (type, RequestedType.Location);
7418 return ReducedExpression.Create (c, this);
7421 if (type.IsDelegate) {
7422 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7425 var tparam = type as TypeParameterSpec;
7426 if (tparam != null) {
7428 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7429 // where type parameter constraint is inflated to struct
7431 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7432 ec.Report.Error (304, loc,
7433 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7434 type.GetSignatureForError ());
7437 if ((arguments != null) && (arguments.Count != 0)) {
7438 ec.Report.Error (417, loc,
7439 "`{0}': cannot provide arguments when creating an instance of a variable type",
7440 type.GetSignatureForError ());
7446 if (type.IsStatic) {
7447 ec.Report.SymbolRelatedToPreviousError (type);
7448 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7452 if (type.IsInterface || type.IsAbstract){
7453 if (!TypeManager.IsGenericType (type)) {
7454 RequestedType = CheckComImport (ec);
7455 if (RequestedType != null)
7456 return RequestedType;
7459 ec.Report.SymbolRelatedToPreviousError (type);
7460 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7465 if (arguments != null) {
7466 arguments.Resolve (ec, out dynamic);
7471 method = ConstructorLookup (ec, type, ref arguments, loc);
7474 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7475 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7481 void DoEmitTypeParameter (EmitContext ec)
7483 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7487 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7488 ec.Emit (OpCodes.Call, ctor_factory);
7492 // This Emit can be invoked in two contexts:
7493 // * As a mechanism that will leave a value on the stack (new object)
7494 // * As one that wont (init struct)
7496 // If we are dealing with a ValueType, we have a few
7497 // situations to deal with:
7499 // * The target is a ValueType, and we have been provided
7500 // the instance (this is easy, we are being assigned).
7502 // * The target of New is being passed as an argument,
7503 // to a boxing operation or a function that takes a
7506 // In this case, we need to create a temporary variable
7507 // that is the argument of New.
7509 // Returns whether a value is left on the stack
7511 // *** Implementation note ***
7513 // To benefit from this optimization, each assignable expression
7514 // has to manually cast to New and call this Emit.
7516 // TODO: It's worth to implement it for arrays and fields
7518 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7520 bool is_value_type = type.IsStructOrEnum;
7521 VariableReference vr = target as VariableReference;
7523 if (target != null && is_value_type && (vr != null || method == null)) {
7524 target.AddressOf (ec, AddressOp.Store);
7525 } else if (vr != null && vr.IsRef) {
7529 if (arguments != null) {
7530 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7531 arguments = arguments.Emit (ec, false, true);
7533 arguments.Emit (ec);
7536 if (is_value_type) {
7537 if (method == null) {
7538 ec.Emit (OpCodes.Initobj, type);
7543 ec.MarkCallEntry (loc);
7544 ec.Emit (OpCodes.Call, method);
7549 if (type is TypeParameterSpec) {
7550 DoEmitTypeParameter (ec);
7554 ec.MarkCallEntry (loc);
7555 ec.Emit (OpCodes.Newobj, method);
7559 public override void Emit (EmitContext ec)
7561 LocalTemporary v = null;
7562 if (method == null && type.IsStructOrEnum) {
7563 // TODO: Use temporary variable from pool
7564 v = new LocalTemporary (type);
7571 public override void EmitStatement (EmitContext ec)
7573 LocalTemporary v = null;
7574 if (method == null && TypeSpec.IsValueType (type)) {
7575 // TODO: Use temporary variable from pool
7576 v = new LocalTemporary (type);
7580 ec.Emit (OpCodes.Pop);
7583 public override void FlowAnalysis (FlowAnalysisContext fc)
7585 if (arguments != null)
7586 arguments.FlowAnalysis (fc);
7589 public void AddressOf (EmitContext ec, AddressOp mode)
7591 EmitAddressOf (ec, mode);
7594 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7596 LocalTemporary value_target = new LocalTemporary (type);
7598 if (type is TypeParameterSpec) {
7599 DoEmitTypeParameter (ec);
7600 value_target.Store (ec);
7601 value_target.AddressOf (ec, mode);
7602 return value_target;
7605 value_target.AddressOf (ec, AddressOp.Store);
7607 if (method == null) {
7608 ec.Emit (OpCodes.Initobj, type);
7610 if (arguments != null)
7611 arguments.Emit (ec);
7613 ec.Emit (OpCodes.Call, method);
7616 value_target.AddressOf (ec, mode);
7617 return value_target;
7620 protected override void CloneTo (CloneContext clonectx, Expression t)
7622 New target = (New) t;
7624 target.RequestedType = RequestedType.Clone (clonectx);
7625 if (arguments != null){
7626 target.arguments = arguments.Clone (clonectx);
7630 public override SLE.Expression MakeExpression (BuilderContext ctx)
7633 return base.MakeExpression (ctx);
7635 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7639 public override object Accept (StructuralVisitor visitor)
7641 return visitor.Visit (this);
7646 // Array initializer expression, the expression is allowed in
7647 // variable or field initialization only which makes it tricky as
7648 // the type has to be infered based on the context either from field
7649 // type or variable type (think of multiple declarators)
7651 public class ArrayInitializer : Expression
7653 List<Expression> elements;
7654 BlockVariable variable;
7656 public ArrayInitializer (List<Expression> init, Location loc)
7662 public ArrayInitializer (int count, Location loc)
7663 : this (new List<Expression> (count), loc)
7667 public ArrayInitializer (Location loc)
7675 get { return elements.Count; }
7678 public List<Expression> Elements {
7684 public Expression this [int index] {
7686 return elements [index];
7690 public BlockVariable VariableDeclaration {
7701 public void Add (Expression expr)
7703 elements.Add (expr);
7706 public override bool ContainsEmitWithAwait ()
7708 throw new NotSupportedException ();
7711 public override Expression CreateExpressionTree (ResolveContext ec)
7713 throw new NotSupportedException ("ET");
7716 protected override void CloneTo (CloneContext clonectx, Expression t)
7718 var target = (ArrayInitializer) t;
7720 target.elements = new List<Expression> (elements.Count);
7721 foreach (var element in elements)
7722 target.elements.Add (element.Clone (clonectx));
7725 protected override Expression DoResolve (ResolveContext rc)
7727 var current_field = rc.CurrentMemberDefinition as FieldBase;
7728 TypeExpression type;
7729 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7730 type = new TypeExpression (current_field.MemberType, current_field.Location);
7731 } else if (variable != null) {
7732 if (variable.TypeExpression is VarExpr) {
7733 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7734 return EmptyExpression.Null;
7737 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7739 throw new NotImplementedException ("Unexpected array initializer context");
7742 return new ArrayCreation (type, this).Resolve (rc);
7745 public override void Emit (EmitContext ec)
7747 throw new InternalErrorException ("Missing Resolve call");
7750 public override void FlowAnalysis (FlowAnalysisContext fc)
7752 throw new InternalErrorException ("Missing Resolve call");
7755 public override object Accept (StructuralVisitor visitor)
7757 return visitor.Visit (this);
7762 /// 14.5.10.2: Represents an array creation expression.
7766 /// There are two possible scenarios here: one is an array creation
7767 /// expression that specifies the dimensions and optionally the
7768 /// initialization data and the other which does not need dimensions
7769 /// specified but where initialization data is mandatory.
7771 public class ArrayCreation : Expression
7773 FullNamedExpression requested_base_type;
7774 ArrayInitializer initializers;
7777 // The list of Argument types.
7778 // This is used to construct the `newarray' or constructor signature
7780 protected List<Expression> arguments;
7782 protected TypeSpec array_element_type;
7784 protected int dimensions;
7785 protected readonly ComposedTypeSpecifier rank;
7786 Expression first_emit;
7787 LocalTemporary first_emit_temp;
7789 protected List<Expression> array_data;
7791 Dictionary<int, int> bounds;
7794 // The number of constants in array initializers
7795 int const_initializers_count;
7796 bool only_constant_initializers;
7798 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7799 : this (requested_base_type, rank, initializers, l)
7801 arguments = new List<Expression> (exprs);
7802 num_arguments = arguments.Count;
7806 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7808 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7810 this.requested_base_type = requested_base_type;
7812 this.initializers = initializers;
7816 num_arguments = rank.Dimension;
7820 // For compiler generated single dimensional arrays only
7822 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7823 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7828 // For expressions like int[] foo = { 1, 2, 3 };
7830 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7831 : this (requested_base_type, null, initializers, initializers.Location)
7835 public ComposedTypeSpecifier Rank {
7841 public FullNamedExpression TypeExpression {
7843 return this.requested_base_type;
7847 public ArrayInitializer Initializers {
7849 return this.initializers;
7853 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7855 if (initializers != null && bounds == null) {
7857 // We use this to store all the data values in the order in which we
7858 // will need to store them in the byte blob later
7860 array_data = new List<Expression> (probe.Count);
7861 bounds = new Dictionary<int, int> ();
7864 if (specified_dims) {
7865 Expression a = arguments [idx];
7870 a = ConvertExpressionToArrayIndex (ec, a);
7876 if (initializers != null) {
7877 Constant c = a as Constant;
7878 if (c == null && a is ArrayIndexCast)
7879 c = ((ArrayIndexCast) a).Child as Constant;
7882 ec.Report.Error (150, a.Location, "A constant value is expected");
7888 value = System.Convert.ToInt32 (c.GetValue ());
7890 ec.Report.Error (150, a.Location, "A constant value is expected");
7894 // TODO: probe.Count does not fit ulong in
7895 if (value != probe.Count) {
7896 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7900 bounds[idx] = value;
7904 if (initializers == null)
7907 for (int i = 0; i < probe.Count; ++i) {
7909 if (o is ArrayInitializer) {
7910 var sub_probe = o as ArrayInitializer;
7911 if (idx + 1 >= dimensions){
7912 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7916 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7917 if (!bounds.ContainsKey(idx + 1))
7918 bounds[idx + 1] = sub_probe.Count;
7920 if (bounds[idx + 1] != sub_probe.Count) {
7921 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7925 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7928 } else if (child_bounds > 1) {
7929 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7931 Expression element = ResolveArrayElement (ec, o);
7932 if (element == null)
7935 // Initializers with the default values can be ignored
7936 Constant c = element as Constant;
7938 if (!c.IsDefaultInitializer (array_element_type)) {
7939 ++const_initializers_count;
7942 only_constant_initializers = false;
7945 array_data.Add (element);
7952 public override bool ContainsEmitWithAwait ()
7954 foreach (var arg in arguments) {
7955 if (arg.ContainsEmitWithAwait ())
7959 return InitializersContainAwait ();
7962 public override Expression CreateExpressionTree (ResolveContext ec)
7966 if (array_data == null) {
7967 args = new Arguments (arguments.Count + 1);
7968 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7969 foreach (Expression a in arguments)
7970 args.Add (new Argument (a.CreateExpressionTree (ec)));
7972 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7975 if (dimensions > 1) {
7976 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7980 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7981 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7982 if (array_data != null) {
7983 for (int i = 0; i < array_data.Count; ++i) {
7984 Expression e = array_data [i];
7985 args.Add (new Argument (e.CreateExpressionTree (ec)));
7989 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7992 void UpdateIndices (ResolveContext rc)
7995 for (var probe = initializers; probe != null;) {
7996 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7998 bounds[i++] = probe.Count;
8000 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8001 probe = (ArrayInitializer) probe[0];
8002 } else if (dimensions > i) {
8010 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8012 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8015 public override void FlowAnalysis (FlowAnalysisContext fc)
8017 foreach (var arg in arguments)
8018 arg.FlowAnalysis (fc);
8020 if (array_data != null) {
8021 foreach (var ad in array_data)
8022 ad.FlowAnalysis (fc);
8026 bool InitializersContainAwait ()
8028 if (array_data == null)
8031 foreach (var expr in array_data) {
8032 if (expr.ContainsEmitWithAwait ())
8039 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8041 element = element.Resolve (ec);
8042 if (element == null)
8045 if (element is CompoundAssign.TargetExpression) {
8046 if (first_emit != null)
8047 throw new InternalErrorException ("Can only handle one mutator at a time");
8048 first_emit = element;
8049 element = first_emit_temp = new LocalTemporary (element.Type);
8052 return Convert.ImplicitConversionRequired (
8053 ec, element, array_element_type, loc);
8056 protected bool ResolveInitializers (ResolveContext ec)
8059 only_constant_initializers = true;
8062 if (arguments != null) {
8064 for (int i = 0; i < arguments.Count; ++i) {
8065 res &= CheckIndices (ec, initializers, i, true, dimensions);
8066 if (initializers != null)
8073 arguments = new List<Expression> ();
8075 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8084 // Resolved the type of the array
8086 bool ResolveArrayType (ResolveContext ec)
8091 FullNamedExpression array_type_expr;
8092 if (num_arguments > 0) {
8093 array_type_expr = new ComposedCast (requested_base_type, rank);
8095 array_type_expr = requested_base_type;
8098 type = array_type_expr.ResolveAsType (ec);
8099 if (array_type_expr == null)
8102 var ac = type as ArrayContainer;
8104 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8108 array_element_type = ac.Element;
8109 dimensions = ac.Rank;
8114 protected override Expression DoResolve (ResolveContext ec)
8119 if (!ResolveArrayType (ec))
8123 // validate the initializers and fill in any missing bits
8125 if (!ResolveInitializers (ec))
8128 eclass = ExprClass.Value;
8132 byte [] MakeByteBlob ()
8137 int count = array_data.Count;
8139 TypeSpec element_type = array_element_type;
8140 if (element_type.IsEnum)
8141 element_type = EnumSpec.GetUnderlyingType (element_type);
8143 factor = BuiltinTypeSpec.GetSize (element_type);
8145 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8147 data = new byte [(count * factor + 3) & ~3];
8150 for (int i = 0; i < count; ++i) {
8151 var c = array_data[i] as Constant;
8157 object v = c.GetValue ();
8159 switch (element_type.BuiltinType) {
8160 case BuiltinTypeSpec.Type.Long:
8161 long lval = (long) v;
8163 for (int j = 0; j < factor; ++j) {
8164 data[idx + j] = (byte) (lval & 0xFF);
8168 case BuiltinTypeSpec.Type.ULong:
8169 ulong ulval = (ulong) v;
8171 for (int j = 0; j < factor; ++j) {
8172 data[idx + j] = (byte) (ulval & 0xFF);
8173 ulval = (ulval >> 8);
8176 case BuiltinTypeSpec.Type.Float:
8177 var fval = SingleConverter.SingleToInt32Bits((float) v);
8179 data[idx] = (byte) (fval & 0xff);
8180 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8181 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8182 data[idx + 3] = (byte) (fval >> 24);
8184 case BuiltinTypeSpec.Type.Double:
8185 element = BitConverter.GetBytes ((double) v);
8187 for (int j = 0; j < factor; ++j)
8188 data[idx + j] = element[j];
8190 // FIXME: Handle the ARM float format.
8191 if (!BitConverter.IsLittleEndian)
8192 System.Array.Reverse (data, idx, 8);
8194 case BuiltinTypeSpec.Type.Char:
8195 int chval = (int) ((char) v);
8197 data[idx] = (byte) (chval & 0xff);
8198 data[idx + 1] = (byte) (chval >> 8);
8200 case BuiltinTypeSpec.Type.Short:
8201 int sval = (int) ((short) v);
8203 data[idx] = (byte) (sval & 0xff);
8204 data[idx + 1] = (byte) (sval >> 8);
8206 case BuiltinTypeSpec.Type.UShort:
8207 int usval = (int) ((ushort) v);
8209 data[idx] = (byte) (usval & 0xff);
8210 data[idx + 1] = (byte) (usval >> 8);
8212 case BuiltinTypeSpec.Type.Int:
8215 data[idx] = (byte) (val & 0xff);
8216 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8217 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8218 data[idx + 3] = (byte) (val >> 24);
8220 case BuiltinTypeSpec.Type.UInt:
8221 uint uval = (uint) v;
8223 data[idx] = (byte) (uval & 0xff);
8224 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8225 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8226 data[idx + 3] = (byte) (uval >> 24);
8228 case BuiltinTypeSpec.Type.SByte:
8229 data[idx] = (byte) (sbyte) v;
8231 case BuiltinTypeSpec.Type.Byte:
8232 data[idx] = (byte) v;
8234 case BuiltinTypeSpec.Type.Bool:
8235 data[idx] = (byte) ((bool) v ? 1 : 0);
8237 case BuiltinTypeSpec.Type.Decimal:
8238 int[] bits = Decimal.GetBits ((decimal) v);
8241 // FIXME: For some reason, this doesn't work on the MS runtime.
8242 int[] nbits = new int[4];
8248 for (int j = 0; j < 4; j++) {
8249 data[p++] = (byte) (nbits[j] & 0xff);
8250 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8251 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8252 data[p++] = (byte) (nbits[j] >> 24);
8256 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8265 #if NET_4_0 || MOBILE_DYNAMIC
8266 public override SLE.Expression MakeExpression (BuilderContext ctx)
8269 return base.MakeExpression (ctx);
8271 var initializers = new SLE.Expression [array_data.Count];
8272 for (var i = 0; i < initializers.Length; i++) {
8273 if (array_data [i] == null)
8274 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8276 initializers [i] = array_data [i].MakeExpression (ctx);
8279 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8285 // Emits the initializers for the array
8287 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8289 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8294 // First, the static data
8296 byte [] data = MakeByteBlob ();
8297 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8299 if (stackArray == null) {
8300 ec.Emit (OpCodes.Dup);
8302 stackArray.Emit (ec);
8305 ec.Emit (OpCodes.Ldtoken, fb);
8306 ec.Emit (OpCodes.Call, m);
8311 // Emits pieces of the array that can not be computed at compile
8312 // time (variables and string locations).
8314 // This always expect the top value on the stack to be the array
8316 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8318 int dims = bounds.Count;
8319 var current_pos = new int [dims];
8321 for (int i = 0; i < array_data.Count; i++){
8323 Expression e = array_data [i];
8324 var c = e as Constant;
8326 // Constant can be initialized via StaticInitializer
8327 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8331 if (stackArray != null) {
8332 if (e.ContainsEmitWithAwait ()) {
8333 e = e.EmitToField (ec);
8336 stackArray.EmitLoad (ec);
8338 ec.Emit (OpCodes.Dup);
8341 for (int idx = 0; idx < dims; idx++)
8342 ec.EmitInt (current_pos [idx]);
8345 // If we are dealing with a struct, get the
8346 // address of it, so we can store it.
8348 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8349 ec.Emit (OpCodes.Ldelema, etype);
8353 ec.EmitArrayStore ((ArrayContainer) type);
8359 for (int j = dims - 1; j >= 0; j--){
8361 if (current_pos [j] < bounds [j])
8363 current_pos [j] = 0;
8367 if (stackArray != null)
8368 stackArray.PrepareCleanup (ec);
8371 public override void Emit (EmitContext ec)
8373 var await_field = EmitToFieldSource (ec);
8374 if (await_field != null)
8375 await_field.Emit (ec);
8378 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8380 if (first_emit != null) {
8381 first_emit.Emit (ec);
8382 first_emit_temp.Store (ec);
8385 StackFieldExpr await_stack_field;
8386 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8387 await_stack_field = ec.GetTemporaryField (type);
8390 await_stack_field = null;
8393 EmitExpressionsList (ec, arguments);
8395 ec.EmitArrayNew ((ArrayContainer) type);
8397 if (initializers == null)
8398 return await_stack_field;
8400 if (await_stack_field != null)
8401 await_stack_field.EmitAssignFromStack (ec);
8405 // Emit static initializer for arrays which contain more than 2 items and
8406 // the static initializer will initialize at least 25% of array values or there
8407 // is more than 10 items to be initialized
8409 // NOTE: const_initializers_count does not contain default constant values.
8411 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8412 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8413 EmitStaticInitializers (ec, await_stack_field);
8415 if (!only_constant_initializers)
8416 EmitDynamicInitializers (ec, false, await_stack_field);
8420 EmitDynamicInitializers (ec, true, await_stack_field);
8423 if (first_emit_temp != null)
8424 first_emit_temp.Release (ec);
8426 return await_stack_field;
8429 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8431 // no multi dimensional or jagged arrays
8432 if (arguments.Count != 1 || array_element_type.IsArray) {
8433 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8437 // No array covariance, except for array -> object
8438 if (type != targetType) {
8439 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8440 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8444 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8445 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8450 // Single dimensional array of 0 size
8451 if (array_data == null) {
8452 IntConstant ic = arguments[0] as IntConstant;
8453 if (ic == null || !ic.IsDefaultValue) {
8454 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8462 enc.Encode (array_data.Count);
8463 foreach (var element in array_data) {
8464 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8468 protected override void CloneTo (CloneContext clonectx, Expression t)
8470 ArrayCreation target = (ArrayCreation) t;
8472 if (requested_base_type != null)
8473 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8475 if (arguments != null){
8476 target.arguments = new List<Expression> (arguments.Count);
8477 foreach (Expression e in arguments)
8478 target.arguments.Add (e.Clone (clonectx));
8481 if (initializers != null)
8482 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8485 public override object Accept (StructuralVisitor visitor)
8487 return visitor.Visit (this);
8492 // Represents an implicitly typed array epxression
8494 class ImplicitlyTypedArrayCreation : ArrayCreation
8496 TypeInferenceContext best_type_inference;
8498 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8499 : base (null, rank, initializers, loc)
8503 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8504 : base (null, initializers, loc)
8508 protected override Expression DoResolve (ResolveContext ec)
8513 dimensions = rank.Dimension;
8515 best_type_inference = new TypeInferenceContext ();
8517 if (!ResolveInitializers (ec))
8520 best_type_inference.FixAllTypes (ec);
8521 array_element_type = best_type_inference.InferredTypeArguments[0];
8522 best_type_inference = null;
8524 if (array_element_type == null ||
8525 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8526 arguments.Count != rank.Dimension) {
8527 ec.Report.Error (826, loc,
8528 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8533 // At this point we found common base type for all initializer elements
8534 // but we have to be sure that all static initializer elements are of
8537 UnifyInitializerElement (ec);
8539 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8540 eclass = ExprClass.Value;
8545 // Converts static initializer only
8547 void UnifyInitializerElement (ResolveContext ec)
8549 for (int i = 0; i < array_data.Count; ++i) {
8550 Expression e = array_data[i];
8552 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8556 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8558 element = element.Resolve (ec);
8559 if (element != null)
8560 best_type_inference.AddCommonTypeBound (element.Type);
8566 sealed class CompilerGeneratedThis : This
8568 public CompilerGeneratedThis (TypeSpec type, Location loc)
8574 protected override Expression DoResolve (ResolveContext rc)
8576 eclass = ExprClass.Variable;
8578 var block = rc.CurrentBlock;
8579 if (block != null) {
8580 var top = block.ParametersBlock.TopBlock;
8581 if (top.ThisVariable != null)
8582 variable_info = top.ThisVariable.VariableInfo;
8589 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8591 return DoResolve (rc);
8594 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8601 /// Represents the `this' construct
8604 public class This : VariableReference
8606 sealed class ThisVariable : ILocalVariable
8608 public static readonly ILocalVariable Instance = new ThisVariable ();
8610 public void Emit (EmitContext ec)
8615 public void EmitAssign (EmitContext ec)
8617 throw new InvalidOperationException ();
8620 public void EmitAddressOf (EmitContext ec)
8626 protected VariableInfo variable_info;
8628 public This (Location loc)
8635 public override string Name {
8636 get { return "this"; }
8639 public override bool IsLockedByStatement {
8647 public override bool IsRef {
8648 get { return type.IsStruct; }
8651 public override bool IsSideEffectFree {
8657 protected override ILocalVariable Variable {
8658 get { return ThisVariable.Instance; }
8661 public override VariableInfo VariableInfo {
8662 get { return variable_info; }
8665 public override bool IsFixed {
8666 get { return false; }
8671 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8674 // It's null for all cases when we don't need to check `this'
8675 // definitive assignment
8677 if (variable_info == null)
8680 if (fc.IsDefinitelyAssigned (variable_info))
8683 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8686 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8688 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8689 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8690 } else if (ec.CurrentAnonymousMethod != null) {
8691 ec.Report.Error (1673, loc,
8692 "Anonymous methods inside structs cannot access instance members of `this'. " +
8693 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8695 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8699 public override void FlowAnalysis (FlowAnalysisContext fc)
8701 CheckStructThisDefiniteAssignment (fc);
8704 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8709 AnonymousMethodStorey storey = ae.Storey;
8710 return storey != null ? storey.HoistedThis : null;
8713 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8715 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8718 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8721 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8727 public virtual void ResolveBase (ResolveContext ec)
8729 eclass = ExprClass.Variable;
8730 type = ec.CurrentType;
8732 if (!IsThisAvailable (ec, false)) {
8733 Error_ThisNotAvailable (ec);
8737 var block = ec.CurrentBlock;
8738 if (block != null) {
8739 var top = block.ParametersBlock.TopBlock;
8740 if (top.ThisVariable != null)
8741 variable_info = top.ThisVariable.VariableInfo;
8743 AnonymousExpression am = ec.CurrentAnonymousMethod;
8744 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8746 // Hoisted this is almost like hoisted variable but not exactly. When
8747 // there is no variable hoisted we can simply emit an instance method
8748 // without lifting this into a storey. Unfotunatelly this complicates
8749 // things in other cases because we don't know where this will be hoisted
8750 // until top-level block is fully resolved
8752 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8753 am.SetHasThisAccess ();
8758 protected override Expression DoResolve (ResolveContext ec)
8764 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8766 if (eclass == ExprClass.Unresolved)
8770 if (right_side == EmptyExpression.UnaryAddress)
8771 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8772 else if (right_side == EmptyExpression.OutAccess)
8773 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8775 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8781 public override int GetHashCode()
8783 throw new NotImplementedException ();
8786 public override bool Equals (object obj)
8788 This t = obj as This;
8795 protected override void CloneTo (CloneContext clonectx, Expression t)
8800 public override void SetHasAddressTaken ()
8805 public override object Accept (StructuralVisitor visitor)
8807 return visitor.Visit (this);
8812 /// Represents the `__arglist' construct
8814 public class ArglistAccess : Expression
8816 public ArglistAccess (Location loc)
8821 protected override void CloneTo (CloneContext clonectx, Expression target)
8826 public override bool ContainsEmitWithAwait ()
8831 public override Expression CreateExpressionTree (ResolveContext ec)
8833 throw new NotSupportedException ("ET");
8836 protected override Expression DoResolve (ResolveContext ec)
8838 eclass = ExprClass.Variable;
8839 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8841 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8842 ec.Report.Error (190, loc,
8843 "The __arglist construct is valid only within a variable argument method");
8849 public override void Emit (EmitContext ec)
8851 ec.Emit (OpCodes.Arglist);
8854 public override object Accept (StructuralVisitor visitor)
8856 return visitor.Visit (this);
8861 /// Represents the `__arglist (....)' construct
8863 public class Arglist : Expression
8865 Arguments arguments;
8867 public Arglist (Location loc)
8872 public Arglist (Arguments args, Location l)
8878 public Arguments Arguments {
8884 public MetaType[] ArgumentTypes {
8886 if (arguments == null)
8887 return MetaType.EmptyTypes;
8889 var retval = new MetaType[arguments.Count];
8890 for (int i = 0; i < retval.Length; i++)
8891 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8897 public override bool ContainsEmitWithAwait ()
8899 throw new NotImplementedException ();
8902 public override Expression CreateExpressionTree (ResolveContext ec)
8904 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8908 protected override Expression DoResolve (ResolveContext ec)
8910 eclass = ExprClass.Variable;
8911 type = InternalType.Arglist;
8912 if (arguments != null) {
8913 bool dynamic; // Can be ignored as there is always only 1 overload
8914 arguments.Resolve (ec, out dynamic);
8920 public override void Emit (EmitContext ec)
8922 if (arguments != null)
8923 arguments.Emit (ec);
8926 protected override void CloneTo (CloneContext clonectx, Expression t)
8928 Arglist target = (Arglist) t;
8930 if (arguments != null)
8931 target.arguments = arguments.Clone (clonectx);
8934 public override object Accept (StructuralVisitor visitor)
8936 return visitor.Visit (this);
8940 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8942 FullNamedExpression texpr;
8944 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8951 public FullNamedExpression TypeExpression {
8957 public override bool ContainsEmitWithAwait ()
8962 public void AddressOf (EmitContext ec, AddressOp mode)
8965 ec.Emit (OpCodes.Refanyval, type);
8968 protected override Expression DoResolve (ResolveContext rc)
8970 expr = expr.Resolve (rc);
8971 type = texpr.ResolveAsType (rc);
8972 if (expr == null || type == null)
8975 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8976 eclass = ExprClass.Variable;
8980 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8982 return DoResolve (rc);
8985 public override void Emit (EmitContext ec)
8988 ec.Emit (OpCodes.Refanyval, type);
8989 ec.EmitLoadFromPtr (type);
8992 public void Emit (EmitContext ec, bool leave_copy)
8994 throw new NotImplementedException ();
8997 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9000 ec.Emit (OpCodes.Refanyval, type);
9003 LocalTemporary temporary = null;
9005 ec.Emit (OpCodes.Dup);
9006 temporary = new LocalTemporary (source.Type);
9007 temporary.Store (ec);
9010 ec.EmitStoreFromPtr (type);
9012 if (temporary != null) {
9013 temporary.Emit (ec);
9014 temporary.Release (ec);
9018 public override object Accept (StructuralVisitor visitor)
9020 return visitor.Visit (this);
9024 public class RefTypeExpr : ShimExpression
9026 public RefTypeExpr (Expression expr, Location loc)
9032 protected override Expression DoResolve (ResolveContext rc)
9034 expr = expr.Resolve (rc);
9038 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9042 type = rc.BuiltinTypes.Type;
9043 eclass = ExprClass.Value;
9047 public override void Emit (EmitContext ec)
9050 ec.Emit (OpCodes.Refanytype);
9051 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9053 ec.Emit (OpCodes.Call, m);
9056 public override object Accept (StructuralVisitor visitor)
9058 return visitor.Visit (this);
9062 public class MakeRefExpr : ShimExpression
9064 public MakeRefExpr (Expression expr, Location loc)
9070 public override bool ContainsEmitWithAwait ()
9072 throw new NotImplementedException ();
9075 protected override Expression DoResolve (ResolveContext rc)
9077 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9078 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9079 eclass = ExprClass.Value;
9083 public override void Emit (EmitContext ec)
9085 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9086 ec.Emit (OpCodes.Mkrefany, expr.Type);
9089 public override object Accept (StructuralVisitor visitor)
9091 return visitor.Visit (this);
9096 /// Implements the typeof operator
9098 public class TypeOf : Expression {
9099 FullNamedExpression QueriedType;
9102 public TypeOf (FullNamedExpression queried_type, Location l)
9104 QueriedType = queried_type;
9109 // Use this constructor for any compiler generated typeof expression
9111 public TypeOf (TypeSpec type, Location loc)
9113 this.typearg = type;
9119 public override bool IsSideEffectFree {
9125 public TypeSpec TypeArgument {
9131 public FullNamedExpression TypeExpression {
9140 protected override void CloneTo (CloneContext clonectx, Expression t)
9142 TypeOf target = (TypeOf) t;
9143 if (QueriedType != null)
9144 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9147 public override bool ContainsEmitWithAwait ()
9152 public override Expression CreateExpressionTree (ResolveContext ec)
9154 Arguments args = new Arguments (2);
9155 args.Add (new Argument (this));
9156 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9157 return CreateExpressionFactoryCall (ec, "Constant", args);
9160 protected override Expression DoResolve (ResolveContext ec)
9162 if (eclass != ExprClass.Unresolved)
9165 if (typearg == null) {
9167 // Pointer types are allowed without explicit unsafe, they are just tokens
9169 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9170 typearg = QueriedType.ResolveAsType (ec, true);
9173 if (typearg == null)
9176 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9177 ec.Report.Error (1962, QueriedType.Location,
9178 "The typeof operator cannot be used on the dynamic type");
9182 type = ec.BuiltinTypes.Type;
9184 // Even though what is returned is a type object, it's treated as a value by the compiler.
9185 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9186 eclass = ExprClass.Value;
9190 static bool ContainsDynamicType (TypeSpec type)
9192 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9195 var element_container = type as ElementTypeSpec;
9196 if (element_container != null)
9197 return ContainsDynamicType (element_container.Element);
9199 foreach (var t in type.TypeArguments) {
9200 if (ContainsDynamicType (t)) {
9208 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9210 // Target type is not System.Type therefore must be object
9211 // and we need to use different encoding sequence
9212 if (targetType != type)
9215 if (typearg is InflatedTypeSpec) {
9218 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9219 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9220 typearg.GetSignatureForError ());
9224 gt = gt.DeclaringType;
9225 } while (gt != null);
9228 if (ContainsDynamicType (typearg)) {
9229 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9233 enc.EncodeTypeName (typearg);
9236 public override void Emit (EmitContext ec)
9238 ec.Emit (OpCodes.Ldtoken, typearg);
9239 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9241 ec.Emit (OpCodes.Call, m);
9244 public override object Accept (StructuralVisitor visitor)
9246 return visitor.Visit (this);
9250 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9252 public TypeOfMethod (MethodSpec method, Location loc)
9253 : base (method, loc)
9257 protected override Expression DoResolve (ResolveContext ec)
9259 if (member.IsConstructor) {
9260 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9262 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9268 return base.DoResolve (ec);
9271 public override void Emit (EmitContext ec)
9273 ec.Emit (OpCodes.Ldtoken, member);
9276 ec.Emit (OpCodes.Castclass, type);
9279 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9281 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9284 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9286 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9290 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9292 protected readonly T member;
9294 protected TypeOfMember (T member, Location loc)
9296 this.member = member;
9300 public override bool IsSideEffectFree {
9306 public override bool ContainsEmitWithAwait ()
9311 public override Expression CreateExpressionTree (ResolveContext ec)
9313 Arguments args = new Arguments (2);
9314 args.Add (new Argument (this));
9315 args.Add (new Argument (new TypeOf (type, loc)));
9316 return CreateExpressionFactoryCall (ec, "Constant", args);
9319 protected override Expression DoResolve (ResolveContext ec)
9321 eclass = ExprClass.Value;
9325 public override void Emit (EmitContext ec)
9327 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9328 PredefinedMember<MethodSpec> p;
9330 p = GetTypeFromHandleGeneric (ec);
9331 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9333 p = GetTypeFromHandle (ec);
9336 var mi = p.Resolve (loc);
9338 ec.Emit (OpCodes.Call, mi);
9341 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9342 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9345 sealed class TypeOfField : TypeOfMember<FieldSpec>
9347 public TypeOfField (FieldSpec field, Location loc)
9352 protected override Expression DoResolve (ResolveContext ec)
9354 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9358 return base.DoResolve (ec);
9361 public override void Emit (EmitContext ec)
9363 ec.Emit (OpCodes.Ldtoken, member);
9367 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9369 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9372 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9374 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9379 /// Implements the sizeof expression
9381 public class SizeOf : Expression {
9382 readonly Expression texpr;
9383 TypeSpec type_queried;
9385 public SizeOf (Expression queried_type, Location l)
9387 this.texpr = queried_type;
9391 public override bool IsSideEffectFree {
9397 public Expression TypeExpression {
9403 public override bool ContainsEmitWithAwait ()
9408 public override Expression CreateExpressionTree (ResolveContext ec)
9410 Error_PointerInsideExpressionTree (ec);
9414 protected override Expression DoResolve (ResolveContext ec)
9416 type_queried = texpr.ResolveAsType (ec);
9417 if (type_queried == null)
9420 if (type_queried.IsEnum)
9421 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9423 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9425 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9428 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9433 ec.Report.Error (233, loc,
9434 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9435 type_queried.GetSignatureForError ());
9438 type = ec.BuiltinTypes.Int;
9439 eclass = ExprClass.Value;
9443 public override void Emit (EmitContext ec)
9445 ec.Emit (OpCodes.Sizeof, type_queried);
9448 protected override void CloneTo (CloneContext clonectx, Expression t)
9452 public override object Accept (StructuralVisitor visitor)
9454 return visitor.Visit (this);
9459 /// Implements the qualified-alias-member (::) expression.
9461 public class QualifiedAliasMember : MemberAccess
9463 readonly string alias;
9464 public static readonly string GlobalAlias = "global";
9466 public QualifiedAliasMember (string alias, string identifier, Location l)
9467 : base (null, identifier, l)
9472 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9473 : base (null, identifier, targs, l)
9478 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9479 : base (null, identifier, arity, l)
9484 public string Alias {
9490 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9492 if (alias == GlobalAlias)
9493 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9495 int errors = mc.Module.Compiler.Report.Errors;
9496 var expr = mc.LookupNamespaceAlias (alias);
9498 if (errors == mc.Module.Compiler.Report.Errors)
9499 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9507 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9509 expr = CreateExpressionFromAlias (mc);
9513 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9516 protected override Expression DoResolve (ResolveContext rc)
9518 return ResolveAsTypeOrNamespace (rc, false);
9521 public override string GetSignatureForError ()
9524 if (targs != null) {
9525 name = Name + "<" + targs.GetSignatureForError () + ">";
9528 return alias + "::" + name;
9531 public override bool HasConditionalAccess ()
9536 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9538 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9539 rc.Module.Compiler.Report.Error (687, loc,
9540 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9541 GetSignatureForError ());
9546 return DoResolve (rc);
9549 protected override void CloneTo (CloneContext clonectx, Expression t)
9554 public override object Accept (StructuralVisitor visitor)
9556 return visitor.Visit (this);
9561 /// Implements the member access expression
9563 public class MemberAccess : ATypeNameExpression
9565 protected Expression expr;
9567 public MemberAccess (Expression expr, string id)
9568 : base (id, expr.Location)
9573 public MemberAccess (Expression expr, string identifier, Location loc)
9574 : base (identifier, loc)
9579 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9580 : base (identifier, args, loc)
9585 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9586 : base (identifier, arity, loc)
9591 public Expression LeftExpression {
9597 public override Location StartLocation {
9599 return expr == null ? loc : expr.StartLocation;
9603 protected override Expression DoResolve (ResolveContext rc)
9605 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
9607 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9612 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9614 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9616 if (e is TypeExpr) {
9617 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9622 e = e.ResolveLValue (rc, rhs);
9627 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9629 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9630 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9632 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9635 public override bool HasConditionalAccess ()
9637 return LeftExpression.HasConditionalAccess ();
9640 public static bool IsValidDotExpression (TypeSpec type)
9642 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9643 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9645 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9648 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9650 var sn = expr as SimpleName;
9651 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9654 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9657 // Resolve expression which does have type set as we need expression type
9658 // with disable flow analysis as we don't know whether left side expression
9659 // is used as variable or type
9661 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9662 expr = expr.Resolve (rc);
9663 } else if (expr is TypeParameterExpr) {
9664 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9668 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
9669 expr = expr.Resolve (rc, flags);
9676 var ns = expr as NamespaceExpression;
9678 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9680 if (retval == null) {
9681 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9686 if (HasTypeArguments)
9687 return new GenericTypeExpr (retval.Type, targs, loc);
9689 targs.Resolve (rc, false);
9696 TypeSpec expr_type = expr.Type;
9697 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9698 me = expr as MemberExpr;
9700 me.ResolveInstanceExpression (rc, null);
9702 Arguments args = new Arguments (1);
9703 args.Add (new Argument (expr));
9704 return new DynamicMemberBinder (Name, args, loc);
9707 var cma = this as ConditionalMemberAccess;
9709 if (!IsNullPropagatingValid (expr.Type)) {
9710 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9714 if (expr_type.IsNullableType) {
9715 expr = Nullable.Unwrap.Create (expr, true).Resolve (rc);
9716 expr_type = expr.Type;
9720 if (!IsValidDotExpression (expr_type)) {
9721 Error_OperatorCannotBeApplied (rc, expr_type);
9725 var lookup_arity = Arity;
9726 bool errorMode = false;
9727 Expression member_lookup;
9729 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9730 if (member_lookup == null) {
9732 // Try to look for extension method when member lookup failed
9734 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9735 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9736 if (methods != null) {
9737 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9738 if (HasTypeArguments) {
9739 if (!targs.Resolve (rc, false))
9742 emg.SetTypeArguments (rc, targs);
9746 emg.ConditionalAccess = true;
9748 // TODO: it should really skip the checks bellow
9749 return emg.Resolve (rc);
9755 if (member_lookup == null) {
9756 var dep = expr_type.GetMissingDependencies ();
9758 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9759 } else if (expr is TypeExpr) {
9760 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9762 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9768 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9769 // Leave it to overload resolution to report correct error
9770 } else if (!(member_lookup is TypeExpr)) {
9771 // TODO: rc.SymbolRelatedToPreviousError
9772 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9777 if (member_lookup != null)
9781 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9785 TypeExpr texpr = member_lookup as TypeExpr;
9786 if (texpr != null) {
9787 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9788 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9789 Name, texpr.GetSignatureForError ());
9792 if (!texpr.Type.IsAccessible (rc)) {
9793 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9794 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9798 if (HasTypeArguments) {
9799 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9802 return member_lookup;
9805 me = member_lookup as MemberExpr;
9807 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9812 me.ConditionalAccess = true;
9815 me = me.ResolveMemberAccess (rc, expr, sn);
9818 if (!targs.Resolve (rc, false))
9821 me.SetTypeArguments (rc, targs);
9827 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9829 FullNamedExpression fexpr = expr as FullNamedExpression;
9830 if (fexpr == null) {
9831 expr.ResolveAsType (rc);
9835 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9837 if (expr_resolved == null)
9840 var ns = expr_resolved as NamespaceExpression;
9842 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9844 if (retval == null) {
9845 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9846 } else if (Arity > 0) {
9847 if (HasTypeArguments) {
9848 retval = new GenericTypeExpr (retval.Type, targs, loc);
9849 if (retval.ResolveAsType (rc) == null)
9852 targs.Resolve (rc, allowUnboundTypeArguments);
9854 retval = new GenericOpenTypeExpr (retval.Type, loc);
9861 var tnew_expr = expr_resolved.ResolveAsType (rc);
9862 if (tnew_expr == null)
9865 TypeSpec expr_type = tnew_expr;
9866 if (TypeManager.IsGenericParameter (expr_type)) {
9867 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9868 tnew_expr.GetSignatureForError ());
9872 var qam = this as QualifiedAliasMember;
9874 rc.Module.Compiler.Report.Error (431, loc,
9875 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9880 TypeSpec nested = null;
9881 while (expr_type != null) {
9882 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9883 if (nested == null) {
9884 if (expr_type == tnew_expr) {
9885 Error_IdentifierNotFound (rc, expr_type);
9889 expr_type = tnew_expr;
9890 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9891 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9895 if (nested.IsAccessible (rc))
9899 // Keep looking after inaccessible candidate but only if
9900 // we are not in same context as the definition itself
9902 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9905 expr_type = expr_type.BaseType;
9910 if (HasTypeArguments) {
9911 texpr = new GenericTypeExpr (nested, targs, loc);
9913 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9915 texpr = new GenericOpenTypeExpr (nested, loc);
9917 } else if (expr_resolved is GenericOpenTypeExpr) {
9918 texpr = new GenericOpenTypeExpr (nested, loc);
9920 texpr = new TypeExpression (nested, loc);
9923 if (texpr.ResolveAsType (rc) == null)
9929 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9931 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9933 if (nested != null) {
9934 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9938 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9939 if (any_other_member != null) {
9940 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9944 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9945 Name, expr_type.GetSignatureForError ());
9948 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9950 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9953 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9955 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9956 ec.Report.SymbolRelatedToPreviousError (type);
9958 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9960 // a using directive or an assembly reference
9962 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9964 missing = "an assembly reference";
9967 ec.Report.Error (1061, loc,
9968 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9969 type.GetSignatureForError (), name, missing);
9973 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9976 public override string GetSignatureForError ()
9978 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9981 protected override void CloneTo (CloneContext clonectx, Expression t)
9983 MemberAccess target = (MemberAccess) t;
9985 target.expr = expr.Clone (clonectx);
9988 public override object Accept (StructuralVisitor visitor)
9990 return visitor.Visit (this);
9994 public class ConditionalMemberAccess : MemberAccess
9996 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9997 : base (expr, identifier, args, loc)
10001 public override bool HasConditionalAccess ()
10008 /// Implements checked expressions
10010 public class CheckedExpr : Expression {
10012 public Expression Expr;
10014 public CheckedExpr (Expression e, Location l)
10020 public override bool ContainsEmitWithAwait ()
10022 return Expr.ContainsEmitWithAwait ();
10025 public override Expression CreateExpressionTree (ResolveContext ec)
10027 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10028 return Expr.CreateExpressionTree (ec);
10031 protected override Expression DoResolve (ResolveContext ec)
10033 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10034 Expr = Expr.Resolve (ec);
10039 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10042 eclass = Expr.eclass;
10047 public override void Emit (EmitContext ec)
10049 using (ec.With (EmitContext.Options.CheckedScope, true))
10053 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10055 using (ec.With (EmitContext.Options.CheckedScope, true))
10056 Expr.EmitBranchable (ec, target, on_true);
10059 public override void FlowAnalysis (FlowAnalysisContext fc)
10061 Expr.FlowAnalysis (fc);
10064 public override SLE.Expression MakeExpression (BuilderContext ctx)
10066 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10067 return Expr.MakeExpression (ctx);
10071 protected override void CloneTo (CloneContext clonectx, Expression t)
10073 CheckedExpr target = (CheckedExpr) t;
10075 target.Expr = Expr.Clone (clonectx);
10078 public override object Accept (StructuralVisitor visitor)
10080 return visitor.Visit (this);
10085 /// Implements the unchecked expression
10087 public class UnCheckedExpr : Expression {
10089 public Expression Expr;
10091 public UnCheckedExpr (Expression e, Location l)
10097 public override bool ContainsEmitWithAwait ()
10099 return Expr.ContainsEmitWithAwait ();
10102 public override Expression CreateExpressionTree (ResolveContext ec)
10104 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10105 return Expr.CreateExpressionTree (ec);
10108 protected override Expression DoResolve (ResolveContext ec)
10110 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10111 Expr = Expr.Resolve (ec);
10116 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10119 eclass = Expr.eclass;
10124 public override void Emit (EmitContext ec)
10126 using (ec.With (EmitContext.Options.CheckedScope, false))
10130 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10132 using (ec.With (EmitContext.Options.CheckedScope, false))
10133 Expr.EmitBranchable (ec, target, on_true);
10136 public override void FlowAnalysis (FlowAnalysisContext fc)
10138 Expr.FlowAnalysis (fc);
10141 protected override void CloneTo (CloneContext clonectx, Expression t)
10143 UnCheckedExpr target = (UnCheckedExpr) t;
10145 target.Expr = Expr.Clone (clonectx);
10148 public override object Accept (StructuralVisitor visitor)
10150 return visitor.Visit (this);
10155 /// An Element Access expression.
10157 /// During semantic analysis these are transformed into
10158 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10160 public class ElementAccess : Expression
10162 public Arguments Arguments;
10163 public Expression Expr;
10165 public ElementAccess (Expression e, Arguments args, Location loc)
10169 this.Arguments = args;
10172 public bool ConditionalAccess { get; set; }
10174 public override Location StartLocation {
10176 return Expr.StartLocation;
10180 public override bool ContainsEmitWithAwait ()
10182 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10186 // We perform some simple tests, and then to "split" the emit and store
10187 // code we create an instance of a different class, and return that.
10189 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10191 Expr = Expr.Resolve (ec);
10197 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10198 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10203 return new ArrayAccess (this, loc) {
10204 ConditionalAccess = ConditionalAccess,
10205 ConditionalAccessReceiver = conditionalAccessReceiver
10208 if (type.IsPointer)
10209 return Expr.MakePointerAccess (ec, type, Arguments);
10211 FieldExpr fe = Expr as FieldExpr;
10213 var ff = fe.Spec as FixedFieldSpec;
10215 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10219 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10220 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10221 var indexer = new IndexerExpr (indexers, type, this) {
10222 ConditionalAccess = ConditionalAccess
10225 if (conditionalAccessReceiver)
10226 indexer.SetConditionalAccessReceiver ();
10231 Error_CannotApplyIndexing (ec, type, loc);
10236 public override Expression CreateExpressionTree (ResolveContext ec)
10238 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10239 Expr.CreateExpressionTree (ec));
10241 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10244 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10246 if (type != InternalType.ErrorType) {
10247 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10248 type.GetSignatureForError ());
10252 public override bool HasConditionalAccess ()
10254 return ConditionalAccess || Expr.HasConditionalAccess ();
10257 protected override Expression DoResolve (ResolveContext rc)
10260 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
10261 if (HasConditionalAccess ()) {
10262 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
10263 expr = CreateAccessExpression (rc, true);
10267 return expr.Resolve (rc);
10272 expr = CreateAccessExpression (rc, false);
10276 return expr.Resolve (rc);
10279 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10281 var res = CreateAccessExpression (ec, false);
10285 return res.ResolveLValue (ec, rhs);
10288 public override void Emit (EmitContext ec)
10290 throw new Exception ("Should never be reached");
10293 public override void FlowAnalysis (FlowAnalysisContext fc)
10295 Expr.FlowAnalysis (fc);
10297 if (ConditionalAccess)
10298 fc.BranchConditionalAccessDefiniteAssignment ();
10300 Arguments.FlowAnalysis (fc);
10303 public override string GetSignatureForError ()
10305 return Expr.GetSignatureForError ();
10308 protected override void CloneTo (CloneContext clonectx, Expression t)
10310 ElementAccess target = (ElementAccess) t;
10312 target.Expr = Expr.Clone (clonectx);
10313 if (Arguments != null)
10314 target.Arguments = Arguments.Clone (clonectx);
10317 public override object Accept (StructuralVisitor visitor)
10319 return visitor.Visit (this);
10324 /// Implements array access
10326 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10328 // Points to our "data" repository
10332 LocalTemporary temp;
10334 bool? has_await_args;
10336 public ArrayAccess (ElementAccess ea_data, Location l)
10342 public bool ConditionalAccess { get; set; }
10344 public bool ConditionalAccessReceiver { get; set; }
10346 public void AddressOf (EmitContext ec, AddressOp mode)
10348 var ac = (ArrayContainer) ea.Expr.Type;
10350 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10351 LoadInstanceAndArguments (ec, false, true);
10354 LoadInstanceAndArguments (ec, false, false);
10356 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10357 ec.Emit (OpCodes.Readonly);
10359 ec.EmitArrayAddress (ac);
10362 public override Expression CreateExpressionTree (ResolveContext ec)
10364 if (ConditionalAccess)
10365 Error_NullShortCircuitInsideExpressionTree (ec);
10367 return ea.CreateExpressionTree (ec);
10370 public override bool ContainsEmitWithAwait ()
10372 return ea.ContainsEmitWithAwait ();
10375 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10377 if (HasConditionalAccess ())
10378 Error_NullPropagatingLValue (ec);
10380 return DoResolve (ec);
10383 protected override Expression DoResolve (ResolveContext ec)
10385 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10387 ea.Arguments.Resolve (ec, out dynamic);
10389 var ac = ea.Expr.Type as ArrayContainer;
10390 int rank = ea.Arguments.Count;
10391 if (ac.Rank != rank) {
10392 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10393 rank.ToString (), ac.Rank.ToString ());
10398 if (type.IsPointer && !ec.IsUnsafe) {
10399 UnsafeError (ec, ea.Location);
10402 if (ConditionalAccessReceiver)
10403 type = LiftMemberType (ec, type);
10405 foreach (Argument a in ea.Arguments) {
10406 var na = a as NamedArgument;
10408 ElementAccess.Error_NamedArgument (na, ec.Report);
10410 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10413 eclass = ExprClass.Variable;
10418 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10420 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10423 public override void FlowAnalysis (FlowAnalysisContext fc)
10425 ea.FlowAnalysis (fc);
10428 public override bool HasConditionalAccess ()
10430 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10434 // Load the array arguments into the stack.
10436 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10438 if (prepareAwait) {
10439 ea.Expr = ea.Expr.EmitToField (ec);
10441 var ie = new InstanceEmitter (ea.Expr, false);
10442 ie.Emit (ec, ConditionalAccess);
10444 if (duplicateArguments) {
10445 ec.Emit (OpCodes.Dup);
10447 var copy = new LocalTemporary (ea.Expr.Type);
10453 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10454 if (dup_args != null)
10455 ea.Arguments = dup_args;
10458 public void Emit (EmitContext ec, bool leave_copy)
10461 ec.EmitLoadFromPtr (type);
10463 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10464 LoadInstanceAndArguments (ec, false, true);
10467 if (ConditionalAccessReceiver)
10468 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10470 var ac = (ArrayContainer) ea.Expr.Type;
10471 LoadInstanceAndArguments (ec, false, false);
10472 ec.EmitArrayLoad (ac);
10474 if (ConditionalAccessReceiver)
10475 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10479 ec.Emit (OpCodes.Dup);
10480 temp = new LocalTemporary (this.type);
10485 public override void Emit (EmitContext ec)
10490 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10492 var ac = (ArrayContainer) ea.Expr.Type;
10493 TypeSpec t = source.Type;
10495 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10498 // When we are dealing with a struct, get the address of it to avoid value copy
10499 // Same cannot be done for reference type because array covariance and the
10500 // check in ldelema requires to specify the type of array element stored at the index
10502 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10503 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10505 if (has_await_args.Value) {
10506 if (source.ContainsEmitWithAwait ()) {
10507 source = source.EmitToField (ec);
10508 isCompound = false;
10512 LoadInstanceAndArguments (ec, isCompound, false);
10517 ec.EmitArrayAddress (ac);
10520 ec.Emit (OpCodes.Dup);
10524 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10526 if (has_await_args.Value) {
10527 if (source.ContainsEmitWithAwait ())
10528 source = source.EmitToField (ec);
10530 LoadInstanceAndArguments (ec, false, false);
10537 var lt = ea.Expr as LocalTemporary;
10543 ec.Emit (OpCodes.Dup);
10544 temp = new LocalTemporary (this.type);
10549 ec.EmitStoreFromPtr (t);
10551 ec.EmitArrayStore (ac);
10554 if (temp != null) {
10560 public override Expression EmitToField (EmitContext ec)
10563 // Have to be specialized for arrays to get access to
10564 // underlying element. Instead of another result copy we
10565 // need direct access to element
10569 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10571 ea.Expr = ea.Expr.EmitToField (ec);
10572 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10576 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10578 #if NET_4_0 || MOBILE_DYNAMIC
10579 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10581 throw new NotImplementedException ();
10585 public override SLE.Expression MakeExpression (BuilderContext ctx)
10587 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10590 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10592 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10593 return Arguments.MakeExpression (ea.Arguments, ctx);
10599 // Indexer access expression
10601 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10603 IList<MemberSpec> indexers;
10604 Arguments arguments;
10605 TypeSpec queried_type;
10607 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10608 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10612 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10615 this.indexers = indexers;
10616 this.queried_type = queriedType;
10617 this.InstanceExpression = instance;
10618 this.arguments = args;
10623 protected override Arguments Arguments {
10632 protected override TypeSpec DeclaringType {
10634 return best_candidate.DeclaringType;
10638 public override bool IsInstance {
10644 public override bool IsStatic {
10650 public override string KindName {
10651 get { return "indexer"; }
10654 public override string Name {
10662 public override bool ContainsEmitWithAwait ()
10664 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10667 public override Expression CreateExpressionTree (ResolveContext ec)
10669 if (ConditionalAccess) {
10670 Error_NullShortCircuitInsideExpressionTree (ec);
10673 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10674 InstanceExpression.CreateExpressionTree (ec),
10675 new TypeOfMethod (Getter, loc));
10677 return CreateExpressionFactoryCall (ec, "Call", args);
10680 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10682 LocalTemporary await_source_arg = null;
10685 emitting_compound_assignment = true;
10686 if (source is DynamicExpressionStatement) {
10691 emitting_compound_assignment = false;
10693 if (has_await_arguments) {
10694 await_source_arg = new LocalTemporary (Type);
10695 await_source_arg.Store (ec);
10697 arguments.Add (new Argument (await_source_arg));
10700 temp = await_source_arg;
10703 has_await_arguments = false;
10708 ec.Emit (OpCodes.Dup);
10709 temp = new LocalTemporary (Type);
10715 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10716 source = source.EmitToField (ec);
10718 temp = new LocalTemporary (Type);
10725 arguments.Add (new Argument (source));
10728 var call = new CallEmitter ();
10729 call.InstanceExpression = InstanceExpression;
10730 if (arguments == null)
10731 call.InstanceExpressionOnStack = true;
10733 call.Emit (ec, Setter, arguments, loc);
10735 if (temp != null) {
10738 } else if (leave_copy) {
10742 if (await_source_arg != null) {
10743 await_source_arg.Release (ec);
10747 public override void FlowAnalysis (FlowAnalysisContext fc)
10749 base.FlowAnalysis (fc);
10750 arguments.FlowAnalysis (fc);
10752 if (conditional_access_receiver)
10753 fc.ConditionalAccessEnd ();
10756 public override string GetSignatureForError ()
10758 return best_candidate.GetSignatureForError ();
10761 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10764 throw new NotSupportedException ();
10766 var value = new[] { source.MakeExpression (ctx) };
10767 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10768 #if NET_4_0 || MOBILE_DYNAMIC
10769 return SLE.Expression.Block (
10770 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10773 return args.First ();
10778 public override SLE.Expression MakeExpression (BuilderContext ctx)
10781 return base.MakeExpression (ctx);
10783 var args = Arguments.MakeExpression (arguments, ctx);
10784 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10788 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10790 if (best_candidate != null)
10793 eclass = ExprClass.IndexerAccess;
10796 arguments.Resolve (rc, out dynamic);
10798 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10801 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10802 res.BaseMembersProvider = this;
10803 res.InstanceQualifier = this;
10805 // TODO: Do I need 2 argument sets?
10806 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10807 if (best_candidate != null)
10808 type = res.BestCandidateReturnType;
10809 else if (!res.BestCandidateIsDynamic)
10814 // It has dynamic arguments
10817 Arguments args = new Arguments (arguments.Count + 1);
10819 rc.Report.Error (1972, loc,
10820 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10822 args.Add (new Argument (InstanceExpression));
10824 args.AddRange (arguments);
10826 best_candidate = null;
10827 return new DynamicIndexBinder (args, loc);
10831 // Try to avoid resolving left expression again
10833 if (right_side != null)
10834 ResolveInstanceExpression (rc, right_side);
10839 protected override void CloneTo (CloneContext clonectx, Expression t)
10841 IndexerExpr target = (IndexerExpr) t;
10843 if (arguments != null)
10844 target.arguments = arguments.Clone (clonectx);
10847 public void SetConditionalAccessReceiver ()
10849 conditional_access_receiver = true;
10852 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10854 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10857 #region IBaseMembersProvider Members
10859 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10861 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10864 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10866 if (queried_type == member.DeclaringType)
10869 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10870 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10873 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10882 // A base access expression
10884 public class BaseThis : This
10886 public BaseThis (Location loc)
10891 public BaseThis (TypeSpec type, Location loc)
10895 eclass = ExprClass.Variable;
10900 public override string Name {
10908 public override Expression CreateExpressionTree (ResolveContext ec)
10910 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10911 return base.CreateExpressionTree (ec);
10914 public override void Emit (EmitContext ec)
10918 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10919 var context_type = ec.CurrentType;
10920 ec.Emit (OpCodes.Ldobj, context_type);
10921 ec.Emit (OpCodes.Box, context_type);
10925 protected override void Error_ThisNotAvailable (ResolveContext ec)
10928 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10930 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10934 public override void ResolveBase (ResolveContext ec)
10936 base.ResolveBase (ec);
10937 type = ec.CurrentType.BaseType;
10940 public override object Accept (StructuralVisitor visitor)
10942 return visitor.Visit (this);
10947 /// This class exists solely to pass the Type around and to be a dummy
10948 /// that can be passed to the conversion functions (this is used by
10949 /// foreach implementation to typecast the object return value from
10950 /// get_Current into the proper type. All code has been generated and
10951 /// we only care about the side effect conversions to be performed
10953 /// This is also now used as a placeholder where a no-action expression
10954 /// is needed (the `New' class).
10956 public class EmptyExpression : Expression
10958 sealed class OutAccessExpression : EmptyExpression
10960 public OutAccessExpression (TypeSpec t)
10965 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10967 rc.Report.Error (206, right_side.Location,
10968 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
10974 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
10975 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
10976 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
10977 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
10978 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
10979 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
10980 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
10981 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
10983 public EmptyExpression (TypeSpec t)
10986 eclass = ExprClass.Value;
10987 loc = Location.Null;
10990 protected override void CloneTo (CloneContext clonectx, Expression target)
10994 public override bool ContainsEmitWithAwait ()
10999 public override Expression CreateExpressionTree (ResolveContext ec)
11001 throw new NotSupportedException ("ET");
11004 protected override Expression DoResolve (ResolveContext ec)
11009 public override void Emit (EmitContext ec)
11011 // nothing, as we only exist to not do anything.
11014 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11018 public override void EmitSideEffect (EmitContext ec)
11022 public override object Accept (StructuralVisitor visitor)
11024 return visitor.Visit (this);
11028 sealed class EmptyAwaitExpression : EmptyExpression
11030 public EmptyAwaitExpression (TypeSpec type)
11035 public override bool ContainsEmitWithAwait ()
11042 // Empty statement expression
11044 public sealed class EmptyExpressionStatement : ExpressionStatement
11046 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11048 private EmptyExpressionStatement ()
11050 loc = Location.Null;
11053 public override bool ContainsEmitWithAwait ()
11058 public override Expression CreateExpressionTree (ResolveContext ec)
11063 public override void EmitStatement (EmitContext ec)
11068 protected override Expression DoResolve (ResolveContext ec)
11070 eclass = ExprClass.Value;
11071 type = ec.BuiltinTypes.Object;
11075 public override void Emit (EmitContext ec)
11080 public override object Accept (StructuralVisitor visitor)
11082 return visitor.Visit (this);
11086 public class ErrorExpression : EmptyExpression
11088 public static readonly ErrorExpression Instance = new ErrorExpression ();
11090 private ErrorExpression ()
11091 : base (InternalType.ErrorType)
11095 public override Expression CreateExpressionTree (ResolveContext ec)
11100 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11105 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11109 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11113 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11117 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11121 public override object Accept (StructuralVisitor visitor)
11123 return visitor.Visit (this);
11127 public class UserCast : Expression {
11131 public UserCast (MethodSpec method, Expression source, Location l)
11133 if (source == null)
11134 throw new ArgumentNullException ("source");
11136 this.method = method;
11137 this.source = source;
11138 type = method.ReturnType;
11142 public Expression Source {
11151 public override bool ContainsEmitWithAwait ()
11153 return source.ContainsEmitWithAwait ();
11156 public override Expression CreateExpressionTree (ResolveContext ec)
11158 Arguments args = new Arguments (3);
11159 args.Add (new Argument (source.CreateExpressionTree (ec)));
11160 args.Add (new Argument (new TypeOf (type, loc)));
11161 args.Add (new Argument (new TypeOfMethod (method, loc)));
11162 return CreateExpressionFactoryCall (ec, "Convert", args);
11165 protected override Expression DoResolve (ResolveContext ec)
11167 ObsoleteAttribute oa = method.GetAttributeObsolete ();
11169 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
11171 eclass = ExprClass.Value;
11175 public override void Emit (EmitContext ec)
11178 ec.MarkCallEntry (loc);
11179 ec.Emit (OpCodes.Call, method);
11182 public override void FlowAnalysis (FlowAnalysisContext fc)
11184 source.FlowAnalysis (fc);
11187 public override string GetSignatureForError ()
11189 return TypeManager.CSharpSignature (method);
11192 public override SLE.Expression MakeExpression (BuilderContext ctx)
11195 return base.MakeExpression (ctx);
11197 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11203 // Holds additional type specifiers like ?, *, []
11205 public class ComposedTypeSpecifier
11207 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11209 public readonly int Dimension;
11210 public readonly Location Location;
11212 public ComposedTypeSpecifier (int specifier, Location loc)
11214 this.Dimension = specifier;
11215 this.Location = loc;
11219 public bool IsNullable {
11221 return Dimension == -1;
11225 public bool IsPointer {
11227 return Dimension == -2;
11231 public ComposedTypeSpecifier Next { get; set; }
11235 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11237 return new ComposedTypeSpecifier (dimension, loc);
11240 public static ComposedTypeSpecifier CreateNullable (Location loc)
11242 return new ComposedTypeSpecifier (-1, loc);
11245 public static ComposedTypeSpecifier CreatePointer (Location loc)
11247 return new ComposedTypeSpecifier (-2, loc);
11250 public string GetSignatureForError ()
11255 ArrayContainer.GetPostfixSignature (Dimension);
11257 return Next != null ? s + Next.GetSignatureForError () : s;
11262 // This class is used to "construct" the type during a typecast
11263 // operation. Since the Type.GetType class in .NET can parse
11264 // the type specification, we just use this to construct the type
11265 // one bit at a time.
11267 public class ComposedCast : TypeExpr {
11268 FullNamedExpression left;
11269 ComposedTypeSpecifier spec;
11271 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11274 throw new ArgumentNullException ("spec");
11278 this.loc = left.Location;
11281 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11283 type = left.ResolveAsType (ec);
11287 eclass = ExprClass.Type;
11289 var single_spec = spec;
11291 if (single_spec.IsNullable) {
11292 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11296 single_spec = single_spec.Next;
11297 } else if (single_spec.IsPointer) {
11298 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11301 if (!ec.IsUnsafe) {
11302 UnsafeError (ec.Module.Compiler.Report, loc);
11306 type = PointerContainer.MakeType (ec.Module, type);
11307 single_spec = single_spec.Next;
11308 } while (single_spec != null && single_spec.IsPointer);
11311 if (single_spec != null && single_spec.Dimension > 0) {
11312 if (type.IsSpecialRuntimeType) {
11313 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11314 } else if (type.IsStatic) {
11315 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11316 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11317 type.GetSignatureForError ());
11319 MakeArray (ec.Module, single_spec);
11326 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11328 if (spec.Next != null)
11329 MakeArray (module, spec.Next);
11331 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11334 public override string GetSignatureForError ()
11336 return left.GetSignatureForError () + spec.GetSignatureForError ();
11339 public override object Accept (StructuralVisitor visitor)
11341 return visitor.Visit (this);
11345 class FixedBufferPtr : Expression
11347 readonly Expression array;
11349 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11351 this.type = array_type;
11352 this.array = array;
11356 public override bool ContainsEmitWithAwait ()
11358 throw new NotImplementedException ();
11361 public override Expression CreateExpressionTree (ResolveContext ec)
11363 Error_PointerInsideExpressionTree (ec);
11367 public override void Emit(EmitContext ec)
11372 protected override Expression DoResolve (ResolveContext ec)
11374 type = PointerContainer.MakeType (ec.Module, type);
11375 eclass = ExprClass.Value;
11382 // This class is used to represent the address of an array, used
11383 // only by the Fixed statement, this generates "&a [0]" construct
11384 // for fixed (char *pa = a)
11386 class ArrayPtr : FixedBufferPtr
11388 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11389 base (array, array_type, l)
11393 public override void Emit (EmitContext ec)
11398 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11403 // Encapsulates a conversion rules required for array indexes
11405 public class ArrayIndexCast : TypeCast
11407 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11408 : base (expr, returnType)
11410 if (expr.Type == returnType) // int -> int
11411 throw new ArgumentException ("unnecessary array index conversion");
11414 public override Expression CreateExpressionTree (ResolveContext ec)
11416 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11417 return base.CreateExpressionTree (ec);
11421 public override void Emit (EmitContext ec)
11425 switch (child.Type.BuiltinType) {
11426 case BuiltinTypeSpec.Type.UInt:
11427 ec.Emit (OpCodes.Conv_U);
11429 case BuiltinTypeSpec.Type.Long:
11430 ec.Emit (OpCodes.Conv_Ovf_I);
11432 case BuiltinTypeSpec.Type.ULong:
11433 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11436 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11442 // Implements the `stackalloc' keyword
11444 public class StackAlloc : Expression {
11449 public StackAlloc (Expression type, Expression count, Location l)
11452 this.count = count;
11456 public Expression TypeExpression {
11462 public Expression CountExpression {
11468 public override bool ContainsEmitWithAwait ()
11473 public override Expression CreateExpressionTree (ResolveContext ec)
11475 throw new NotSupportedException ("ET");
11478 protected override Expression DoResolve (ResolveContext ec)
11480 count = count.Resolve (ec);
11484 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11485 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11490 Constant c = count as Constant;
11491 if (c != null && c.IsNegative) {
11492 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11495 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11496 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11499 otype = texpr.ResolveAsType (ec);
11503 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11506 type = PointerContainer.MakeType (ec.Module, otype);
11507 eclass = ExprClass.Value;
11512 public override void Emit (EmitContext ec)
11514 int size = BuiltinTypeSpec.GetSize (otype);
11519 ec.Emit (OpCodes.Sizeof, otype);
11523 ec.Emit (OpCodes.Mul_Ovf_Un);
11524 ec.Emit (OpCodes.Localloc);
11527 protected override void CloneTo (CloneContext clonectx, Expression t)
11529 StackAlloc target = (StackAlloc) t;
11530 target.count = count.Clone (clonectx);
11531 target.texpr = texpr.Clone (clonectx);
11534 public override object Accept (StructuralVisitor visitor)
11536 return visitor.Visit (this);
11541 // An object initializer expression
11543 public class ElementInitializer : Assign
11545 public readonly string Name;
11547 public ElementInitializer (string name, Expression initializer, Location loc)
11548 : base (null, initializer, loc)
11553 public bool IsDictionaryInitializer {
11555 return Name == null;
11559 protected override void CloneTo (CloneContext clonectx, Expression t)
11561 ElementInitializer target = (ElementInitializer) t;
11562 target.source = source.Clone (clonectx);
11565 public override Expression CreateExpressionTree (ResolveContext ec)
11567 Arguments args = new Arguments (2);
11568 FieldExpr fe = target as FieldExpr;
11570 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11572 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11575 Expression arg_expr;
11576 var cinit = source as CollectionOrObjectInitializers;
11577 if (cinit == null) {
11579 arg_expr = source.CreateExpressionTree (ec);
11581 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11582 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11585 args.Add (new Argument (arg_expr));
11586 return CreateExpressionFactoryCall (ec, mname, args);
11589 protected override Expression DoResolve (ResolveContext ec)
11591 if (source == null)
11592 return EmptyExpressionStatement.Instance;
11594 if (!ResolveElement (ec))
11597 if (source is CollectionOrObjectInitializers) {
11598 Expression previous = ec.CurrentInitializerVariable;
11599 ec.CurrentInitializerVariable = target;
11600 source = source.Resolve (ec);
11601 ec.CurrentInitializerVariable = previous;
11602 if (source == null)
11605 eclass = source.eclass;
11606 type = source.Type;
11610 return base.DoResolve (ec);
11613 public override void EmitStatement (EmitContext ec)
11615 if (source is CollectionOrObjectInitializers)
11618 base.EmitStatement (ec);
11621 protected virtual bool ResolveElement (ResolveContext rc)
11623 var t = rc.CurrentInitializerVariable.Type;
11624 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11625 Arguments args = new Arguments (1);
11626 args.Add (new Argument (rc.CurrentInitializerVariable));
11627 target = new DynamicMemberBinder (Name, args, loc);
11630 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11631 if (member == null) {
11632 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11634 if (member != null) {
11635 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11636 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11641 if (member == null) {
11642 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11646 var me = member as MemberExpr;
11647 if (me is EventExpr) {
11648 me = me.ResolveMemberAccess (rc, null, null);
11649 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11650 rc.Report.Error (1913, loc,
11651 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11652 member.GetSignatureForError ());
11658 rc.Report.Error (1914, loc,
11659 "Static field or property `{0}' cannot be assigned in an object initializer",
11660 me.GetSignatureForError ());
11664 me.InstanceExpression = rc.CurrentInitializerVariable;
11672 // A collection initializer expression
11674 class CollectionElementInitializer : Invocation
11676 public class ElementInitializerArgument : Argument
11678 public ElementInitializerArgument (Expression e)
11684 sealed class AddMemberAccess : MemberAccess
11686 public AddMemberAccess (Expression expr, Location loc)
11687 : base (expr, "Add", loc)
11691 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11693 if (TypeManager.HasElementType (type))
11696 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11700 public CollectionElementInitializer (Expression argument)
11701 : base (null, new Arguments (1))
11703 base.arguments.Add (new ElementInitializerArgument (argument));
11704 this.loc = argument.Location;
11707 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11708 : base (null, new Arguments (arguments.Count))
11710 foreach (Expression e in arguments)
11711 base.arguments.Add (new ElementInitializerArgument (e));
11716 public CollectionElementInitializer (Location loc)
11717 : base (null, null)
11722 public override Expression CreateExpressionTree (ResolveContext ec)
11724 Arguments args = new Arguments (2);
11725 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11727 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11728 foreach (Argument a in arguments)
11729 expr_initializers.Add (a.CreateExpressionTree (ec));
11731 args.Add (new Argument (new ArrayCreation (
11732 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11733 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11736 protected override void CloneTo (CloneContext clonectx, Expression t)
11738 CollectionElementInitializer target = (CollectionElementInitializer) t;
11739 if (arguments != null)
11740 target.arguments = arguments.Clone (clonectx);
11743 protected override Expression DoResolve (ResolveContext ec)
11745 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11747 return base.DoResolve (ec);
11751 class DictionaryElementInitializer : ElementInitializer
11753 readonly Arguments args;
11755 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11756 : base (null, initializer, loc)
11758 this.args = arguments;
11761 public override Expression CreateExpressionTree (ResolveContext ec)
11763 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11767 protected override bool ResolveElement (ResolveContext rc)
11769 var init = rc.CurrentInitializerVariable;
11770 var type = init.Type;
11772 if (type.IsArray) {
11773 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11777 if (type.IsPointer) {
11778 target = init.MakePointerAccess (rc, type, args);
11782 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11783 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11784 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11788 target = new IndexerExpr (indexers, type, init, args, loc).Resolve (rc);
11794 // A block of object or collection initializers
11796 public class CollectionOrObjectInitializers : ExpressionStatement
11798 IList<Expression> initializers;
11799 bool is_collection_initialization;
11801 public CollectionOrObjectInitializers (Location loc)
11802 : this (new Expression[0], loc)
11806 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11808 this.initializers = initializers;
11812 public IList<Expression> Initializers {
11814 return initializers;
11818 public bool IsEmpty {
11820 return initializers.Count == 0;
11824 public bool IsCollectionInitializer {
11826 return is_collection_initialization;
11830 protected override void CloneTo (CloneContext clonectx, Expression target)
11832 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11834 t.initializers = new List<Expression> (initializers.Count);
11835 foreach (var e in initializers)
11836 t.initializers.Add (e.Clone (clonectx));
11839 public override bool ContainsEmitWithAwait ()
11841 foreach (var e in initializers) {
11842 if (e.ContainsEmitWithAwait ())
11849 public override Expression CreateExpressionTree (ResolveContext ec)
11851 return CreateExpressionTree (ec, false);
11854 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11856 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11857 foreach (Expression e in initializers) {
11858 Expression expr = e.CreateExpressionTree (ec);
11860 expr_initializers.Add (expr);
11864 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11866 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11869 protected override Expression DoResolve (ResolveContext ec)
11871 List<string> element_names = null;
11872 for (int i = 0; i < initializers.Count; ++i) {
11873 Expression initializer = initializers [i];
11874 ElementInitializer element_initializer = initializer as ElementInitializer;
11877 if (element_initializer != null) {
11878 element_names = new List<string> (initializers.Count);
11879 if (!element_initializer.IsDictionaryInitializer)
11880 element_names.Add (element_initializer.Name);
11881 } else if (initializer is CompletingExpression) {
11882 initializer.Resolve (ec);
11883 throw new InternalErrorException ("This line should never be reached");
11885 var t = ec.CurrentInitializerVariable.Type;
11886 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11887 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11888 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11889 "object initializer because type `{1}' does not implement `{2}' interface",
11890 ec.CurrentInitializerVariable.GetSignatureForError (),
11891 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11892 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11895 is_collection_initialization = true;
11898 if (is_collection_initialization != (element_initializer == null)) {
11899 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11900 is_collection_initialization ? "collection initializer" : "object initializer");
11904 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11905 if (element_names.Contains (element_initializer.Name)) {
11906 ec.Report.Error (1912, element_initializer.Location,
11907 "An object initializer includes more than one member `{0}' initialization",
11908 element_initializer.Name);
11910 element_names.Add (element_initializer.Name);
11915 Expression e = initializer.Resolve (ec);
11916 if (e == EmptyExpressionStatement.Instance)
11917 initializers.RemoveAt (i--);
11919 initializers [i] = e;
11922 type = ec.CurrentInitializerVariable.Type;
11923 if (is_collection_initialization) {
11924 if (TypeManager.HasElementType (type)) {
11925 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11926 type.GetSignatureForError ());
11930 eclass = ExprClass.Variable;
11934 public override void Emit (EmitContext ec)
11936 EmitStatement (ec);
11939 public override void EmitStatement (EmitContext ec)
11941 foreach (ExpressionStatement e in initializers) {
11942 // TODO: need location region
11943 ec.Mark (e.Location);
11944 e.EmitStatement (ec);
11948 public override void FlowAnalysis (FlowAnalysisContext fc)
11950 foreach (var initializer in initializers) {
11951 if (initializer != null)
11952 initializer.FlowAnalysis (fc);
11958 // New expression with element/object initializers
11960 public class NewInitialize : New
11963 // This class serves as a proxy for variable initializer target instances.
11964 // A real variable is assigned later when we resolve left side of an
11967 sealed class InitializerTargetExpression : Expression, IMemoryLocation
11969 NewInitialize new_instance;
11971 public InitializerTargetExpression (NewInitialize newInstance)
11973 this.type = newInstance.type;
11974 this.loc = newInstance.loc;
11975 this.eclass = newInstance.eclass;
11976 this.new_instance = newInstance;
11979 public override bool ContainsEmitWithAwait ()
11984 public override Expression CreateExpressionTree (ResolveContext ec)
11986 // Should not be reached
11987 throw new NotSupportedException ("ET");
11990 protected override Expression DoResolve (ResolveContext ec)
11995 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12000 public override void Emit (EmitContext ec)
12002 Expression e = (Expression) new_instance.instance;
12006 public override Expression EmitToField (EmitContext ec)
12008 return (Expression) new_instance.instance;
12011 #region IMemoryLocation Members
12013 public void AddressOf (EmitContext ec, AddressOp mode)
12015 new_instance.instance.AddressOf (ec, mode);
12021 CollectionOrObjectInitializers initializers;
12022 IMemoryLocation instance;
12023 DynamicExpressionStatement dynamic;
12025 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12026 : base (requested_type, arguments, l)
12028 this.initializers = initializers;
12031 public CollectionOrObjectInitializers Initializers {
12033 return initializers;
12037 protected override void CloneTo (CloneContext clonectx, Expression t)
12039 base.CloneTo (clonectx, t);
12041 NewInitialize target = (NewInitialize) t;
12042 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12045 public override bool ContainsEmitWithAwait ()
12047 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12050 public override Expression CreateExpressionTree (ResolveContext ec)
12052 Arguments args = new Arguments (2);
12053 args.Add (new Argument (base.CreateExpressionTree (ec)));
12054 if (!initializers.IsEmpty)
12055 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12057 return CreateExpressionFactoryCall (ec,
12058 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12062 protected override Expression DoResolve (ResolveContext ec)
12064 Expression e = base.DoResolve (ec);
12068 if (type.IsDelegate) {
12069 ec.Report.Error (1958, Initializers.Location,
12070 "Object and collection initializers cannot be used to instantiate a delegate");
12073 Expression previous = ec.CurrentInitializerVariable;
12074 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12075 initializers.Resolve (ec);
12076 ec.CurrentInitializerVariable = previous;
12078 dynamic = e as DynamicExpressionStatement;
12079 if (dynamic != null)
12085 public override void Emit (EmitContext ec)
12087 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12088 var fe = ec.GetTemporaryField (type);
12090 if (!Emit (ec, fe))
12099 public override bool Emit (EmitContext ec, IMemoryLocation target)
12102 // Expression is initialized into temporary target then moved
12103 // to real one for atomicity
12105 IMemoryLocation temp_target = target;
12107 LocalTemporary temp = null;
12108 bool by_ref = false;
12109 if (!initializers.IsEmpty) {
12110 temp_target = target as LocalTemporary;
12111 if (temp_target == null)
12112 temp_target = target as StackFieldExpr;
12114 if (temp_target == null) {
12115 var vr = target as VariableReference;
12116 if (vr != null && vr.IsRef) {
12122 if (temp_target == null)
12123 temp_target = temp = new LocalTemporary (type);
12126 bool left_on_stack;
12127 if (dynamic != null) {
12129 left_on_stack = true;
12131 left_on_stack = base.Emit (ec, temp_target);
12134 if (initializers.IsEmpty)
12135 return left_on_stack;
12137 StackFieldExpr sf = null;
12139 // Move a new instance (reference-type) to local temporary variable
12140 if (left_on_stack) {
12142 temp_target = temp = new LocalTemporary (type);
12148 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12150 throw new NotImplementedException ();
12152 sf = ec.GetTemporaryField (type);
12153 sf.EmitAssign (ec, temp, false, false);
12156 left_on_stack = false;
12160 instance = temp_target;
12162 initializers.Emit (ec);
12164 ((Expression)temp_target).Emit (ec);
12170 sf.IsAvailableForReuse = true;
12175 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12177 instance = base.EmitAddressOf (ec, Mode);
12179 if (!initializers.IsEmpty)
12180 initializers.Emit (ec);
12185 public override void FlowAnalysis (FlowAnalysisContext fc)
12187 base.FlowAnalysis (fc);
12188 initializers.FlowAnalysis (fc);
12191 public override object Accept (StructuralVisitor visitor)
12193 return visitor.Visit (this);
12197 public class NewAnonymousType : New
12199 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12201 List<AnonymousTypeParameter> parameters;
12202 readonly TypeContainer parent;
12203 AnonymousTypeClass anonymous_type;
12205 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12206 : base (null, null, loc)
12208 this.parameters = parameters;
12209 this.parent = parent;
12212 public List<AnonymousTypeParameter> Parameters {
12214 return this.parameters;
12218 protected override void CloneTo (CloneContext clonectx, Expression target)
12220 if (parameters == null)
12223 NewAnonymousType t = (NewAnonymousType) target;
12224 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12225 foreach (AnonymousTypeParameter atp in parameters)
12226 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12229 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12231 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12235 type = AnonymousTypeClass.Create (parent, parameters, loc);
12239 int errors = ec.Report.Errors;
12240 type.CreateContainer ();
12241 type.DefineContainer ();
12243 if ((ec.Report.Errors - errors) == 0) {
12244 parent.Module.AddAnonymousType (type);
12245 type.PrepareEmit ();
12251 public override Expression CreateExpressionTree (ResolveContext ec)
12253 if (parameters == null)
12254 return base.CreateExpressionTree (ec);
12256 var init = new ArrayInitializer (parameters.Count, loc);
12257 foreach (var m in anonymous_type.Members) {
12258 var p = m as Property;
12260 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12263 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12264 foreach (Argument a in arguments)
12265 ctor_args.Add (a.CreateExpressionTree (ec));
12267 Arguments args = new Arguments (3);
12268 args.Add (new Argument (new TypeOfMethod (method, loc)));
12269 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12270 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12272 return CreateExpressionFactoryCall (ec, "New", args);
12275 protected override Expression DoResolve (ResolveContext ec)
12277 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12278 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12282 if (parameters == null) {
12283 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12284 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12285 return base.DoResolve (ec);
12288 bool error = false;
12289 arguments = new Arguments (parameters.Count);
12290 var t_args = new TypeSpec [parameters.Count];
12291 for (int i = 0; i < parameters.Count; ++i) {
12292 Expression e = parameters [i].Resolve (ec);
12298 arguments.Add (new Argument (e));
12299 t_args [i] = e.Type;
12305 anonymous_type = CreateAnonymousType (ec, parameters);
12306 if (anonymous_type == null)
12309 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12310 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12311 eclass = ExprClass.Value;
12315 public override object Accept (StructuralVisitor visitor)
12317 return visitor.Visit (this);
12321 public class AnonymousTypeParameter : ShimExpression
12323 public readonly string Name;
12325 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12326 : base (initializer)
12332 public AnonymousTypeParameter (Parameter parameter)
12333 : base (new SimpleName (parameter.Name, parameter.Location))
12335 this.Name = parameter.Name;
12336 this.loc = parameter.Location;
12339 public override bool Equals (object o)
12341 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12342 return other != null && Name == other.Name;
12345 public override int GetHashCode ()
12347 return Name.GetHashCode ();
12350 protected override Expression DoResolve (ResolveContext ec)
12352 Expression e = expr.Resolve (ec);
12356 if (e.eclass == ExprClass.MethodGroup) {
12357 Error_InvalidInitializer (ec, e.ExprClassName);
12362 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12363 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12370 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12372 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12373 Name, initializer);
12377 public class CatchFilterExpression : BooleanExpression
12379 public CatchFilterExpression (Expression expr, Location loc)
12386 public class InterpolatedString : Expression
12388 readonly StringLiteral start, end;
12389 List<Expression> interpolations;
12390 Arguments arguments;
12392 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12394 this.start = start;
12396 this.interpolations = interpolations;
12397 loc = start.Location;
12400 protected override void CloneTo (CloneContext clonectx, Expression t)
12402 InterpolatedString target = (InterpolatedString) t;
12404 if (interpolations != null) {
12405 target.interpolations = new List<Expression> ();
12406 foreach (var interpolation in interpolations) {
12407 target.interpolations.Add (interpolation.Clone (clonectx));
12412 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12414 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12415 if (factory == null)
12418 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12419 var res = new Invocation (ma, arguments).Resolve (rc);
12420 if (res != null && res.Type != type)
12421 res = Convert.ExplicitConversion (rc, res, type, loc);
12426 public override bool ContainsEmitWithAwait ()
12428 if (interpolations == null)
12431 foreach (var expr in interpolations) {
12432 if (expr.ContainsEmitWithAwait ())
12439 public override Expression CreateExpressionTree (ResolveContext rc)
12441 var best = ResolveBestFormatOverload (rc);
12445 Expression instance = new NullLiteral (loc);
12446 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12447 return CreateExpressionFactoryCall (rc, "Call", args);
12450 protected override Expression DoResolve (ResolveContext rc)
12454 if (interpolations == null) {
12456 arguments = new Arguments (1);
12458 for (int i = 0; i < interpolations.Count; i += 2) {
12459 var ipi = (InterpolatedStringInsert)interpolations [i];
12463 arguments = new Arguments (interpolations.Count);
12465 var sb = new StringBuilder (start.Value);
12466 for (int i = 0; i < interpolations.Count; ++i) {
12468 sb.Append ('{').Append (i / 2);
12469 var isi = (InterpolatedStringInsert)interpolations [i];
12470 if (isi.Alignment != null) {
12472 var value = isi.ResolveAligment (rc);
12474 sb.Append (value.Value);
12477 if (isi.Format != null) {
12479 sb.Append (isi.Format);
12483 arguments.Add (new Argument (interpolations [i]));
12485 sb.Append (((StringLiteral)interpolations [i]).Value);
12489 sb.Append (end.Value);
12490 str = sb.ToString ();
12493 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12495 eclass = ExprClass.Value;
12496 type = rc.BuiltinTypes.String;
12500 public override void Emit (EmitContext ec)
12502 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12503 if (interpolations == null) {
12504 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12505 if (str != start.Value)
12506 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12513 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12517 var ca = new CallEmitter ();
12518 ca.Emit (ec, best, arguments, loc);
12521 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12523 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12524 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12525 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12529 public class InterpolatedStringInsert : CompositeExpression
12531 public InterpolatedStringInsert (Expression expr)
12536 public Expression Alignment { get; set; }
12537 public string Format { get; set; }
12539 protected override void CloneTo (CloneContext clonectx, Expression t)
12541 var target = (InterpolatedStringInsert)t;
12542 if (Alignment != null)
12543 target.Alignment = Alignment.Clone (clonectx);
12546 protected override Expression DoResolve (ResolveContext rc)
12548 var expr = base.DoResolve (rc);
12553 // For better error reporting, assumes the built-in implementation uses object
12556 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12559 public int? ResolveAligment (ResolveContext rc)
12561 var c = Alignment.ResolveLabelConstant (rc);
12565 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12569 var value = (int) c.GetValueAsLong ();
12570 if (value > 32767 || value < -32767) {
12571 rc.Report.Warning (8094, 1, Alignment.Location,
12572 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");