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)).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,
3175 readonly Operator oper;
3176 Expression left, right;
3178 ConvCast.Mode enum_conversion;
3180 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3181 : this (oper, left, right)
3184 state |= State.Compound;
3187 public Binary (Operator oper, Expression left, Expression right)
3188 : this (oper, left, right, left.Location)
3192 public Binary (Operator oper, Expression left, Expression right, Location loc)
3202 public bool IsCompound {
3204 return (state & State.Compound) != 0;
3208 public Operator Oper {
3214 public Expression Left {
3220 public Expression Right {
3226 public override Location StartLocation {
3228 return left.StartLocation;
3235 /// Returns a stringified representation of the Operator
3237 string OperName (Operator oper)
3241 case Operator.Multiply:
3244 case Operator.Division:
3247 case Operator.Modulus:
3250 case Operator.Addition:
3253 case Operator.Subtraction:
3256 case Operator.LeftShift:
3259 case Operator.RightShift:
3262 case Operator.LessThan:
3265 case Operator.GreaterThan:
3268 case Operator.LessThanOrEqual:
3271 case Operator.GreaterThanOrEqual:
3274 case Operator.Equality:
3277 case Operator.Inequality:
3280 case Operator.BitwiseAnd:
3283 case Operator.BitwiseOr:
3286 case Operator.ExclusiveOr:
3289 case Operator.LogicalOr:
3292 case Operator.LogicalAnd:
3296 s = oper.ToString ();
3306 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3308 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3311 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3313 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3317 l = left.Type.GetSignatureForError ();
3318 r = right.Type.GetSignatureForError ();
3320 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3324 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3326 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3329 public override void FlowAnalysis (FlowAnalysisContext fc)
3332 // Optimized version when on-true/on-false data are not needed
3334 if ((oper & Operator.LogicalMask) == 0) {
3335 left.FlowAnalysis (fc);
3336 right.FlowAnalysis (fc);
3340 left.FlowAnalysisConditional (fc);
3341 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3342 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3344 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3345 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3346 right.FlowAnalysisConditional (fc);
3348 if (oper == Operator.LogicalOr)
3349 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3351 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3354 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3356 if ((oper & Operator.LogicalMask) == 0) {
3357 base.FlowAnalysisConditional (fc);
3361 left.FlowAnalysisConditional (fc);
3362 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3363 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3365 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3366 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3367 right.FlowAnalysisConditional (fc);
3369 var lc = left as Constant;
3370 if (oper == Operator.LogicalOr) {
3371 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3372 if (lc != null && lc.IsDefaultValue)
3373 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3375 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3377 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3378 if (lc != null && !lc.IsDefaultValue)
3379 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3381 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3386 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3388 string GetOperatorExpressionTypeName ()
3391 case Operator.Addition:
3392 return IsCompound ? "AddAssign" : "Add";
3393 case Operator.BitwiseAnd:
3394 return IsCompound ? "AndAssign" : "And";
3395 case Operator.BitwiseOr:
3396 return IsCompound ? "OrAssign" : "Or";
3397 case Operator.Division:
3398 return IsCompound ? "DivideAssign" : "Divide";
3399 case Operator.ExclusiveOr:
3400 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3401 case Operator.Equality:
3403 case Operator.GreaterThan:
3404 return "GreaterThan";
3405 case Operator.GreaterThanOrEqual:
3406 return "GreaterThanOrEqual";
3407 case Operator.Inequality:
3409 case Operator.LeftShift:
3410 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3411 case Operator.LessThan:
3413 case Operator.LessThanOrEqual:
3414 return "LessThanOrEqual";
3415 case Operator.LogicalAnd:
3417 case Operator.LogicalOr:
3419 case Operator.Modulus:
3420 return IsCompound ? "ModuloAssign" : "Modulo";
3421 case Operator.Multiply:
3422 return IsCompound ? "MultiplyAssign" : "Multiply";
3423 case Operator.RightShift:
3424 return IsCompound ? "RightShiftAssign" : "RightShift";
3425 case Operator.Subtraction:
3426 return IsCompound ? "SubtractAssign" : "Subtract";
3428 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3432 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3435 case Operator.Addition:
3436 return CSharp.Operator.OpType.Addition;
3437 case Operator.BitwiseAnd:
3438 case Operator.LogicalAnd:
3439 return CSharp.Operator.OpType.BitwiseAnd;
3440 case Operator.BitwiseOr:
3441 case Operator.LogicalOr:
3442 return CSharp.Operator.OpType.BitwiseOr;
3443 case Operator.Division:
3444 return CSharp.Operator.OpType.Division;
3445 case Operator.Equality:
3446 return CSharp.Operator.OpType.Equality;
3447 case Operator.ExclusiveOr:
3448 return CSharp.Operator.OpType.ExclusiveOr;
3449 case Operator.GreaterThan:
3450 return CSharp.Operator.OpType.GreaterThan;
3451 case Operator.GreaterThanOrEqual:
3452 return CSharp.Operator.OpType.GreaterThanOrEqual;
3453 case Operator.Inequality:
3454 return CSharp.Operator.OpType.Inequality;
3455 case Operator.LeftShift:
3456 return CSharp.Operator.OpType.LeftShift;
3457 case Operator.LessThan:
3458 return CSharp.Operator.OpType.LessThan;
3459 case Operator.LessThanOrEqual:
3460 return CSharp.Operator.OpType.LessThanOrEqual;
3461 case Operator.Modulus:
3462 return CSharp.Operator.OpType.Modulus;
3463 case Operator.Multiply:
3464 return CSharp.Operator.OpType.Multiply;
3465 case Operator.RightShift:
3466 return CSharp.Operator.OpType.RightShift;
3467 case Operator.Subtraction:
3468 return CSharp.Operator.OpType.Subtraction;
3470 throw new InternalErrorException (op.ToString ());
3474 public override bool ContainsEmitWithAwait ()
3476 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3479 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3484 case Operator.Multiply:
3485 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3486 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3487 opcode = OpCodes.Mul_Ovf;
3488 else if (!IsFloat (l))
3489 opcode = OpCodes.Mul_Ovf_Un;
3491 opcode = OpCodes.Mul;
3493 opcode = OpCodes.Mul;
3497 case Operator.Division:
3499 opcode = OpCodes.Div_Un;
3501 opcode = OpCodes.Div;
3504 case Operator.Modulus:
3506 opcode = OpCodes.Rem_Un;
3508 opcode = OpCodes.Rem;
3511 case Operator.Addition:
3512 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3513 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3514 opcode = OpCodes.Add_Ovf;
3515 else if (!IsFloat (l))
3516 opcode = OpCodes.Add_Ovf_Un;
3518 opcode = OpCodes.Add;
3520 opcode = OpCodes.Add;
3523 case Operator.Subtraction:
3524 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3525 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3526 opcode = OpCodes.Sub_Ovf;
3527 else if (!IsFloat (l))
3528 opcode = OpCodes.Sub_Ovf_Un;
3530 opcode = OpCodes.Sub;
3532 opcode = OpCodes.Sub;
3535 case Operator.RightShift:
3536 if (!(right is IntConstant)) {
3537 ec.EmitInt (GetShiftMask (l));
3538 ec.Emit (OpCodes.And);
3542 opcode = OpCodes.Shr_Un;
3544 opcode = OpCodes.Shr;
3547 case Operator.LeftShift:
3548 if (!(right is IntConstant)) {
3549 ec.EmitInt (GetShiftMask (l));
3550 ec.Emit (OpCodes.And);
3553 opcode = OpCodes.Shl;
3556 case Operator.Equality:
3557 opcode = OpCodes.Ceq;
3560 case Operator.Inequality:
3561 ec.Emit (OpCodes.Ceq);
3564 opcode = OpCodes.Ceq;
3567 case Operator.LessThan:
3569 opcode = OpCodes.Clt_Un;
3571 opcode = OpCodes.Clt;
3574 case Operator.GreaterThan:
3576 opcode = OpCodes.Cgt_Un;
3578 opcode = OpCodes.Cgt;
3581 case Operator.LessThanOrEqual:
3582 if (IsUnsigned (l) || IsFloat (l))
3583 ec.Emit (OpCodes.Cgt_Un);
3585 ec.Emit (OpCodes.Cgt);
3588 opcode = OpCodes.Ceq;
3591 case Operator.GreaterThanOrEqual:
3592 if (IsUnsigned (l) || IsFloat (l))
3593 ec.Emit (OpCodes.Clt_Un);
3595 ec.Emit (OpCodes.Clt);
3599 opcode = OpCodes.Ceq;
3602 case Operator.BitwiseOr:
3603 opcode = OpCodes.Or;
3606 case Operator.BitwiseAnd:
3607 opcode = OpCodes.And;
3610 case Operator.ExclusiveOr:
3611 opcode = OpCodes.Xor;
3615 throw new InternalErrorException (oper.ToString ());
3621 static int GetShiftMask (TypeSpec type)
3623 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3626 static bool IsUnsigned (TypeSpec t)
3628 switch (t.BuiltinType) {
3629 case BuiltinTypeSpec.Type.Char:
3630 case BuiltinTypeSpec.Type.UInt:
3631 case BuiltinTypeSpec.Type.ULong:
3632 case BuiltinTypeSpec.Type.UShort:
3633 case BuiltinTypeSpec.Type.Byte:
3640 static bool IsFloat (TypeSpec t)
3642 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3645 public Expression ResolveOperator (ResolveContext rc)
3647 eclass = ExprClass.Value;
3649 TypeSpec l = left.Type;
3650 TypeSpec r = right.Type;
3652 bool primitives_only = false;
3655 // Handles predefined primitive types
3657 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3658 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3659 if ((oper & Operator.ShiftMask) == 0) {
3660 if (!DoBinaryOperatorPromotion (rc))
3663 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3667 if (l.IsPointer || r.IsPointer)
3668 return ResolveOperatorPointer (rc, l, r);
3671 expr = ResolveUserOperator (rc, left, right);
3676 bool lenum = l.IsEnum;
3677 bool renum = r.IsEnum;
3678 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3682 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3683 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3688 if ((oper & Operator.BitwiseMask) != 0) {
3689 expr = EmptyCast.Create (expr, type);
3690 enum_conversion = GetEnumResultCast (type);
3692 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3693 expr = OptimizeAndOperation (expr);
3697 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3698 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3701 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3702 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3706 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3709 // We cannot break here there is also Enum + String possible match
3710 // which is not ambiguous with predefined enum operators
3713 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3714 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3718 } else if (l.IsDelegate || r.IsDelegate) {
3722 expr = ResolveOperatorDelegate (rc, l, r);
3724 // TODO: Can this be ambiguous
3732 // Equality operators are more complicated
3734 if ((oper & Operator.EqualityMask) != 0) {
3735 return ResolveEquality (rc, l, r, primitives_only);
3738 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3742 if (primitives_only)
3746 // Lifted operators have lower priority
3748 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3751 static bool IsEnumOrNullableEnum (TypeSpec type)
3753 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3757 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3758 // if 'left' is not an enumeration constant, create one from the type of 'right'
3759 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3762 case Operator.BitwiseOr:
3763 case Operator.BitwiseAnd:
3764 case Operator.ExclusiveOr:
3765 case Operator.Equality:
3766 case Operator.Inequality:
3767 case Operator.LessThan:
3768 case Operator.LessThanOrEqual:
3769 case Operator.GreaterThan:
3770 case Operator.GreaterThanOrEqual:
3771 if (left.Type.IsEnum)
3774 if (left.IsZeroInteger)
3775 return left.Reduce (ec, right.Type);
3779 case Operator.Addition:
3780 case Operator.Subtraction:
3783 case Operator.Multiply:
3784 case Operator.Division:
3785 case Operator.Modulus:
3786 case Operator.LeftShift:
3787 case Operator.RightShift:
3788 if (right.Type.IsEnum || left.Type.IsEnum)
3797 // The `|' operator used on types which were extended is dangerous
3799 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3801 OpcodeCast lcast = left as OpcodeCast;
3802 if (lcast != null) {
3803 if (IsUnsigned (lcast.UnderlyingType))
3807 OpcodeCast rcast = right as OpcodeCast;
3808 if (rcast != null) {
3809 if (IsUnsigned (rcast.UnderlyingType))
3813 if (lcast == null && rcast == null)
3816 // FIXME: consider constants
3818 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3819 ec.Report.Warning (675, 3, loc,
3820 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3821 ltype.GetSignatureForError ());
3824 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3826 return new PredefinedOperator[] {
3828 // Pointer arithmetic:
3830 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3831 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3832 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3833 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3835 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3836 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3837 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3838 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3841 // T* operator + (int y, T* x);
3842 // T* operator + (uint y, T *x);
3843 // T* operator + (long y, T *x);
3844 // T* operator + (ulong y, T *x);
3846 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3847 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3848 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3849 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3852 // long operator - (T* x, T *y)
3854 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3858 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3860 TypeSpec bool_type = types.Bool;
3863 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3864 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3865 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3866 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3867 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3868 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3869 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3871 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3872 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3873 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3874 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3875 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3876 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3877 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3879 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3880 // Remaining string operators are in lifted tables
3882 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3884 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3885 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3886 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3890 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3892 var types = module.Compiler.BuiltinTypes;
3895 // Not strictly lifted but need to be in second group otherwise expressions like
3896 // int + null would resolve to +(object, string) instead of +(int?, int?)
3898 var string_operators = new [] {
3899 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3900 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3903 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3904 if (nullable == null)
3905 return string_operators;
3907 var bool_type = types.Bool;
3909 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3910 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3911 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3912 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3913 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3914 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3915 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3916 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3919 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3920 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3921 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3922 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3923 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3924 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3925 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3927 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3928 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3929 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3930 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3931 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3932 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3933 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3935 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3937 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3938 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3939 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3941 string_operators [0],
3942 string_operators [1]
3946 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3948 TypeSpec bool_type = types.Bool;
3951 new PredefinedEqualityOperator (types.String, bool_type),
3952 new PredefinedEqualityOperator (types.Delegate, bool_type),
3953 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3954 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3955 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3956 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3957 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3958 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3959 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3960 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3964 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3966 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3968 if (nullable == null)
3969 return new PredefinedOperator [0];
3971 var types = module.Compiler.BuiltinTypes;
3972 var bool_type = types.Bool;
3973 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3974 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3975 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3976 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3977 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3978 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3979 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3980 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3983 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3984 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3985 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3986 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3987 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3988 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3989 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3990 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3995 // 7.2.6.2 Binary numeric promotions
3997 bool DoBinaryOperatorPromotion (ResolveContext rc)
3999 TypeSpec ltype = left.Type;
4000 if (ltype.IsNullableType) {
4001 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4005 // This is numeric promotion code only
4007 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4010 TypeSpec rtype = right.Type;
4011 if (rtype.IsNullableType) {
4012 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4015 var lb = ltype.BuiltinType;
4016 var rb = rtype.BuiltinType;
4020 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4021 type = rc.BuiltinTypes.Decimal;
4022 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4023 type = rc.BuiltinTypes.Double;
4024 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4025 type = rc.BuiltinTypes.Float;
4026 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4027 type = rc.BuiltinTypes.ULong;
4029 if (IsSignedType (lb)) {
4030 expr = ConvertSignedConstant (left, type);
4034 } else if (IsSignedType (rb)) {
4035 expr = ConvertSignedConstant (right, type);
4041 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4042 type = rc.BuiltinTypes.Long;
4043 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4044 type = rc.BuiltinTypes.UInt;
4046 if (IsSignedType (lb)) {
4047 expr = ConvertSignedConstant (left, type);
4049 type = rc.BuiltinTypes.Long;
4050 } else if (IsSignedType (rb)) {
4051 expr = ConvertSignedConstant (right, type);
4053 type = rc.BuiltinTypes.Long;
4056 type = rc.BuiltinTypes.Int;
4059 if (ltype != type) {
4060 expr = PromoteExpression (rc, left, type);
4067 if (rtype != type) {
4068 expr = PromoteExpression (rc, right, type);
4078 static bool IsSignedType (BuiltinTypeSpec.Type type)
4081 case BuiltinTypeSpec.Type.Int:
4082 case BuiltinTypeSpec.Type.Short:
4083 case BuiltinTypeSpec.Type.SByte:
4084 case BuiltinTypeSpec.Type.Long:
4091 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4093 var c = expr as Constant;
4097 return c.ConvertImplicitly (type);
4100 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4102 if (expr.Type.IsNullableType) {
4103 return Convert.ImplicitConversionStandard (rc, expr,
4104 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4107 var c = expr as Constant;
4109 return c.ConvertImplicitly (type);
4111 return Convert.ImplicitNumericConversion (expr, type);
4114 protected override Expression DoResolve (ResolveContext ec)
4119 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4120 left = ((ParenthesizedExpression) left).Expr;
4121 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4125 if (left.eclass == ExprClass.Type) {
4126 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4130 left = left.Resolve (ec);
4135 right = right.Resolve (ec);
4139 Constant lc = left as Constant;
4140 Constant rc = right as Constant;
4142 // The conversion rules are ignored in enum context but why
4143 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4144 lc = EnumLiftUp (ec, lc, rc);
4146 rc = EnumLiftUp (ec, rc, lc);
4149 if (rc != null && lc != null) {
4150 int prev_e = ec.Report.Errors;
4151 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4152 if (e != null || ec.Report.Errors != prev_e)
4156 // Comparison warnings
4157 if ((oper & Operator.ComparisonMask) != 0) {
4158 if (left.Equals (right)) {
4159 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4161 CheckOutOfRangeComparison (ec, lc, right.Type);
4162 CheckOutOfRangeComparison (ec, rc, left.Type);
4165 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4166 return DoResolveDynamic (ec);
4168 return DoResolveCore (ec, left, right);
4171 Expression DoResolveDynamic (ResolveContext rc)
4174 var rt = right.Type;
4175 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4176 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4177 Error_OperatorCannotBeApplied (rc, left, right);
4184 // Special handling for logical boolean operators which require rhs not to be
4185 // evaluated based on lhs value
4187 if ((oper & Operator.LogicalMask) != 0) {
4188 Expression cond_left, cond_right, expr;
4190 args = new Arguments (2);
4192 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4193 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4195 var cond_args = new Arguments (1);
4196 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4199 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4200 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4202 left = temp.CreateReferenceExpression (rc, loc);
4203 if (oper == Operator.LogicalAnd) {
4204 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4207 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4211 args.Add (new Argument (left));
4212 args.Add (new Argument (right));
4213 cond_right = new DynamicExpressionStatement (this, args, loc);
4215 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4217 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4218 rc.Report.Error (7083, left.Location,
4219 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4220 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4224 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4225 args.Add (new Argument (right));
4226 right = new DynamicExpressionStatement (this, args, loc);
4229 // bool && dynamic => (temp = left) ? temp && right : temp;
4230 // bool || dynamic => (temp = left) ? temp : temp || right;
4232 if (oper == Operator.LogicalAnd) {
4234 cond_right = temp.CreateReferenceExpression (rc, loc);
4236 cond_left = temp.CreateReferenceExpression (rc, loc);
4240 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4243 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4246 args = new Arguments (2);
4247 args.Add (new Argument (left));
4248 args.Add (new Argument (right));
4249 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4252 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4254 Expression expr = ResolveOperator (ec);
4256 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4258 if (left == null || right == null)
4259 throw new InternalErrorException ("Invalid conversion");
4261 if (oper == Operator.BitwiseOr)
4262 CheckBitwiseOrOnSignExtended (ec);
4267 public override SLE.Expression MakeExpression (BuilderContext ctx)
4269 return MakeExpression (ctx, left, right);
4272 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4274 var le = left.MakeExpression (ctx);
4275 var re = right.MakeExpression (ctx);
4276 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4279 case Operator.Addition:
4280 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4281 case Operator.BitwiseAnd:
4282 return SLE.Expression.And (le, re);
4283 case Operator.BitwiseOr:
4284 return SLE.Expression.Or (le, re);
4285 case Operator.Division:
4286 return SLE.Expression.Divide (le, re);
4287 case Operator.Equality:
4288 return SLE.Expression.Equal (le, re);
4289 case Operator.ExclusiveOr:
4290 return SLE.Expression.ExclusiveOr (le, re);
4291 case Operator.GreaterThan:
4292 return SLE.Expression.GreaterThan (le, re);
4293 case Operator.GreaterThanOrEqual:
4294 return SLE.Expression.GreaterThanOrEqual (le, re);
4295 case Operator.Inequality:
4296 return SLE.Expression.NotEqual (le, re);
4297 case Operator.LeftShift:
4298 return SLE.Expression.LeftShift (le, re);
4299 case Operator.LessThan:
4300 return SLE.Expression.LessThan (le, re);
4301 case Operator.LessThanOrEqual:
4302 return SLE.Expression.LessThanOrEqual (le, re);
4303 case Operator.LogicalAnd:
4304 return SLE.Expression.AndAlso (le, re);
4305 case Operator.LogicalOr:
4306 return SLE.Expression.OrElse (le, re);
4307 case Operator.Modulus:
4308 return SLE.Expression.Modulo (le, re);
4309 case Operator.Multiply:
4310 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4311 case Operator.RightShift:
4312 return SLE.Expression.RightShift (le, re);
4313 case Operator.Subtraction:
4314 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4316 throw new NotImplementedException (oper.ToString ());
4321 // D operator + (D x, D y)
4322 // D operator - (D x, D y)
4324 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4326 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4328 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4329 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4334 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4335 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4345 MethodSpec method = null;
4346 Arguments args = new Arguments (2);
4347 args.Add (new Argument (left));
4348 args.Add (new Argument (right));
4350 if (oper == Operator.Addition) {
4351 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4352 } else if (oper == Operator.Subtraction) {
4353 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4357 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4359 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4360 return new ClassCast (expr, l);
4364 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4366 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4369 // bool operator == (E x, E y);
4370 // bool operator != (E x, E y);
4371 // bool operator < (E x, E y);
4372 // bool operator > (E x, E y);
4373 // bool operator <= (E x, E y);
4374 // bool operator >= (E x, E y);
4376 // E operator & (E x, E y);
4377 // E operator | (E x, E y);
4378 // E operator ^ (E x, E y);
4381 if ((oper & Operator.ComparisonMask) != 0) {
4382 type = rc.BuiltinTypes.Bool;
4388 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4394 if (ltype == rtype) {
4398 var lifted = new Nullable.LiftedBinaryOperator (this);
4400 lifted.Right = right;
4401 return lifted.Resolve (rc);
4404 if (renum && !ltype.IsNullableType) {
4405 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4410 } else if (lenum && !rtype.IsNullableType) {
4411 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4419 // Now try lifted version of predefined operator
4421 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4422 if (nullable_type != null) {
4423 if (renum && !ltype.IsNullableType) {
4424 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4426 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4429 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4432 if ((oper & Operator.BitwiseMask) != 0)
4436 if ((oper & Operator.BitwiseMask) != 0)
4437 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4439 return CreateLiftedValueTypeResult (rc, rtype);
4443 var lifted = new Nullable.LiftedBinaryOperator (this);
4445 lifted.Right = right;
4446 return lifted.Resolve (rc);
4448 } else if (lenum && !rtype.IsNullableType) {
4449 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4451 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4454 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4457 if ((oper & Operator.BitwiseMask) != 0)
4461 if ((oper & Operator.BitwiseMask) != 0)
4462 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4464 return CreateLiftedValueTypeResult (rc, ltype);
4468 var lifted = new Nullable.LiftedBinaryOperator (this);
4470 lifted.Right = expr;
4471 return lifted.Resolve (rc);
4473 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4474 Nullable.Unwrap unwrap = null;
4475 if (left.IsNull || right.IsNull) {
4476 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4477 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4479 if ((oper & Operator.RelationalMask) != 0)
4480 return CreateLiftedValueTypeResult (rc, rtype);
4482 if ((oper & Operator.BitwiseMask) != 0)
4483 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4486 return CreateLiftedValueTypeResult (rc, left.Type);
4488 // Equality operators are valid between E? and null
4490 unwrap = new Nullable.Unwrap (right);
4492 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4498 var lifted = new Nullable.LiftedBinaryOperator (this);
4500 lifted.Right = right;
4501 lifted.UnwrapRight = unwrap;
4502 return lifted.Resolve (rc);
4504 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4505 Nullable.Unwrap unwrap = null;
4506 if (right.IsNull || left.IsNull) {
4507 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4508 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4510 if ((oper & Operator.RelationalMask) != 0)
4511 return CreateLiftedValueTypeResult (rc, ltype);
4513 if ((oper & Operator.BitwiseMask) != 0)
4514 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4517 return CreateLiftedValueTypeResult (rc, right.Type);
4519 // Equality operators are valid between E? and null
4521 unwrap = new Nullable.Unwrap (left);
4523 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4529 var lifted = new Nullable.LiftedBinaryOperator (this);
4531 lifted.UnwrapLeft = unwrap;
4532 lifted.Right = expr;
4533 return lifted.Resolve (rc);
4541 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4543 TypeSpec underlying_type;
4544 if (expr.Type.IsNullableType) {
4545 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4547 underlying_type = EnumSpec.GetUnderlyingType (nt);
4549 underlying_type = nt;
4550 } else if (expr.Type.IsEnum) {
4551 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4553 underlying_type = expr.Type;
4556 switch (underlying_type.BuiltinType) {
4557 case BuiltinTypeSpec.Type.SByte:
4558 case BuiltinTypeSpec.Type.Byte:
4559 case BuiltinTypeSpec.Type.Short:
4560 case BuiltinTypeSpec.Type.UShort:
4561 underlying_type = rc.BuiltinTypes.Int;
4565 if (expr.Type.IsNullableType || liftType)
4566 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4568 if (expr.Type == underlying_type)
4571 return EmptyCast.Create (expr, underlying_type);
4574 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4577 // U operator - (E e, E f)
4578 // E operator - (E e, U x) // Internal decomposition operator
4579 // E operator - (U x, E e) // Internal decomposition operator
4581 // E operator + (E e, U x)
4582 // E operator + (U x, E e)
4591 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4597 if (!enum_type.IsNullableType) {
4598 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4600 if (oper == Operator.Subtraction)
4601 expr = ConvertEnumSubtractionResult (rc, expr);
4603 expr = ConvertEnumAdditionalResult (expr, enum_type);
4605 enum_conversion = GetEnumResultCast (expr.Type);
4610 var nullable = rc.Module.PredefinedTypes.Nullable;
4613 // Don't try nullable version when nullable type is undefined
4615 if (!nullable.IsDefined)
4618 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4621 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4623 if (oper == Operator.Subtraction)
4624 expr = ConvertEnumSubtractionResult (rc, expr);
4626 expr = ConvertEnumAdditionalResult (expr, enum_type);
4628 enum_conversion = GetEnumResultCast (expr.Type);
4634 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4636 return EmptyCast.Create (expr, enumType);
4639 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4642 // Enumeration subtraction has different result type based on
4645 TypeSpec result_type;
4646 if (left.Type == right.Type) {
4647 var c = right as EnumConstant;
4648 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4650 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4651 // E which is not what expressions E - 1 or 0 - E return
4653 result_type = left.Type;
4655 result_type = left.Type.IsNullableType ?
4656 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4657 EnumSpec.GetUnderlyingType (left.Type);
4660 if (IsEnumOrNullableEnum (left.Type)) {
4661 result_type = left.Type;
4663 result_type = right.Type;
4666 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4667 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4670 return EmptyCast.Create (expr, result_type);
4673 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4675 if (type.IsNullableType)
4676 type = Nullable.NullableInfo.GetUnderlyingType (type);
4679 type = EnumSpec.GetUnderlyingType (type);
4681 switch (type.BuiltinType) {
4682 case BuiltinTypeSpec.Type.SByte:
4683 return ConvCast.Mode.I4_I1;
4684 case BuiltinTypeSpec.Type.Byte:
4685 return ConvCast.Mode.I4_U1;
4686 case BuiltinTypeSpec.Type.Short:
4687 return ConvCast.Mode.I4_I2;
4688 case BuiltinTypeSpec.Type.UShort:
4689 return ConvCast.Mode.I4_U2;
4696 // Equality operators rules
4698 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4701 type = ec.BuiltinTypes.Bool;
4702 bool no_arg_conv = false;
4704 if (!primitives_only) {
4707 // a, Both operands are reference-type values or the value null
4708 // b, One operand is a value of type T where T is a type-parameter and
4709 // the other operand is the value null. Furthermore T does not have the
4710 // value type constraint
4712 // LAMESPEC: Very confusing details in the specification, basically any
4713 // reference like type-parameter is allowed
4715 var tparam_l = l as TypeParameterSpec;
4716 var tparam_r = r as TypeParameterSpec;
4717 if (tparam_l != null) {
4718 if (right is NullLiteral) {
4719 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4722 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4726 if (!tparam_l.IsReferenceType)
4729 l = tparam_l.GetEffectiveBase ();
4730 left = new BoxedCast (left, l);
4731 } else if (left is NullLiteral && tparam_r == null) {
4732 if (TypeSpec.IsReferenceType (r))
4735 if (r.Kind == MemberKind.InternalCompilerType)
4739 if (tparam_r != null) {
4740 if (left is NullLiteral) {
4741 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4744 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4748 if (!tparam_r.IsReferenceType)
4751 r = tparam_r.GetEffectiveBase ();
4752 right = new BoxedCast (right, r);
4753 } else if (right is NullLiteral) {
4754 if (TypeSpec.IsReferenceType (l))
4757 if (l.Kind == MemberKind.InternalCompilerType)
4762 // LAMESPEC: method groups can be compared when they convert to other side delegate
4765 if (right.eclass == ExprClass.MethodGroup) {
4766 result = Convert.ImplicitConversion (ec, right, l, loc);
4772 } else if (r.IsDelegate && l != r) {
4775 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4776 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4783 no_arg_conv = l == r && !l.IsStruct;
4788 // bool operator != (string a, string b)
4789 // bool operator == (string a, string b)
4791 // bool operator != (Delegate a, Delegate b)
4792 // bool operator == (Delegate a, Delegate b)
4794 // bool operator != (bool a, bool b)
4795 // bool operator == (bool a, bool b)
4797 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4798 // they implement an implicit conversion to any of types above. This does
4799 // not apply when both operands are of same reference type
4801 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4802 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4807 // Now try lifted version of predefined operators
4809 if (no_arg_conv && !l.IsNullableType) {
4811 // Optimizes cases which won't match
4814 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4820 // The == and != operators permit one operand to be a value of a nullable
4821 // type and the other to be the null literal, even if no predefined or user-defined
4822 // operator (in unlifted or lifted form) exists for the operation.
4824 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4825 var lifted = new Nullable.LiftedBinaryOperator (this);
4827 lifted.Right = right;
4828 return lifted.Resolve (ec);
4833 // bool operator != (object a, object b)
4834 // bool operator == (object a, object b)
4836 // An explicit reference conversion exists from the
4837 // type of either operand to the type of the other operand.
4840 // Optimize common path
4842 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4845 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4846 !Convert.ExplicitReferenceConversionExists (r, l))
4849 // Reject allowed explicit conversions like int->object
4850 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4853 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4854 ec.Report.Warning (253, 2, loc,
4855 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4856 l.GetSignatureForError ());
4858 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4859 ec.Report.Warning (252, 2, loc,
4860 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4861 r.GetSignatureForError ());
4867 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4870 // bool operator == (void* x, void* y);
4871 // bool operator != (void* x, void* y);
4872 // bool operator < (void* x, void* y);
4873 // bool operator > (void* x, void* y);
4874 // bool operator <= (void* x, void* y);
4875 // bool operator >= (void* x, void* y);
4877 if ((oper & Operator.ComparisonMask) != 0) {
4880 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4887 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4893 type = ec.BuiltinTypes.Bool;
4897 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4901 // Build-in operators method overloading
4903 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4905 PredefinedOperator best_operator = null;
4906 TypeSpec l = left.Type;
4907 TypeSpec r = right.Type;
4908 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4910 foreach (PredefinedOperator po in operators) {
4911 if ((po.OperatorsMask & oper_mask) == 0)
4914 if (primitives_only) {
4915 if (!po.IsPrimitiveApplicable (l, r))
4918 if (!po.IsApplicable (ec, left, right))
4922 if (best_operator == null) {
4924 if (primitives_only)
4930 best_operator = po.ResolveBetterOperator (ec, best_operator);
4932 if (best_operator == null) {
4933 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4934 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4941 if (best_operator == null)
4944 return best_operator.ConvertResult (ec, this);
4948 // Optimize & constant expressions with 0 value
4950 Expression OptimizeAndOperation (Expression expr)
4952 Constant rc = right as Constant;
4953 Constant lc = left as Constant;
4954 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4956 // The result is a constant with side-effect
4958 Constant side_effect = rc == null ?
4959 new SideEffectConstant (lc, right, loc) :
4960 new SideEffectConstant (rc, left, loc);
4962 return ReducedExpression.Create (side_effect, expr);
4969 // Value types can be compared with the null literal because of the lifting
4970 // language rules. However the result is always true or false.
4972 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4974 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4975 type = rc.BuiltinTypes.Bool;
4979 // FIXME: Handle side effect constants
4980 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4982 if ((Oper & Operator.EqualityMask) != 0) {
4983 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4984 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4986 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4987 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4994 // Performs user-operator overloading
4996 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4998 Expression oper_expr;
5000 var op = ConvertBinaryToUserOperator (oper);
5002 if (l.IsNullableType)
5003 l = Nullable.NullableInfo.GetUnderlyingType (l);
5005 if (r.IsNullableType)
5006 r = Nullable.NullableInfo.GetUnderlyingType (r);
5008 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5009 IList<MemberSpec> right_operators = null;
5012 right_operators = MemberCache.GetUserOperator (r, op, false);
5013 if (right_operators == null && left_operators == null)
5015 } else if (left_operators == null) {
5019 Arguments args = new Arguments (2);
5020 Argument larg = new Argument (left);
5022 Argument rarg = new Argument (right);
5026 // User-defined operator implementations always take precedence
5027 // over predefined operator implementations
5029 if (left_operators != null && right_operators != null) {
5030 left_operators = CombineUserOperators (left_operators, right_operators);
5031 } else if (right_operators != null) {
5032 left_operators = right_operators;
5035 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5036 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5038 var res = new OverloadResolver (left_operators, restr, loc);
5040 var oper_method = res.ResolveOperator (rc, ref args);
5041 if (oper_method == null) {
5043 // Logical && and || cannot be lifted
5045 if ((oper & Operator.LogicalMask) != 0)
5049 // Apply lifted user operators only for liftable types. Implicit conversion
5050 // to nullable types is not allowed
5052 if (!IsLiftedOperatorApplicable ())
5055 // TODO: Cache the result in module container
5056 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5057 if (lifted_methods == null)
5060 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5062 oper_method = res.ResolveOperator (rc, ref args);
5063 if (oper_method == null)
5066 MethodSpec best_original = null;
5067 foreach (MethodSpec ms in left_operators) {
5068 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5074 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5076 // Expression trees use lifted notation in this case
5078 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5079 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5082 var ptypes = best_original.Parameters.Types;
5084 if (left.IsNull || right.IsNull) {
5086 // The lifted operator produces a null value if one or both operands are null
5088 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5089 type = oper_method.ReturnType;
5090 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5094 // The lifted operator produces the value false if one or both operands are null for
5095 // relational operators.
5097 if ((oper & Operator.RelationalMask) != 0) {
5099 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5100 // because return type is actually bool
5102 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5105 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5106 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5110 type = oper_method.ReturnType;
5111 var lifted = new Nullable.LiftedBinaryOperator (this);
5112 lifted.UserOperator = best_original;
5114 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5115 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5118 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5119 lifted.UnwrapRight = new Nullable.Unwrap (right);
5122 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5123 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5125 return lifted.Resolve (rc);
5128 if ((oper & Operator.LogicalMask) != 0) {
5129 // TODO: CreateExpressionTree is allocated every time
5130 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5131 oper == Operator.LogicalAnd, loc).Resolve (rc);
5133 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5136 this.left = larg.Expr;
5137 this.right = rarg.Expr;
5142 bool IsLiftedOperatorApplicable ()
5144 if (left.Type.IsNullableType) {
5145 if ((oper & Operator.EqualityMask) != 0)
5146 return !right.IsNull;
5151 if (right.Type.IsNullableType) {
5152 if ((oper & Operator.EqualityMask) != 0)
5153 return !left.IsNull;
5158 if (TypeSpec.IsValueType (left.Type))
5159 return right.IsNull;
5161 if (TypeSpec.IsValueType (right.Type))
5167 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5169 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5170 if (nullable_type == null)
5174 // Lifted operators permit predefined and user-defined operators that operate
5175 // on non-nullable value types to also be used with nullable forms of those types.
5176 // Lifted operators are constructed from predefined and user-defined operators
5177 // that meet certain requirements
5179 List<MemberSpec> lifted = null;
5180 foreach (MethodSpec oper in operators) {
5182 if ((Oper & Operator.ComparisonMask) != 0) {
5184 // Result type must be of type bool for lifted comparison operators
5186 rt = oper.ReturnType;
5187 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5190 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5196 var ptypes = oper.Parameters.Types;
5197 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5201 // LAMESPEC: I am not sure why but for equality operators to be lifted
5202 // both types have to match
5204 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5208 lifted = new List<MemberSpec> ();
5211 // The lifted form is constructed by adding a single ? modifier to each operand and
5212 // result type except for comparison operators where return type is bool
5215 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5217 var parameters = ParametersCompiled.CreateFullyResolved (
5218 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5219 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5221 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5222 rt, parameters, oper.Modifiers);
5224 lifted.Add (lifted_op);
5231 // Merge two sets of user operators into one, they are mostly distinguish
5232 // except when they share base type and it contains an operator
5234 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5236 var combined = new List<MemberSpec> (left.Count + right.Count);
5237 combined.AddRange (left);
5238 foreach (var r in right) {
5240 foreach (var l in left) {
5241 if (l.DeclaringType == r.DeclaringType) {
5254 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5256 if (c is IntegralConstant || c is CharConstant) {
5258 c.ConvertExplicitly (true, type);
5259 } catch (OverflowException) {
5260 ec.Report.Warning (652, 2, loc,
5261 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5262 type.GetSignatureForError ());
5268 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5269 /// context of a conditional bool expression. This function will return
5270 /// false if it is was possible to use EmitBranchable, or true if it was.
5272 /// The expression's code is generated, and we will generate a branch to `target'
5273 /// if the resulting expression value is equal to isTrue
5275 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5277 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5278 left = left.EmitToField (ec);
5280 if ((oper & Operator.LogicalMask) == 0) {
5281 right = right.EmitToField (ec);
5286 // This is more complicated than it looks, but its just to avoid
5287 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5288 // but on top of that we want for == and != to use a special path
5289 // if we are comparing against null
5291 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5292 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5295 // put the constant on the rhs, for simplicity
5297 if (left is Constant) {
5298 Expression swap = right;
5304 // brtrue/brfalse works with native int only
5306 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5307 left.EmitBranchable (ec, target, my_on_true);
5310 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5311 // right is a boolean, and it's not 'false' => it is 'true'
5312 left.EmitBranchable (ec, target, !my_on_true);
5316 } else if (oper == Operator.LogicalAnd) {
5319 Label tests_end = ec.DefineLabel ();
5321 left.EmitBranchable (ec, tests_end, false);
5322 right.EmitBranchable (ec, target, true);
5323 ec.MarkLabel (tests_end);
5326 // This optimizes code like this
5327 // if (true && i > 4)
5329 if (!(left is Constant))
5330 left.EmitBranchable (ec, target, false);
5332 if (!(right is Constant))
5333 right.EmitBranchable (ec, target, false);
5338 } else if (oper == Operator.LogicalOr){
5340 left.EmitBranchable (ec, target, true);
5341 right.EmitBranchable (ec, target, true);
5344 Label tests_end = ec.DefineLabel ();
5345 left.EmitBranchable (ec, tests_end, true);
5346 right.EmitBranchable (ec, target, false);
5347 ec.MarkLabel (tests_end);
5352 } else if ((oper & Operator.ComparisonMask) == 0) {
5353 base.EmitBranchable (ec, target, on_true);
5360 TypeSpec t = left.Type;
5361 bool is_float = IsFloat (t);
5362 bool is_unsigned = is_float || IsUnsigned (t);
5365 case Operator.Equality:
5367 ec.Emit (OpCodes.Beq, target);
5369 ec.Emit (OpCodes.Bne_Un, target);
5372 case Operator.Inequality:
5374 ec.Emit (OpCodes.Bne_Un, target);
5376 ec.Emit (OpCodes.Beq, target);
5379 case Operator.LessThan:
5381 if (is_unsigned && !is_float)
5382 ec.Emit (OpCodes.Blt_Un, target);
5384 ec.Emit (OpCodes.Blt, target);
5387 ec.Emit (OpCodes.Bge_Un, target);
5389 ec.Emit (OpCodes.Bge, target);
5392 case Operator.GreaterThan:
5394 if (is_unsigned && !is_float)
5395 ec.Emit (OpCodes.Bgt_Un, target);
5397 ec.Emit (OpCodes.Bgt, target);
5400 ec.Emit (OpCodes.Ble_Un, target);
5402 ec.Emit (OpCodes.Ble, target);
5405 case Operator.LessThanOrEqual:
5407 if (is_unsigned && !is_float)
5408 ec.Emit (OpCodes.Ble_Un, target);
5410 ec.Emit (OpCodes.Ble, target);
5413 ec.Emit (OpCodes.Bgt_Un, target);
5415 ec.Emit (OpCodes.Bgt, target);
5419 case Operator.GreaterThanOrEqual:
5421 if (is_unsigned && !is_float)
5422 ec.Emit (OpCodes.Bge_Un, target);
5424 ec.Emit (OpCodes.Bge, target);
5427 ec.Emit (OpCodes.Blt_Un, target);
5429 ec.Emit (OpCodes.Blt, target);
5432 throw new InternalErrorException (oper.ToString ());
5436 public override void Emit (EmitContext ec)
5438 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5439 left = left.EmitToField (ec);
5441 if ((oper & Operator.LogicalMask) == 0) {
5442 right = right.EmitToField (ec);
5447 // Handle short-circuit operators differently
5450 if ((oper & Operator.LogicalMask) != 0) {
5451 Label load_result = ec.DefineLabel ();
5452 Label end = ec.DefineLabel ();
5454 bool is_or = oper == Operator.LogicalOr;
5455 left.EmitBranchable (ec, load_result, is_or);
5457 ec.Emit (OpCodes.Br_S, end);
5459 ec.MarkLabel (load_result);
5460 ec.EmitInt (is_or ? 1 : 0);
5466 // Optimize zero-based operations which cannot be optimized at expression level
5468 if (oper == Operator.Subtraction) {
5469 var lc = left as IntegralConstant;
5470 if (lc != null && lc.IsDefaultValue) {
5472 ec.Emit (OpCodes.Neg);
5477 EmitOperator (ec, left, right);
5480 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5485 EmitOperatorOpcode (ec, oper, left.Type, right);
5488 // Emit result enumerable conversion this way because it's quite complicated get it
5489 // to resolved tree because expression tree cannot see it.
5491 if (enum_conversion != 0)
5492 ConvCast.Emit (ec, enum_conversion);
5495 public override void EmitSideEffect (EmitContext ec)
5497 if ((oper & Operator.LogicalMask) != 0 ||
5498 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5499 base.EmitSideEffect (ec);
5501 left.EmitSideEffect (ec);
5502 right.EmitSideEffect (ec);
5506 public override Expression EmitToField (EmitContext ec)
5508 if ((oper & Operator.LogicalMask) == 0) {
5509 var await_expr = left as Await;
5510 if (await_expr != null && right.IsSideEffectFree) {
5511 await_expr.Statement.EmitPrologue (ec);
5512 left = await_expr.Statement.GetResultExpression (ec);
5516 await_expr = right as Await;
5517 if (await_expr != null && left.IsSideEffectFree) {
5518 await_expr.Statement.EmitPrologue (ec);
5519 right = await_expr.Statement.GetResultExpression (ec);
5524 return base.EmitToField (ec);
5527 protected override void CloneTo (CloneContext clonectx, Expression t)
5529 Binary target = (Binary) t;
5531 target.left = left.Clone (clonectx);
5532 target.right = right.Clone (clonectx);
5535 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5537 Arguments binder_args = new Arguments (4);
5539 MemberAccess sle = new MemberAccess (new MemberAccess (
5540 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5542 CSharpBinderFlags flags = 0;
5543 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5544 flags = CSharpBinderFlags.CheckedContext;
5546 if ((oper & Operator.LogicalMask) != 0)
5547 flags |= CSharpBinderFlags.BinaryOperationLogical;
5549 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5550 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5551 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5552 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5554 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5557 public override Expression CreateExpressionTree (ResolveContext ec)
5559 return CreateExpressionTree (ec, null);
5562 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5565 bool lift_arg = false;
5568 case Operator.Addition:
5569 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5570 method_name = "AddChecked";
5572 method_name = "Add";
5574 case Operator.BitwiseAnd:
5575 method_name = "And";
5577 case Operator.BitwiseOr:
5580 case Operator.Division:
5581 method_name = "Divide";
5583 case Operator.Equality:
5584 method_name = "Equal";
5587 case Operator.ExclusiveOr:
5588 method_name = "ExclusiveOr";
5590 case Operator.GreaterThan:
5591 method_name = "GreaterThan";
5594 case Operator.GreaterThanOrEqual:
5595 method_name = "GreaterThanOrEqual";
5598 case Operator.Inequality:
5599 method_name = "NotEqual";
5602 case Operator.LeftShift:
5603 method_name = "LeftShift";
5605 case Operator.LessThan:
5606 method_name = "LessThan";
5609 case Operator.LessThanOrEqual:
5610 method_name = "LessThanOrEqual";
5613 case Operator.LogicalAnd:
5614 method_name = "AndAlso";
5616 case Operator.LogicalOr:
5617 method_name = "OrElse";
5619 case Operator.Modulus:
5620 method_name = "Modulo";
5622 case Operator.Multiply:
5623 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5624 method_name = "MultiplyChecked";
5626 method_name = "Multiply";
5628 case Operator.RightShift:
5629 method_name = "RightShift";
5631 case Operator.Subtraction:
5632 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5633 method_name = "SubtractChecked";
5635 method_name = "Subtract";
5639 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5642 Arguments args = new Arguments (2);
5643 args.Add (new Argument (left.CreateExpressionTree (ec)));
5644 args.Add (new Argument (right.CreateExpressionTree (ec)));
5645 if (method != null) {
5647 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5649 args.Add (new Argument (method));
5652 return CreateExpressionFactoryCall (ec, method_name, args);
5655 public override object Accept (StructuralVisitor visitor)
5657 return visitor.Visit (this);
5663 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5664 // b, c, d... may be strings or objects.
5666 public class StringConcat : Expression
5668 Arguments arguments;
5670 StringConcat (Location loc)
5673 arguments = new Arguments (2);
5676 public override bool ContainsEmitWithAwait ()
5678 return arguments.ContainsEmitWithAwait ();
5681 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5683 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5684 throw new ArgumentException ();
5686 var s = new StringConcat (loc);
5687 s.type = rc.BuiltinTypes.String;
5688 s.eclass = ExprClass.Value;
5690 s.Append (rc, left);
5691 s.Append (rc, right);
5695 public override Expression CreateExpressionTree (ResolveContext ec)
5697 Argument arg = arguments [0];
5698 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5702 // Creates nested calls tree from an array of arguments used for IL emit
5704 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5706 Arguments concat_args = new Arguments (2);
5707 Arguments add_args = new Arguments (3);
5709 concat_args.Add (left);
5710 add_args.Add (new Argument (left_etree));
5712 concat_args.Add (arguments [pos]);
5713 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5715 var methods = GetConcatMethodCandidates ();
5716 if (methods == null)
5719 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5720 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5724 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5726 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5727 if (++pos == arguments.Count)
5730 left = new Argument (new EmptyExpression (method.ReturnType));
5731 return CreateExpressionAddCall (ec, left, expr, pos);
5734 protected override Expression DoResolve (ResolveContext ec)
5739 void Append (ResolveContext rc, Expression operand)
5744 StringConstant sc = operand as StringConstant;
5746 if (arguments.Count != 0) {
5747 Argument last_argument = arguments [arguments.Count - 1];
5748 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5749 if (last_expr_constant != null) {
5750 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5756 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5758 StringConcat concat_oper = operand as StringConcat;
5759 if (concat_oper != null) {
5760 arguments.AddRange (concat_oper.arguments);
5765 arguments.Add (new Argument (operand));
5768 IList<MemberSpec> GetConcatMethodCandidates ()
5770 return MemberCache.FindMembers (type, "Concat", true);
5773 public override void Emit (EmitContext ec)
5775 // Optimize by removing any extra null arguments, they are no-op
5776 for (int i = 0; i < arguments.Count; ++i) {
5777 if (arguments[i].Expr is NullConstant)
5778 arguments.RemoveAt (i--);
5781 var members = GetConcatMethodCandidates ();
5782 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5783 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5784 if (method != null) {
5785 var call = new CallEmitter ();
5786 call.EmitPredefined (ec, method, arguments, false);
5790 public override void FlowAnalysis (FlowAnalysisContext fc)
5792 arguments.FlowAnalysis (fc);
5795 public override SLE.Expression MakeExpression (BuilderContext ctx)
5797 if (arguments.Count != 2)
5798 throw new NotImplementedException ("arguments.Count != 2");
5800 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5801 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5806 // User-defined conditional logical operator
5808 public class ConditionalLogicalOperator : UserOperatorCall
5810 readonly bool is_and;
5811 Expression oper_expr;
5813 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5814 : base (oper, arguments, expr_tree, loc)
5816 this.is_and = is_and;
5817 eclass = ExprClass.Unresolved;
5820 protected override Expression DoResolve (ResolveContext ec)
5822 AParametersCollection pd = oper.Parameters;
5823 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5824 ec.Report.Error (217, loc,
5825 "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",
5826 oper.GetSignatureForError ());
5830 Expression left_dup = new EmptyExpression (type);
5831 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5832 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5833 if (op_true == null || op_false == null) {
5834 ec.Report.Error (218, loc,
5835 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5836 type.GetSignatureForError (), oper.GetSignatureForError ());
5840 oper_expr = is_and ? op_false : op_true;
5841 eclass = ExprClass.Value;
5845 public override void Emit (EmitContext ec)
5847 Label end_target = ec.DefineLabel ();
5850 // Emit and duplicate left argument
5852 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5853 if (right_contains_await) {
5854 arguments[0] = arguments[0].EmitToField (ec, false);
5855 arguments[0].Expr.Emit (ec);
5857 arguments[0].Expr.Emit (ec);
5858 ec.Emit (OpCodes.Dup);
5859 arguments.RemoveAt (0);
5862 oper_expr.EmitBranchable (ec, end_target, true);
5866 if (right_contains_await) {
5868 // Special handling when right expression contains await and left argument
5869 // could not be left on stack before logical branch
5871 Label skip_left_load = ec.DefineLabel ();
5872 ec.Emit (OpCodes.Br_S, skip_left_load);
5873 ec.MarkLabel (end_target);
5874 arguments[0].Expr.Emit (ec);
5875 ec.MarkLabel (skip_left_load);
5877 ec.MarkLabel (end_target);
5882 public class PointerArithmetic : Expression {
5883 Expression left, right;
5884 readonly Binary.Operator op;
5887 // We assume that `l' is always a pointer
5889 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5898 public override bool ContainsEmitWithAwait ()
5900 throw new NotImplementedException ();
5903 public override Expression CreateExpressionTree (ResolveContext ec)
5905 Error_PointerInsideExpressionTree (ec);
5909 protected override Expression DoResolve (ResolveContext ec)
5911 eclass = ExprClass.Variable;
5913 var pc = left.Type as PointerContainer;
5914 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5915 Error_VoidPointerOperation (ec);
5922 public override void Emit (EmitContext ec)
5924 TypeSpec op_type = left.Type;
5926 // It must be either array or fixed buffer
5928 if (TypeManager.HasElementType (op_type)) {
5929 element = TypeManager.GetElementType (op_type);
5931 FieldExpr fe = left as FieldExpr;
5933 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5938 int size = BuiltinTypeSpec.GetSize(element);
5939 TypeSpec rtype = right.Type;
5941 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5943 // handle (pointer - pointer)
5947 ec.Emit (OpCodes.Sub);
5951 ec.Emit (OpCodes.Sizeof, element);
5954 ec.Emit (OpCodes.Div);
5956 ec.Emit (OpCodes.Conv_I8);
5959 // handle + and - on (pointer op int)
5961 Constant left_const = left as Constant;
5962 if (left_const != null) {
5964 // Optimize ((T*)null) pointer operations
5966 if (left_const.IsDefaultValue) {
5967 left = EmptyExpression.Null;
5975 var right_const = right as Constant;
5976 if (right_const != null) {
5978 // Optimize 0-based arithmetic
5980 if (right_const.IsDefaultValue)
5984 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5986 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5988 // TODO: Should be the checks resolve context sensitive?
5989 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5990 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5996 switch (rtype.BuiltinType) {
5997 case BuiltinTypeSpec.Type.SByte:
5998 case BuiltinTypeSpec.Type.Byte:
5999 case BuiltinTypeSpec.Type.Short:
6000 case BuiltinTypeSpec.Type.UShort:
6001 ec.Emit (OpCodes.Conv_I);
6003 case BuiltinTypeSpec.Type.UInt:
6004 ec.Emit (OpCodes.Conv_U);
6008 if (right_const == null && size != 1){
6010 ec.Emit (OpCodes.Sizeof, element);
6013 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6014 ec.Emit (OpCodes.Conv_I8);
6016 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6019 if (left_const == null) {
6020 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6021 ec.Emit (OpCodes.Conv_I);
6022 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6023 ec.Emit (OpCodes.Conv_U);
6025 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6032 // A boolean-expression is an expression that yields a result
6035 public class BooleanExpression : ShimExpression
6037 public BooleanExpression (Expression expr)
6040 this.loc = expr.Location;
6043 public override Expression CreateExpressionTree (ResolveContext ec)
6045 // TODO: We should emit IsTrue (v4) instead of direct user operator
6046 // call but that would break csc compatibility
6047 return base.CreateExpressionTree (ec);
6050 protected override Expression DoResolve (ResolveContext ec)
6052 // A boolean-expression is required to be of a type
6053 // that can be implicitly converted to bool or of
6054 // a type that implements operator true
6056 expr = expr.Resolve (ec);
6060 Assign ass = expr as Assign;
6061 if (ass != null && ass.Source is Constant) {
6062 ec.Report.Warning (665, 3, loc,
6063 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6066 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6069 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6070 Arguments args = new Arguments (1);
6071 args.Add (new Argument (expr));
6072 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6075 type = ec.BuiltinTypes.Bool;
6076 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6077 if (converted != null)
6081 // If no implicit conversion to bool exists, try using `operator true'
6083 converted = GetOperatorTrue (ec, expr, loc);
6084 if (converted == null) {
6085 expr.Error_ValueCannotBeConverted (ec, type, false);
6092 public override object Accept (StructuralVisitor visitor)
6094 return visitor.Visit (this);
6098 public class BooleanExpressionFalse : Unary
6100 public BooleanExpressionFalse (Expression expr)
6101 : base (Operator.LogicalNot, expr, expr.Location)
6105 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6107 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6112 /// Implements the ternary conditional operator (?:)
6114 public class Conditional : Expression {
6115 Expression expr, true_expr, false_expr;
6117 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6120 this.true_expr = true_expr;
6121 this.false_expr = false_expr;
6127 public Expression Expr {
6133 public Expression TrueExpr {
6139 public Expression FalseExpr {
6147 public override bool ContainsEmitWithAwait ()
6149 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6152 public override Expression CreateExpressionTree (ResolveContext ec)
6154 Arguments args = new Arguments (3);
6155 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6156 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6157 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6158 return CreateExpressionFactoryCall (ec, "Condition", args);
6161 protected override Expression DoResolve (ResolveContext ec)
6163 expr = expr.Resolve (ec);
6164 true_expr = true_expr.Resolve (ec);
6165 false_expr = false_expr.Resolve (ec);
6167 if (true_expr == null || false_expr == null || expr == null)
6170 eclass = ExprClass.Value;
6171 TypeSpec true_type = true_expr.Type;
6172 TypeSpec false_type = false_expr.Type;
6176 // First, if an implicit conversion exists from true_expr
6177 // to false_expr, then the result type is of type false_expr.Type
6179 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6180 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6181 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6183 // Check if both can convert implicitly to each other's type
6187 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6188 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6190 // LAMESPEC: There seems to be hardcoded promotition to int type when
6191 // both sides are numeric constants and one side is int constant and
6192 // other side is numeric constant convertible to int.
6194 // var res = condition ? (short)1 : 1;
6196 // Type of res is int even if according to the spec the conversion is
6197 // ambiguous because 1 literal can be converted to short.
6199 if (conv_false_expr != null) {
6200 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6202 conv_false_expr = null;
6203 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6204 conv_false_expr = null;
6208 if (conv_false_expr != null) {
6209 ec.Report.Error (172, true_expr.Location,
6210 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6211 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6216 if (true_expr.Type != type)
6217 true_expr = EmptyCast.Create (true_expr, type);
6218 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6221 if (false_type != InternalType.ErrorType) {
6222 ec.Report.Error (173, true_expr.Location,
6223 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6224 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6230 Constant c = expr as Constant;
6232 bool is_false = c.IsDefaultValue;
6235 // Don't issue the warning for constant expressions
6237 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6238 // CSC: Missing warning
6239 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6242 return ReducedExpression.Create (
6243 is_false ? false_expr : true_expr, this,
6244 false_expr is Constant && true_expr is Constant).Resolve (ec);
6250 public override void Emit (EmitContext ec)
6252 Label false_target = ec.DefineLabel ();
6253 Label end_target = ec.DefineLabel ();
6255 expr.EmitBranchable (ec, false_target, false);
6256 true_expr.Emit (ec);
6259 // Verifier doesn't support interface merging. When there are two types on
6260 // the stack without common type hint and the common type is an interface.
6261 // Use temporary local to give verifier hint on what type to unify the stack
6263 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6264 var temp = ec.GetTemporaryLocal (type);
6265 ec.Emit (OpCodes.Stloc, temp);
6266 ec.Emit (OpCodes.Ldloc, temp);
6267 ec.FreeTemporaryLocal (temp, type);
6270 ec.Emit (OpCodes.Br, end_target);
6271 ec.MarkLabel (false_target);
6272 false_expr.Emit (ec);
6273 ec.MarkLabel (end_target);
6276 public override void FlowAnalysis (FlowAnalysisContext fc)
6278 expr.FlowAnalysisConditional (fc);
6279 var expr_true = fc.DefiniteAssignmentOnTrue;
6280 var expr_false = fc.DefiniteAssignmentOnFalse;
6282 fc.BranchDefiniteAssignment (expr_true);
6283 true_expr.FlowAnalysis (fc);
6284 var true_fc = fc.DefiniteAssignment;
6286 fc.BranchDefiniteAssignment (expr_false);
6287 false_expr.FlowAnalysis (fc);
6289 fc.DefiniteAssignment &= true_fc;
6292 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6294 expr.FlowAnalysisConditional (fc);
6295 var expr_true = fc.DefiniteAssignmentOnTrue;
6296 var expr_false = fc.DefiniteAssignmentOnFalse;
6298 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6299 true_expr.FlowAnalysisConditional (fc);
6300 var true_fc = fc.DefiniteAssignment;
6301 var true_da_true = fc.DefiniteAssignmentOnTrue;
6302 var true_da_false = fc.DefiniteAssignmentOnFalse;
6304 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6305 false_expr.FlowAnalysisConditional (fc);
6307 fc.DefiniteAssignment &= true_fc;
6308 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6309 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6312 protected override void CloneTo (CloneContext clonectx, Expression t)
6314 Conditional target = (Conditional) t;
6316 target.expr = expr.Clone (clonectx);
6317 target.true_expr = true_expr.Clone (clonectx);
6318 target.false_expr = false_expr.Clone (clonectx);
6322 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6324 LocalTemporary temp;
6327 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6328 public abstract void SetHasAddressTaken ();
6330 public abstract bool IsLockedByStatement { get; set; }
6332 public abstract bool IsFixed { get; }
6333 public abstract bool IsRef { get; }
6334 public abstract string Name { get; }
6337 // Variable IL data, it has to be protected to encapsulate hoisted variables
6339 protected abstract ILocalVariable Variable { get; }
6342 // Variable flow-analysis data
6344 public abstract VariableInfo VariableInfo { get; }
6347 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6349 HoistedVariable hv = GetHoistedVariable (ec);
6351 hv.AddressOf (ec, mode);
6355 Variable.EmitAddressOf (ec);
6358 public override bool ContainsEmitWithAwait ()
6363 public override Expression CreateExpressionTree (ResolveContext ec)
6365 HoistedVariable hv = GetHoistedVariable (ec);
6367 return hv.CreateExpressionTree ();
6369 Arguments arg = new Arguments (1);
6370 arg.Add (new Argument (this));
6371 return CreateExpressionFactoryCall (ec, "Constant", arg);
6374 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6376 if (IsLockedByStatement) {
6377 rc.Report.Warning (728, 2, loc,
6378 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6385 public override void Emit (EmitContext ec)
6390 public override void EmitSideEffect (EmitContext ec)
6396 // This method is used by parameters that are references, that are
6397 // being passed as references: we only want to pass the pointer (that
6398 // is already stored in the parameter, not the address of the pointer,
6399 // and not the value of the variable).
6401 public void EmitLoad (EmitContext ec)
6406 public void Emit (EmitContext ec, bool leave_copy)
6408 HoistedVariable hv = GetHoistedVariable (ec);
6410 hv.Emit (ec, leave_copy);
6418 // If we are a reference, we loaded on the stack a pointer
6419 // Now lets load the real value
6421 ec.EmitLoadFromPtr (type);
6425 ec.Emit (OpCodes.Dup);
6428 temp = new LocalTemporary (Type);
6434 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6435 bool prepare_for_load)
6437 HoistedVariable hv = GetHoistedVariable (ec);
6439 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6443 New n_source = source as New;
6444 if (n_source != null) {
6445 if (!n_source.Emit (ec, this)) {
6449 ec.EmitLoadFromPtr (type);
6461 ec.Emit (OpCodes.Dup);
6463 temp = new LocalTemporary (Type);
6469 ec.EmitStoreFromPtr (type);
6471 Variable.EmitAssign (ec);
6479 public override Expression EmitToField (EmitContext ec)
6481 HoistedVariable hv = GetHoistedVariable (ec);
6483 return hv.EmitToField (ec);
6486 return base.EmitToField (ec);
6489 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6491 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6494 public HoistedVariable GetHoistedVariable (EmitContext ec)
6496 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6499 public override string GetSignatureForError ()
6504 public bool IsHoisted {
6505 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6510 // Resolved reference to a local variable
6512 public class LocalVariableReference : VariableReference
6514 public LocalVariable local_info;
6516 public LocalVariableReference (LocalVariable li, Location l)
6518 this.local_info = li;
6522 public override VariableInfo VariableInfo {
6523 get { return local_info.VariableInfo; }
6526 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6528 return local_info.HoistedVariant;
6534 // A local variable is always fixed
6536 public override bool IsFixed {
6542 public override bool IsLockedByStatement {
6544 return local_info.IsLocked;
6547 local_info.IsLocked = value;
6551 public override bool IsRef {
6552 get { return false; }
6555 public override string Name {
6556 get { return local_info.Name; }
6561 public override void FlowAnalysis (FlowAnalysisContext fc)
6563 VariableInfo variable_info = VariableInfo;
6564 if (variable_info == null)
6567 if (fc.IsDefinitelyAssigned (variable_info))
6570 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6571 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6574 public override void SetHasAddressTaken ()
6576 local_info.SetHasAddressTaken ();
6579 void DoResolveBase (ResolveContext ec)
6581 eclass = ExprClass.Variable;
6582 type = local_info.Type;
6585 // If we are referencing a variable from the external block
6586 // flag it for capturing
6588 if (ec.MustCaptureVariable (local_info)) {
6589 if (local_info.AddressTaken) {
6590 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6591 } else if (local_info.IsFixed) {
6592 ec.Report.Error (1764, loc,
6593 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6594 GetSignatureForError ());
6597 if (ec.IsVariableCapturingRequired) {
6598 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6599 storey.CaptureLocalVariable (ec, local_info);
6604 protected override Expression DoResolve (ResolveContext ec)
6606 local_info.SetIsUsed ();
6610 if (local_info.Type == InternalType.VarOutType) {
6611 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6612 GetSignatureForError ());
6614 type = InternalType.ErrorType;
6620 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6623 // Don't be too pedantic when variable is used as out param or for some broken code
6624 // which uses property/indexer access to run some initialization
6626 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6627 local_info.SetIsUsed ();
6629 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6630 if (rhs == EmptyExpression.LValueMemberAccess) {
6631 // CS1654 already reported
6635 if (rhs == EmptyExpression.OutAccess) {
6636 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6637 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6638 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6639 } else if (rhs == EmptyExpression.UnaryAddress) {
6640 code = 459; msg = "Cannot take the address of {1} `{0}'";
6642 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6644 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6648 if (eclass == ExprClass.Unresolved)
6651 return base.DoResolveLValue (ec, rhs);
6654 public override int GetHashCode ()
6656 return local_info.GetHashCode ();
6659 public override bool Equals (object obj)
6661 LocalVariableReference lvr = obj as LocalVariableReference;
6665 return local_info == lvr.local_info;
6668 protected override ILocalVariable Variable {
6669 get { return local_info; }
6672 public override string ToString ()
6674 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6677 protected override void CloneTo (CloneContext clonectx, Expression t)
6684 /// This represents a reference to a parameter in the intermediate
6687 public class ParameterReference : VariableReference
6689 protected ParametersBlock.ParameterInfo pi;
6691 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6699 public override bool IsLockedByStatement {
6704 pi.IsLocked = value;
6708 public override bool IsRef {
6709 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6712 bool HasOutModifier {
6713 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6716 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6718 return pi.Parameter.HoistedVariant;
6722 // A ref or out parameter is classified as a moveable variable, even
6723 // if the argument given for the parameter is a fixed variable
6725 public override bool IsFixed {
6726 get { return !IsRef; }
6729 public override string Name {
6730 get { return Parameter.Name; }
6733 public Parameter Parameter {
6734 get { return pi.Parameter; }
6737 public override VariableInfo VariableInfo {
6738 get { return pi.VariableInfo; }
6741 protected override ILocalVariable Variable {
6742 get { return Parameter; }
6747 public override void AddressOf (EmitContext ec, AddressOp mode)
6750 // ParameterReferences might already be a reference
6757 base.AddressOf (ec, mode);
6760 public override void SetHasAddressTaken ()
6762 Parameter.HasAddressTaken = true;
6765 bool DoResolveBase (ResolveContext ec)
6767 if (eclass != ExprClass.Unresolved)
6770 type = pi.ParameterType;
6771 eclass = ExprClass.Variable;
6774 // If we are referencing a parameter from the external block
6775 // flag it for capturing
6777 if (ec.MustCaptureVariable (pi)) {
6778 if (Parameter.HasAddressTaken)
6779 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6782 ec.Report.Error (1628, loc,
6783 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6784 Name, ec.CurrentAnonymousMethod.ContainerType);
6787 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6788 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6789 storey.CaptureParameter (ec, pi, this);
6796 public override int GetHashCode ()
6798 return Name.GetHashCode ();
6801 public override bool Equals (object obj)
6803 ParameterReference pr = obj as ParameterReference;
6807 return Name == pr.Name;
6810 protected override void CloneTo (CloneContext clonectx, Expression target)
6816 public override Expression CreateExpressionTree (ResolveContext ec)
6818 HoistedVariable hv = GetHoistedVariable (ec);
6820 return hv.CreateExpressionTree ();
6822 return Parameter.ExpressionTreeVariableReference ();
6825 protected override Expression DoResolve (ResolveContext ec)
6827 if (!DoResolveBase (ec))
6833 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6835 if (!DoResolveBase (ec))
6838 if (Parameter.HoistedVariant != null)
6839 Parameter.HoistedVariant.IsAssigned = true;
6841 return base.DoResolveLValue (ec, right_side);
6844 public override void FlowAnalysis (FlowAnalysisContext fc)
6846 VariableInfo variable_info = VariableInfo;
6847 if (variable_info == null)
6850 if (fc.IsDefinitelyAssigned (variable_info))
6853 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6854 fc.SetVariableAssigned (variable_info);
6859 /// Invocation of methods or delegates.
6861 public class Invocation : ExpressionStatement
6863 public class Predefined : Invocation
6865 public Predefined (MethodGroupExpr expr, Arguments arguments)
6866 : base (expr, arguments)
6871 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6873 if (!rc.IsObsolete) {
6874 var member = mg.BestCandidate;
6875 ObsoleteAttribute oa = member.GetAttributeObsolete ();
6877 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
6884 protected Arguments arguments;
6885 protected Expression expr;
6886 protected MethodGroupExpr mg;
6887 bool conditional_access_receiver;
6889 public Invocation (Expression expr, Arguments arguments)
6892 this.arguments = arguments;
6894 loc = expr.Location;
6899 public Arguments Arguments {
6905 public Expression Exp {
6911 public MethodGroupExpr MethodGroup {
6917 public override Location StartLocation {
6919 return expr.StartLocation;
6925 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6927 if (MethodGroup == null)
6930 var candidate = MethodGroup.BestCandidate;
6931 if (candidate == null || !(candidate.IsStatic || Exp is This))
6934 var args_count = arguments == null ? 0 : arguments.Count;
6935 if (args_count != body.Parameters.Count)
6938 var lambda_parameters = body.Block.Parameters.FixedParameters;
6939 for (int i = 0; i < args_count; ++i) {
6940 var pr = arguments[i].Expr as ParameterReference;
6944 if (lambda_parameters[i] != pr.Parameter)
6947 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6951 var emg = MethodGroup as ExtensionMethodGroupExpr;
6953 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6954 if (candidate.IsGeneric) {
6955 var targs = new TypeExpression [candidate.Arity];
6956 for (int i = 0; i < targs.Length; ++i) {
6957 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6960 mg.SetTypeArguments (null, new TypeArguments (targs));
6969 protected override void CloneTo (CloneContext clonectx, Expression t)
6971 Invocation target = (Invocation) t;
6973 if (arguments != null)
6974 target.arguments = arguments.Clone (clonectx);
6976 target.expr = expr.Clone (clonectx);
6979 public override bool ContainsEmitWithAwait ()
6981 if (arguments != null && arguments.ContainsEmitWithAwait ())
6984 return mg.ContainsEmitWithAwait ();
6987 public override Expression CreateExpressionTree (ResolveContext ec)
6989 Expression instance = mg.IsInstance ?
6990 mg.InstanceExpression.CreateExpressionTree (ec) :
6991 new NullLiteral (loc);
6993 var args = Arguments.CreateForExpressionTree (ec, arguments,
6995 mg.CreateExpressionTree (ec));
6997 return CreateExpressionFactoryCall (ec, "Call", args);
7000 protected override Expression DoResolve (ResolveContext rc)
7002 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
7003 if (expr.HasConditionalAccess ()) {
7004 conditional_access_receiver = true;
7005 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
7006 return DoResolveInvocation (rc);
7011 return DoResolveInvocation (rc);
7014 Expression DoResolveInvocation (ResolveContext ec)
7016 Expression member_expr;
7017 var atn = expr as ATypeNameExpression;
7019 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7020 if (member_expr != null) {
7021 var name_of = member_expr as NameOf;
7022 if (name_of != null) {
7023 return name_of.ResolveOverload (ec, arguments);
7026 member_expr = member_expr.Resolve (ec);
7029 member_expr = expr.Resolve (ec);
7032 if (member_expr == null)
7036 // Next, evaluate all the expressions in the argument list
7038 bool dynamic_arg = false;
7039 if (arguments != null)
7040 arguments.Resolve (ec, out dynamic_arg);
7042 TypeSpec expr_type = member_expr.Type;
7043 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7044 return DoResolveDynamic (ec, member_expr);
7046 mg = member_expr as MethodGroupExpr;
7047 Expression invoke = null;
7050 if (expr_type != null && expr_type.IsDelegate) {
7051 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7052 invoke = invoke.Resolve (ec);
7053 if (invoke == null || !dynamic_arg)
7056 if (member_expr is RuntimeValueExpression) {
7057 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7058 member_expr.Type.GetSignatureForError ());
7062 MemberExpr me = member_expr as MemberExpr;
7064 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7068 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7069 member_expr.GetSignatureForError ());
7074 if (invoke == null) {
7075 mg = DoResolveOverload (ec);
7081 return DoResolveDynamic (ec, member_expr);
7083 var method = mg.BestCandidate;
7084 type = mg.BestCandidateReturnType;
7085 if (conditional_access_receiver)
7086 type = LiftMemberType (ec, type);
7088 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7090 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7092 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7096 IsSpecialMethodInvocation (ec, method, loc);
7098 eclass = ExprClass.Value;
7102 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7105 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7107 args = dmb.Arguments;
7108 if (arguments != null)
7109 args.AddRange (arguments);
7110 } else if (mg == null) {
7111 if (arguments == null)
7112 args = new Arguments (1);
7116 args.Insert (0, new Argument (memberExpr));
7120 ec.Report.Error (1971, loc,
7121 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7126 if (arguments == null)
7127 args = new Arguments (1);
7131 MemberAccess ma = expr as MemberAccess;
7133 var inst = mg.InstanceExpression;
7134 var left_type = inst as TypeExpr;
7135 if (left_type != null) {
7136 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7137 } else if (inst != null) {
7139 // Any value type has to be pass as by-ref to get back the same
7140 // instance on which the member was called
7142 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7143 Argument.AType.Ref : Argument.AType.None;
7144 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7146 } else { // is SimpleName
7148 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7150 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7155 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7158 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7160 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7163 public override void FlowAnalysis (FlowAnalysisContext fc)
7165 if (mg.IsConditionallyExcluded)
7168 mg.FlowAnalysis (fc);
7170 if (arguments != null)
7171 arguments.FlowAnalysis (fc);
7173 if (conditional_access_receiver)
7174 fc.ConditionalAccessEnd ();
7177 public override string GetSignatureForError ()
7179 return mg.GetSignatureForError ();
7182 public override bool HasConditionalAccess ()
7184 return expr.HasConditionalAccess ();
7188 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7189 // or the type dynamic, then the member is invocable
7191 public static bool IsMemberInvocable (MemberSpec member)
7193 switch (member.Kind) {
7194 case MemberKind.Event:
7196 case MemberKind.Field:
7197 case MemberKind.Property:
7198 var m = member as IInterfaceMemberSpec;
7199 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7205 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7207 if (!method.IsReservedMethod)
7210 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7213 ec.Report.SymbolRelatedToPreviousError (method);
7214 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7215 method.GetSignatureForError ());
7220 public override void Emit (EmitContext ec)
7222 if (mg.IsConditionallyExcluded)
7225 if (conditional_access_receiver)
7226 mg.EmitCall (ec, arguments, type, false);
7228 mg.EmitCall (ec, arguments, false);
7231 public override void EmitStatement (EmitContext ec)
7233 if (mg.IsConditionallyExcluded)
7236 if (conditional_access_receiver)
7237 mg.EmitCall (ec, arguments, type, true);
7239 mg.EmitCall (ec, arguments, true);
7242 public override SLE.Expression MakeExpression (BuilderContext ctx)
7244 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7247 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7250 throw new NotSupportedException ();
7252 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7253 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7257 public override object Accept (StructuralVisitor visitor)
7259 return visitor.Visit (this);
7264 // Implements simple new expression
7266 public class New : ExpressionStatement, IMemoryLocation
7268 protected Arguments arguments;
7271 // During bootstrap, it contains the RequestedType,
7272 // but if `type' is not null, it *might* contain a NewDelegate
7273 // (because of field multi-initialization)
7275 protected Expression RequestedType;
7277 protected MethodSpec method;
7279 public New (Expression requested_type, Arguments arguments, Location l)
7281 RequestedType = requested_type;
7282 this.arguments = arguments;
7287 public Arguments Arguments {
7294 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7296 public bool IsGeneratedStructConstructor {
7298 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7302 public Expression TypeExpression {
7304 return RequestedType;
7311 /// Converts complex core type syntax like 'new int ()' to simple constant
7313 public static Constant Constantify (TypeSpec t, Location loc)
7315 switch (t.BuiltinType) {
7316 case BuiltinTypeSpec.Type.Int:
7317 return new IntConstant (t, 0, loc);
7318 case BuiltinTypeSpec.Type.UInt:
7319 return new UIntConstant (t, 0, loc);
7320 case BuiltinTypeSpec.Type.Long:
7321 return new LongConstant (t, 0, loc);
7322 case BuiltinTypeSpec.Type.ULong:
7323 return new ULongConstant (t, 0, loc);
7324 case BuiltinTypeSpec.Type.Float:
7325 return new FloatConstant (t, 0, loc);
7326 case BuiltinTypeSpec.Type.Double:
7327 return new DoubleConstant (t, 0, loc);
7328 case BuiltinTypeSpec.Type.Short:
7329 return new ShortConstant (t, 0, loc);
7330 case BuiltinTypeSpec.Type.UShort:
7331 return new UShortConstant (t, 0, loc);
7332 case BuiltinTypeSpec.Type.SByte:
7333 return new SByteConstant (t, 0, loc);
7334 case BuiltinTypeSpec.Type.Byte:
7335 return new ByteConstant (t, 0, loc);
7336 case BuiltinTypeSpec.Type.Char:
7337 return new CharConstant (t, '\0', loc);
7338 case BuiltinTypeSpec.Type.Bool:
7339 return new BoolConstant (t, false, loc);
7340 case BuiltinTypeSpec.Type.Decimal:
7341 return new DecimalConstant (t, 0, loc);
7345 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7347 if (t.IsNullableType)
7348 return Nullable.LiftedNull.Create (t, loc);
7353 public override bool ContainsEmitWithAwait ()
7355 return arguments != null && arguments.ContainsEmitWithAwait ();
7359 // Checks whether the type is an interface that has the
7360 // [ComImport, CoClass] attributes and must be treated
7363 public Expression CheckComImport (ResolveContext ec)
7365 if (!type.IsInterface)
7369 // Turn the call into:
7370 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7372 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7373 if (real_class == null)
7376 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7377 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7378 return cast.Resolve (ec);
7381 public override Expression CreateExpressionTree (ResolveContext ec)
7384 if (method == null) {
7385 args = new Arguments (1);
7386 args.Add (new Argument (new TypeOf (type, loc)));
7388 args = Arguments.CreateForExpressionTree (ec,
7389 arguments, new TypeOfMethod (method, loc));
7392 return CreateExpressionFactoryCall (ec, "New", args);
7395 protected override Expression DoResolve (ResolveContext ec)
7397 type = RequestedType.ResolveAsType (ec);
7401 eclass = ExprClass.Value;
7403 if (type.IsPointer) {
7404 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7405 type.GetSignatureForError ());
7409 if (arguments == null) {
7410 Constant c = Constantify (type, RequestedType.Location);
7412 return ReducedExpression.Create (c, this);
7415 if (type.IsDelegate) {
7416 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7419 var tparam = type as TypeParameterSpec;
7420 if (tparam != null) {
7422 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7423 // where type parameter constraint is inflated to struct
7425 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7426 ec.Report.Error (304, loc,
7427 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7428 type.GetSignatureForError ());
7431 if ((arguments != null) && (arguments.Count != 0)) {
7432 ec.Report.Error (417, loc,
7433 "`{0}': cannot provide arguments when creating an instance of a variable type",
7434 type.GetSignatureForError ());
7440 if (type.IsStatic) {
7441 ec.Report.SymbolRelatedToPreviousError (type);
7442 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7446 if (type.IsInterface || type.IsAbstract){
7447 if (!TypeManager.IsGenericType (type)) {
7448 RequestedType = CheckComImport (ec);
7449 if (RequestedType != null)
7450 return RequestedType;
7453 ec.Report.SymbolRelatedToPreviousError (type);
7454 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7459 if (arguments != null) {
7460 arguments.Resolve (ec, out dynamic);
7465 method = ConstructorLookup (ec, type, ref arguments, loc);
7468 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7469 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7475 void DoEmitTypeParameter (EmitContext ec)
7477 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7481 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7482 ec.Emit (OpCodes.Call, ctor_factory);
7486 // This Emit can be invoked in two contexts:
7487 // * As a mechanism that will leave a value on the stack (new object)
7488 // * As one that wont (init struct)
7490 // If we are dealing with a ValueType, we have a few
7491 // situations to deal with:
7493 // * The target is a ValueType, and we have been provided
7494 // the instance (this is easy, we are being assigned).
7496 // * The target of New is being passed as an argument,
7497 // to a boxing operation or a function that takes a
7500 // In this case, we need to create a temporary variable
7501 // that is the argument of New.
7503 // Returns whether a value is left on the stack
7505 // *** Implementation note ***
7507 // To benefit from this optimization, each assignable expression
7508 // has to manually cast to New and call this Emit.
7510 // TODO: It's worth to implement it for arrays and fields
7512 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7514 bool is_value_type = type.IsStructOrEnum;
7515 VariableReference vr = target as VariableReference;
7517 if (target != null && is_value_type && (vr != null || method == null)) {
7518 target.AddressOf (ec, AddressOp.Store);
7519 } else if (vr != null && vr.IsRef) {
7523 if (arguments != null) {
7524 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7525 arguments = arguments.Emit (ec, false, true);
7527 arguments.Emit (ec);
7530 if (is_value_type) {
7531 if (method == null) {
7532 ec.Emit (OpCodes.Initobj, type);
7537 ec.MarkCallEntry (loc);
7538 ec.Emit (OpCodes.Call, method);
7543 if (type is TypeParameterSpec) {
7544 DoEmitTypeParameter (ec);
7548 ec.MarkCallEntry (loc);
7549 ec.Emit (OpCodes.Newobj, method);
7553 public override void Emit (EmitContext ec)
7555 LocalTemporary v = null;
7556 if (method == null && type.IsStructOrEnum) {
7557 // TODO: Use temporary variable from pool
7558 v = new LocalTemporary (type);
7565 public override void EmitStatement (EmitContext ec)
7567 LocalTemporary v = null;
7568 if (method == null && TypeSpec.IsValueType (type)) {
7569 // TODO: Use temporary variable from pool
7570 v = new LocalTemporary (type);
7574 ec.Emit (OpCodes.Pop);
7577 public override void FlowAnalysis (FlowAnalysisContext fc)
7579 if (arguments != null)
7580 arguments.FlowAnalysis (fc);
7583 public void AddressOf (EmitContext ec, AddressOp mode)
7585 EmitAddressOf (ec, mode);
7588 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7590 LocalTemporary value_target = new LocalTemporary (type);
7592 if (type is TypeParameterSpec) {
7593 DoEmitTypeParameter (ec);
7594 value_target.Store (ec);
7595 value_target.AddressOf (ec, mode);
7596 return value_target;
7599 value_target.AddressOf (ec, AddressOp.Store);
7601 if (method == null) {
7602 ec.Emit (OpCodes.Initobj, type);
7604 if (arguments != null)
7605 arguments.Emit (ec);
7607 ec.Emit (OpCodes.Call, method);
7610 value_target.AddressOf (ec, mode);
7611 return value_target;
7614 protected override void CloneTo (CloneContext clonectx, Expression t)
7616 New target = (New) t;
7618 target.RequestedType = RequestedType.Clone (clonectx);
7619 if (arguments != null){
7620 target.arguments = arguments.Clone (clonectx);
7624 public override SLE.Expression MakeExpression (BuilderContext ctx)
7627 return base.MakeExpression (ctx);
7629 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7633 public override object Accept (StructuralVisitor visitor)
7635 return visitor.Visit (this);
7640 // Array initializer expression, the expression is allowed in
7641 // variable or field initialization only which makes it tricky as
7642 // the type has to be infered based on the context either from field
7643 // type or variable type (think of multiple declarators)
7645 public class ArrayInitializer : Expression
7647 List<Expression> elements;
7648 BlockVariable variable;
7650 public ArrayInitializer (List<Expression> init, Location loc)
7656 public ArrayInitializer (int count, Location loc)
7657 : this (new List<Expression> (count), loc)
7661 public ArrayInitializer (Location loc)
7669 get { return elements.Count; }
7672 public List<Expression> Elements {
7678 public Expression this [int index] {
7680 return elements [index];
7684 public BlockVariable VariableDeclaration {
7695 public void Add (Expression expr)
7697 elements.Add (expr);
7700 public override bool ContainsEmitWithAwait ()
7702 throw new NotSupportedException ();
7705 public override Expression CreateExpressionTree (ResolveContext ec)
7707 throw new NotSupportedException ("ET");
7710 protected override void CloneTo (CloneContext clonectx, Expression t)
7712 var target = (ArrayInitializer) t;
7714 target.elements = new List<Expression> (elements.Count);
7715 foreach (var element in elements)
7716 target.elements.Add (element.Clone (clonectx));
7719 protected override Expression DoResolve (ResolveContext rc)
7721 var current_field = rc.CurrentMemberDefinition as FieldBase;
7722 TypeExpression type;
7723 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7724 type = new TypeExpression (current_field.MemberType, current_field.Location);
7725 } else if (variable != null) {
7726 if (variable.TypeExpression is VarExpr) {
7727 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7728 return EmptyExpression.Null;
7731 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7733 throw new NotImplementedException ("Unexpected array initializer context");
7736 return new ArrayCreation (type, this).Resolve (rc);
7739 public override void Emit (EmitContext ec)
7741 throw new InternalErrorException ("Missing Resolve call");
7744 public override void FlowAnalysis (FlowAnalysisContext fc)
7746 throw new InternalErrorException ("Missing Resolve call");
7749 public override object Accept (StructuralVisitor visitor)
7751 return visitor.Visit (this);
7756 /// 14.5.10.2: Represents an array creation expression.
7760 /// There are two possible scenarios here: one is an array creation
7761 /// expression that specifies the dimensions and optionally the
7762 /// initialization data and the other which does not need dimensions
7763 /// specified but where initialization data is mandatory.
7765 public class ArrayCreation : Expression
7767 FullNamedExpression requested_base_type;
7768 ArrayInitializer initializers;
7771 // The list of Argument types.
7772 // This is used to construct the `newarray' or constructor signature
7774 protected List<Expression> arguments;
7776 protected TypeSpec array_element_type;
7778 protected int dimensions;
7779 protected readonly ComposedTypeSpecifier rank;
7780 Expression first_emit;
7781 LocalTemporary first_emit_temp;
7783 protected List<Expression> array_data;
7785 Dictionary<int, int> bounds;
7788 // The number of constants in array initializers
7789 int const_initializers_count;
7790 bool only_constant_initializers;
7792 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7793 : this (requested_base_type, rank, initializers, l)
7795 arguments = new List<Expression> (exprs);
7796 num_arguments = arguments.Count;
7800 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7802 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7804 this.requested_base_type = requested_base_type;
7806 this.initializers = initializers;
7810 num_arguments = rank.Dimension;
7814 // For compiler generated single dimensional arrays only
7816 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7817 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7822 // For expressions like int[] foo = { 1, 2, 3 };
7824 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7825 : this (requested_base_type, null, initializers, initializers.Location)
7829 public ComposedTypeSpecifier Rank {
7835 public FullNamedExpression TypeExpression {
7837 return this.requested_base_type;
7841 public ArrayInitializer Initializers {
7843 return this.initializers;
7847 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7849 if (initializers != null && bounds == null) {
7851 // We use this to store all the data values in the order in which we
7852 // will need to store them in the byte blob later
7854 array_data = new List<Expression> (probe.Count);
7855 bounds = new Dictionary<int, int> ();
7858 if (specified_dims) {
7859 Expression a = arguments [idx];
7864 a = ConvertExpressionToArrayIndex (ec, a);
7870 if (initializers != null) {
7871 Constant c = a as Constant;
7872 if (c == null && a is ArrayIndexCast)
7873 c = ((ArrayIndexCast) a).Child as Constant;
7876 ec.Report.Error (150, a.Location, "A constant value is expected");
7882 value = System.Convert.ToInt32 (c.GetValue ());
7884 ec.Report.Error (150, a.Location, "A constant value is expected");
7888 // TODO: probe.Count does not fit ulong in
7889 if (value != probe.Count) {
7890 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7894 bounds[idx] = value;
7898 if (initializers == null)
7901 for (int i = 0; i < probe.Count; ++i) {
7903 if (o is ArrayInitializer) {
7904 var sub_probe = o as ArrayInitializer;
7905 if (idx + 1 >= dimensions){
7906 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7910 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7911 if (!bounds.ContainsKey(idx + 1))
7912 bounds[idx + 1] = sub_probe.Count;
7914 if (bounds[idx + 1] != sub_probe.Count) {
7915 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7919 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7922 } else if (child_bounds > 1) {
7923 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7925 Expression element = ResolveArrayElement (ec, o);
7926 if (element == null)
7929 // Initializers with the default values can be ignored
7930 Constant c = element as Constant;
7932 if (!c.IsDefaultInitializer (array_element_type)) {
7933 ++const_initializers_count;
7936 only_constant_initializers = false;
7939 array_data.Add (element);
7946 public override bool ContainsEmitWithAwait ()
7948 foreach (var arg in arguments) {
7949 if (arg.ContainsEmitWithAwait ())
7953 return InitializersContainAwait ();
7956 public override Expression CreateExpressionTree (ResolveContext ec)
7960 if (array_data == null) {
7961 args = new Arguments (arguments.Count + 1);
7962 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7963 foreach (Expression a in arguments)
7964 args.Add (new Argument (a.CreateExpressionTree (ec)));
7966 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7969 if (dimensions > 1) {
7970 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7974 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7975 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7976 if (array_data != null) {
7977 for (int i = 0; i < array_data.Count; ++i) {
7978 Expression e = array_data [i];
7979 args.Add (new Argument (e.CreateExpressionTree (ec)));
7983 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7986 void UpdateIndices (ResolveContext rc)
7989 for (var probe = initializers; probe != null;) {
7990 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7992 bounds[i++] = probe.Count;
7994 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7995 probe = (ArrayInitializer) probe[0];
7996 } else if (dimensions > i) {
8004 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8006 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8009 public override void FlowAnalysis (FlowAnalysisContext fc)
8011 foreach (var arg in arguments)
8012 arg.FlowAnalysis (fc);
8014 if (array_data != null) {
8015 foreach (var ad in array_data)
8016 ad.FlowAnalysis (fc);
8020 bool InitializersContainAwait ()
8022 if (array_data == null)
8025 foreach (var expr in array_data) {
8026 if (expr.ContainsEmitWithAwait ())
8033 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8035 element = element.Resolve (ec);
8036 if (element == null)
8039 if (element is CompoundAssign.TargetExpression) {
8040 if (first_emit != null)
8041 throw new InternalErrorException ("Can only handle one mutator at a time");
8042 first_emit = element;
8043 element = first_emit_temp = new LocalTemporary (element.Type);
8046 return Convert.ImplicitConversionRequired (
8047 ec, element, array_element_type, loc);
8050 protected bool ResolveInitializers (ResolveContext ec)
8053 only_constant_initializers = true;
8056 if (arguments != null) {
8058 for (int i = 0; i < arguments.Count; ++i) {
8059 res &= CheckIndices (ec, initializers, i, true, dimensions);
8060 if (initializers != null)
8067 arguments = new List<Expression> ();
8069 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8078 // Resolved the type of the array
8080 bool ResolveArrayType (ResolveContext ec)
8085 FullNamedExpression array_type_expr;
8086 if (num_arguments > 0) {
8087 array_type_expr = new ComposedCast (requested_base_type, rank);
8089 array_type_expr = requested_base_type;
8092 type = array_type_expr.ResolveAsType (ec);
8093 if (array_type_expr == null)
8096 var ac = type as ArrayContainer;
8098 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8102 array_element_type = ac.Element;
8103 dimensions = ac.Rank;
8108 protected override Expression DoResolve (ResolveContext ec)
8113 if (!ResolveArrayType (ec))
8117 // validate the initializers and fill in any missing bits
8119 if (!ResolveInitializers (ec))
8122 eclass = ExprClass.Value;
8126 byte [] MakeByteBlob ()
8131 int count = array_data.Count;
8133 TypeSpec element_type = array_element_type;
8134 if (element_type.IsEnum)
8135 element_type = EnumSpec.GetUnderlyingType (element_type);
8137 factor = BuiltinTypeSpec.GetSize (element_type);
8139 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8141 data = new byte [(count * factor + 3) & ~3];
8144 for (int i = 0; i < count; ++i) {
8145 var c = array_data[i] as Constant;
8151 object v = c.GetValue ();
8153 switch (element_type.BuiltinType) {
8154 case BuiltinTypeSpec.Type.Long:
8155 long lval = (long) v;
8157 for (int j = 0; j < factor; ++j) {
8158 data[idx + j] = (byte) (lval & 0xFF);
8162 case BuiltinTypeSpec.Type.ULong:
8163 ulong ulval = (ulong) v;
8165 for (int j = 0; j < factor; ++j) {
8166 data[idx + j] = (byte) (ulval & 0xFF);
8167 ulval = (ulval >> 8);
8170 case BuiltinTypeSpec.Type.Float:
8171 var fval = SingleConverter.SingleToInt32Bits((float) v);
8173 data[idx] = (byte) (fval & 0xff);
8174 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8175 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8176 data[idx + 3] = (byte) (fval >> 24);
8178 case BuiltinTypeSpec.Type.Double:
8179 element = BitConverter.GetBytes ((double) v);
8181 for (int j = 0; j < factor; ++j)
8182 data[idx + j] = element[j];
8184 // FIXME: Handle the ARM float format.
8185 if (!BitConverter.IsLittleEndian)
8186 System.Array.Reverse (data, idx, 8);
8188 case BuiltinTypeSpec.Type.Char:
8189 int chval = (int) ((char) v);
8191 data[idx] = (byte) (chval & 0xff);
8192 data[idx + 1] = (byte) (chval >> 8);
8194 case BuiltinTypeSpec.Type.Short:
8195 int sval = (int) ((short) v);
8197 data[idx] = (byte) (sval & 0xff);
8198 data[idx + 1] = (byte) (sval >> 8);
8200 case BuiltinTypeSpec.Type.UShort:
8201 int usval = (int) ((ushort) v);
8203 data[idx] = (byte) (usval & 0xff);
8204 data[idx + 1] = (byte) (usval >> 8);
8206 case BuiltinTypeSpec.Type.Int:
8209 data[idx] = (byte) (val & 0xff);
8210 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8211 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8212 data[idx + 3] = (byte) (val >> 24);
8214 case BuiltinTypeSpec.Type.UInt:
8215 uint uval = (uint) v;
8217 data[idx] = (byte) (uval & 0xff);
8218 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8219 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8220 data[idx + 3] = (byte) (uval >> 24);
8222 case BuiltinTypeSpec.Type.SByte:
8223 data[idx] = (byte) (sbyte) v;
8225 case BuiltinTypeSpec.Type.Byte:
8226 data[idx] = (byte) v;
8228 case BuiltinTypeSpec.Type.Bool:
8229 data[idx] = (byte) ((bool) v ? 1 : 0);
8231 case BuiltinTypeSpec.Type.Decimal:
8232 int[] bits = Decimal.GetBits ((decimal) v);
8235 // FIXME: For some reason, this doesn't work on the MS runtime.
8236 int[] nbits = new int[4];
8242 for (int j = 0; j < 4; j++) {
8243 data[p++] = (byte) (nbits[j] & 0xff);
8244 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8245 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8246 data[p++] = (byte) (nbits[j] >> 24);
8250 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8259 #if NET_4_0 || MOBILE_DYNAMIC
8260 public override SLE.Expression MakeExpression (BuilderContext ctx)
8263 return base.MakeExpression (ctx);
8265 var initializers = new SLE.Expression [array_data.Count];
8266 for (var i = 0; i < initializers.Length; i++) {
8267 if (array_data [i] == null)
8268 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8270 initializers [i] = array_data [i].MakeExpression (ctx);
8273 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8279 // Emits the initializers for the array
8281 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8283 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8288 // First, the static data
8290 byte [] data = MakeByteBlob ();
8291 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8293 if (stackArray == null) {
8294 ec.Emit (OpCodes.Dup);
8296 stackArray.Emit (ec);
8299 ec.Emit (OpCodes.Ldtoken, fb);
8300 ec.Emit (OpCodes.Call, m);
8305 // Emits pieces of the array that can not be computed at compile
8306 // time (variables and string locations).
8308 // This always expect the top value on the stack to be the array
8310 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8312 int dims = bounds.Count;
8313 var current_pos = new int [dims];
8315 for (int i = 0; i < array_data.Count; i++){
8317 Expression e = array_data [i];
8318 var c = e as Constant;
8320 // Constant can be initialized via StaticInitializer
8321 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8325 if (stackArray != null) {
8326 if (e.ContainsEmitWithAwait ()) {
8327 e = e.EmitToField (ec);
8330 stackArray.EmitLoad (ec);
8332 ec.Emit (OpCodes.Dup);
8335 for (int idx = 0; idx < dims; idx++)
8336 ec.EmitInt (current_pos [idx]);
8339 // If we are dealing with a struct, get the
8340 // address of it, so we can store it.
8342 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8343 ec.Emit (OpCodes.Ldelema, etype);
8347 ec.EmitArrayStore ((ArrayContainer) type);
8353 for (int j = dims - 1; j >= 0; j--){
8355 if (current_pos [j] < bounds [j])
8357 current_pos [j] = 0;
8361 if (stackArray != null)
8362 stackArray.PrepareCleanup (ec);
8365 public override void Emit (EmitContext ec)
8367 var await_field = EmitToFieldSource (ec);
8368 if (await_field != null)
8369 await_field.Emit (ec);
8372 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8374 if (first_emit != null) {
8375 first_emit.Emit (ec);
8376 first_emit_temp.Store (ec);
8379 StackFieldExpr await_stack_field;
8380 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8381 await_stack_field = ec.GetTemporaryField (type);
8384 await_stack_field = null;
8387 EmitExpressionsList (ec, arguments);
8389 ec.EmitArrayNew ((ArrayContainer) type);
8391 if (initializers == null)
8392 return await_stack_field;
8394 if (await_stack_field != null)
8395 await_stack_field.EmitAssignFromStack (ec);
8399 // Emit static initializer for arrays which contain more than 2 items and
8400 // the static initializer will initialize at least 25% of array values or there
8401 // is more than 10 items to be initialized
8403 // NOTE: const_initializers_count does not contain default constant values.
8405 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8406 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8407 EmitStaticInitializers (ec, await_stack_field);
8409 if (!only_constant_initializers)
8410 EmitDynamicInitializers (ec, false, await_stack_field);
8414 EmitDynamicInitializers (ec, true, await_stack_field);
8417 if (first_emit_temp != null)
8418 first_emit_temp.Release (ec);
8420 return await_stack_field;
8423 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8425 // no multi dimensional or jagged arrays
8426 if (arguments.Count != 1 || array_element_type.IsArray) {
8427 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8431 // No array covariance, except for array -> object
8432 if (type != targetType) {
8433 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8434 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8438 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8439 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8444 // Single dimensional array of 0 size
8445 if (array_data == null) {
8446 IntConstant ic = arguments[0] as IntConstant;
8447 if (ic == null || !ic.IsDefaultValue) {
8448 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8456 enc.Encode (array_data.Count);
8457 foreach (var element in array_data) {
8458 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8462 protected override void CloneTo (CloneContext clonectx, Expression t)
8464 ArrayCreation target = (ArrayCreation) t;
8466 if (requested_base_type != null)
8467 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8469 if (arguments != null){
8470 target.arguments = new List<Expression> (arguments.Count);
8471 foreach (Expression e in arguments)
8472 target.arguments.Add (e.Clone (clonectx));
8475 if (initializers != null)
8476 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8479 public override object Accept (StructuralVisitor visitor)
8481 return visitor.Visit (this);
8486 // Represents an implicitly typed array epxression
8488 class ImplicitlyTypedArrayCreation : ArrayCreation
8490 TypeInferenceContext best_type_inference;
8492 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8493 : base (null, rank, initializers, loc)
8497 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8498 : base (null, initializers, loc)
8502 protected override Expression DoResolve (ResolveContext ec)
8507 dimensions = rank.Dimension;
8509 best_type_inference = new TypeInferenceContext ();
8511 if (!ResolveInitializers (ec))
8514 best_type_inference.FixAllTypes (ec);
8515 array_element_type = best_type_inference.InferredTypeArguments[0];
8516 best_type_inference = null;
8518 if (array_element_type == null ||
8519 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8520 arguments.Count != rank.Dimension) {
8521 ec.Report.Error (826, loc,
8522 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8527 // At this point we found common base type for all initializer elements
8528 // but we have to be sure that all static initializer elements are of
8531 UnifyInitializerElement (ec);
8533 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8534 eclass = ExprClass.Value;
8539 // Converts static initializer only
8541 void UnifyInitializerElement (ResolveContext ec)
8543 for (int i = 0; i < array_data.Count; ++i) {
8544 Expression e = array_data[i];
8546 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8550 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8552 element = element.Resolve (ec);
8553 if (element != null)
8554 best_type_inference.AddCommonTypeBound (element.Type);
8560 sealed class CompilerGeneratedThis : This
8562 public CompilerGeneratedThis (TypeSpec type, Location loc)
8568 protected override Expression DoResolve (ResolveContext rc)
8570 eclass = ExprClass.Variable;
8572 var block = rc.CurrentBlock;
8573 if (block != null) {
8574 var top = block.ParametersBlock.TopBlock;
8575 if (top.ThisVariable != null)
8576 variable_info = top.ThisVariable.VariableInfo;
8583 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8585 return DoResolve (rc);
8588 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8595 /// Represents the `this' construct
8598 public class This : VariableReference
8600 sealed class ThisVariable : ILocalVariable
8602 public static readonly ILocalVariable Instance = new ThisVariable ();
8604 public void Emit (EmitContext ec)
8609 public void EmitAssign (EmitContext ec)
8611 throw new InvalidOperationException ();
8614 public void EmitAddressOf (EmitContext ec)
8620 protected VariableInfo variable_info;
8622 public This (Location loc)
8629 public override string Name {
8630 get { return "this"; }
8633 public override bool IsLockedByStatement {
8641 public override bool IsRef {
8642 get { return type.IsStruct; }
8645 public override bool IsSideEffectFree {
8651 protected override ILocalVariable Variable {
8652 get { return ThisVariable.Instance; }
8655 public override VariableInfo VariableInfo {
8656 get { return variable_info; }
8659 public override bool IsFixed {
8660 get { return false; }
8665 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8668 // It's null for all cases when we don't need to check `this'
8669 // definitive assignment
8671 if (variable_info == null)
8674 if (fc.IsDefinitelyAssigned (variable_info))
8677 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8680 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8682 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8683 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8684 } else if (ec.CurrentAnonymousMethod != null) {
8685 ec.Report.Error (1673, loc,
8686 "Anonymous methods inside structs cannot access instance members of `this'. " +
8687 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8689 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8693 public override void FlowAnalysis (FlowAnalysisContext fc)
8695 CheckStructThisDefiniteAssignment (fc);
8698 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8703 AnonymousMethodStorey storey = ae.Storey;
8704 return storey != null ? storey.HoistedThis : null;
8707 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8709 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8712 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8715 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8721 public virtual void ResolveBase (ResolveContext ec)
8723 eclass = ExprClass.Variable;
8724 type = ec.CurrentType;
8726 if (!IsThisAvailable (ec, false)) {
8727 Error_ThisNotAvailable (ec);
8731 var block = ec.CurrentBlock;
8732 if (block != null) {
8733 var top = block.ParametersBlock.TopBlock;
8734 if (top.ThisVariable != null)
8735 variable_info = top.ThisVariable.VariableInfo;
8737 AnonymousExpression am = ec.CurrentAnonymousMethod;
8738 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8740 // Hoisted this is almost like hoisted variable but not exactly. When
8741 // there is no variable hoisted we can simply emit an instance method
8742 // without lifting this into a storey. Unfotunatelly this complicates
8743 // things in other cases because we don't know where this will be hoisted
8744 // until top-level block is fully resolved
8746 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8747 am.SetHasThisAccess ();
8752 protected override Expression DoResolve (ResolveContext ec)
8758 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8760 if (eclass == ExprClass.Unresolved)
8764 if (right_side == EmptyExpression.UnaryAddress)
8765 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8766 else if (right_side == EmptyExpression.OutAccess)
8767 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8769 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8775 public override int GetHashCode()
8777 throw new NotImplementedException ();
8780 public override bool Equals (object obj)
8782 This t = obj as This;
8789 protected override void CloneTo (CloneContext clonectx, Expression t)
8794 public override void SetHasAddressTaken ()
8799 public override object Accept (StructuralVisitor visitor)
8801 return visitor.Visit (this);
8806 /// Represents the `__arglist' construct
8808 public class ArglistAccess : Expression
8810 public ArglistAccess (Location loc)
8815 protected override void CloneTo (CloneContext clonectx, Expression target)
8820 public override bool ContainsEmitWithAwait ()
8825 public override Expression CreateExpressionTree (ResolveContext ec)
8827 throw new NotSupportedException ("ET");
8830 protected override Expression DoResolve (ResolveContext ec)
8832 eclass = ExprClass.Variable;
8833 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8835 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8836 ec.Report.Error (190, loc,
8837 "The __arglist construct is valid only within a variable argument method");
8843 public override void Emit (EmitContext ec)
8845 ec.Emit (OpCodes.Arglist);
8848 public override object Accept (StructuralVisitor visitor)
8850 return visitor.Visit (this);
8855 /// Represents the `__arglist (....)' construct
8857 public class Arglist : Expression
8859 Arguments arguments;
8861 public Arglist (Location loc)
8866 public Arglist (Arguments args, Location l)
8872 public Arguments Arguments {
8878 public MetaType[] ArgumentTypes {
8880 if (arguments == null)
8881 return MetaType.EmptyTypes;
8883 var retval = new MetaType[arguments.Count];
8884 for (int i = 0; i < retval.Length; i++)
8885 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8891 public override bool ContainsEmitWithAwait ()
8893 throw new NotImplementedException ();
8896 public override Expression CreateExpressionTree (ResolveContext ec)
8898 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8902 protected override Expression DoResolve (ResolveContext ec)
8904 eclass = ExprClass.Variable;
8905 type = InternalType.Arglist;
8906 if (arguments != null) {
8907 bool dynamic; // Can be ignored as there is always only 1 overload
8908 arguments.Resolve (ec, out dynamic);
8914 public override void Emit (EmitContext ec)
8916 if (arguments != null)
8917 arguments.Emit (ec);
8920 protected override void CloneTo (CloneContext clonectx, Expression t)
8922 Arglist target = (Arglist) t;
8924 if (arguments != null)
8925 target.arguments = arguments.Clone (clonectx);
8928 public override object Accept (StructuralVisitor visitor)
8930 return visitor.Visit (this);
8934 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8936 FullNamedExpression texpr;
8938 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8945 public FullNamedExpression TypeExpression {
8951 public override bool ContainsEmitWithAwait ()
8956 public void AddressOf (EmitContext ec, AddressOp mode)
8959 ec.Emit (OpCodes.Refanyval, type);
8962 protected override Expression DoResolve (ResolveContext rc)
8964 expr = expr.Resolve (rc);
8965 type = texpr.ResolveAsType (rc);
8966 if (expr == null || type == null)
8969 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8970 eclass = ExprClass.Variable;
8974 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8976 return DoResolve (rc);
8979 public override void Emit (EmitContext ec)
8982 ec.Emit (OpCodes.Refanyval, type);
8983 ec.EmitLoadFromPtr (type);
8986 public void Emit (EmitContext ec, bool leave_copy)
8988 throw new NotImplementedException ();
8991 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8994 ec.Emit (OpCodes.Refanyval, type);
8997 LocalTemporary temporary = null;
8999 ec.Emit (OpCodes.Dup);
9000 temporary = new LocalTemporary (source.Type);
9001 temporary.Store (ec);
9004 ec.EmitStoreFromPtr (type);
9006 if (temporary != null) {
9007 temporary.Emit (ec);
9008 temporary.Release (ec);
9012 public override object Accept (StructuralVisitor visitor)
9014 return visitor.Visit (this);
9018 public class RefTypeExpr : ShimExpression
9020 public RefTypeExpr (Expression expr, Location loc)
9026 protected override Expression DoResolve (ResolveContext rc)
9028 expr = expr.Resolve (rc);
9032 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9036 type = rc.BuiltinTypes.Type;
9037 eclass = ExprClass.Value;
9041 public override void Emit (EmitContext ec)
9044 ec.Emit (OpCodes.Refanytype);
9045 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9047 ec.Emit (OpCodes.Call, m);
9050 public override object Accept (StructuralVisitor visitor)
9052 return visitor.Visit (this);
9056 public class MakeRefExpr : ShimExpression
9058 public MakeRefExpr (Expression expr, Location loc)
9064 public override bool ContainsEmitWithAwait ()
9066 throw new NotImplementedException ();
9069 protected override Expression DoResolve (ResolveContext rc)
9071 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9072 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9073 eclass = ExprClass.Value;
9077 public override void Emit (EmitContext ec)
9079 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9080 ec.Emit (OpCodes.Mkrefany, expr.Type);
9083 public override object Accept (StructuralVisitor visitor)
9085 return visitor.Visit (this);
9090 /// Implements the typeof operator
9092 public class TypeOf : Expression {
9093 FullNamedExpression QueriedType;
9096 public TypeOf (FullNamedExpression queried_type, Location l)
9098 QueriedType = queried_type;
9103 // Use this constructor for any compiler generated typeof expression
9105 public TypeOf (TypeSpec type, Location loc)
9107 this.typearg = type;
9113 public override bool IsSideEffectFree {
9119 public TypeSpec TypeArgument {
9125 public FullNamedExpression TypeExpression {
9134 protected override void CloneTo (CloneContext clonectx, Expression t)
9136 TypeOf target = (TypeOf) t;
9137 if (QueriedType != null)
9138 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9141 public override bool ContainsEmitWithAwait ()
9146 public override Expression CreateExpressionTree (ResolveContext ec)
9148 Arguments args = new Arguments (2);
9149 args.Add (new Argument (this));
9150 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9151 return CreateExpressionFactoryCall (ec, "Constant", args);
9154 protected override Expression DoResolve (ResolveContext ec)
9156 if (eclass != ExprClass.Unresolved)
9159 if (typearg == null) {
9161 // Pointer types are allowed without explicit unsafe, they are just tokens
9163 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9164 typearg = QueriedType.ResolveAsType (ec, true);
9167 if (typearg == null)
9170 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9171 ec.Report.Error (1962, QueriedType.Location,
9172 "The typeof operator cannot be used on the dynamic type");
9176 type = ec.BuiltinTypes.Type;
9178 // Even though what is returned is a type object, it's treated as a value by the compiler.
9179 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9180 eclass = ExprClass.Value;
9184 static bool ContainsDynamicType (TypeSpec type)
9186 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9189 var element_container = type as ElementTypeSpec;
9190 if (element_container != null)
9191 return ContainsDynamicType (element_container.Element);
9193 foreach (var t in type.TypeArguments) {
9194 if (ContainsDynamicType (t)) {
9202 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9204 // Target type is not System.Type therefore must be object
9205 // and we need to use different encoding sequence
9206 if (targetType != type)
9209 if (typearg is InflatedTypeSpec) {
9212 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9213 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9214 typearg.GetSignatureForError ());
9218 gt = gt.DeclaringType;
9219 } while (gt != null);
9222 if (ContainsDynamicType (typearg)) {
9223 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9227 enc.EncodeTypeName (typearg);
9230 public override void Emit (EmitContext ec)
9232 ec.Emit (OpCodes.Ldtoken, typearg);
9233 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9235 ec.Emit (OpCodes.Call, m);
9238 public override object Accept (StructuralVisitor visitor)
9240 return visitor.Visit (this);
9244 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9246 public TypeOfMethod (MethodSpec method, Location loc)
9247 : base (method, loc)
9251 protected override Expression DoResolve (ResolveContext ec)
9253 if (member.IsConstructor) {
9254 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9256 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9262 return base.DoResolve (ec);
9265 public override void Emit (EmitContext ec)
9267 ec.Emit (OpCodes.Ldtoken, member);
9270 ec.Emit (OpCodes.Castclass, type);
9273 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9275 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9278 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9280 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9284 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9286 protected readonly T member;
9288 protected TypeOfMember (T member, Location loc)
9290 this.member = member;
9294 public override bool IsSideEffectFree {
9300 public override bool ContainsEmitWithAwait ()
9305 public override Expression CreateExpressionTree (ResolveContext ec)
9307 Arguments args = new Arguments (2);
9308 args.Add (new Argument (this));
9309 args.Add (new Argument (new TypeOf (type, loc)));
9310 return CreateExpressionFactoryCall (ec, "Constant", args);
9313 protected override Expression DoResolve (ResolveContext ec)
9315 eclass = ExprClass.Value;
9319 public override void Emit (EmitContext ec)
9321 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9322 PredefinedMember<MethodSpec> p;
9324 p = GetTypeFromHandleGeneric (ec);
9325 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9327 p = GetTypeFromHandle (ec);
9330 var mi = p.Resolve (loc);
9332 ec.Emit (OpCodes.Call, mi);
9335 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9336 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9339 sealed class TypeOfField : TypeOfMember<FieldSpec>
9341 public TypeOfField (FieldSpec field, Location loc)
9346 protected override Expression DoResolve (ResolveContext ec)
9348 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9352 return base.DoResolve (ec);
9355 public override void Emit (EmitContext ec)
9357 ec.Emit (OpCodes.Ldtoken, member);
9361 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9363 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9366 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9368 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9373 /// Implements the sizeof expression
9375 public class SizeOf : Expression {
9376 readonly Expression texpr;
9377 TypeSpec type_queried;
9379 public SizeOf (Expression queried_type, Location l)
9381 this.texpr = queried_type;
9385 public override bool IsSideEffectFree {
9391 public Expression TypeExpression {
9397 public override bool ContainsEmitWithAwait ()
9402 public override Expression CreateExpressionTree (ResolveContext ec)
9404 Error_PointerInsideExpressionTree (ec);
9408 protected override Expression DoResolve (ResolveContext ec)
9410 type_queried = texpr.ResolveAsType (ec);
9411 if (type_queried == null)
9414 if (type_queried.IsEnum)
9415 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9417 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9419 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9422 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9427 ec.Report.Error (233, loc,
9428 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9429 type_queried.GetSignatureForError ());
9432 type = ec.BuiltinTypes.Int;
9433 eclass = ExprClass.Value;
9437 public override void Emit (EmitContext ec)
9439 ec.Emit (OpCodes.Sizeof, type_queried);
9442 protected override void CloneTo (CloneContext clonectx, Expression t)
9446 public override object Accept (StructuralVisitor visitor)
9448 return visitor.Visit (this);
9453 /// Implements the qualified-alias-member (::) expression.
9455 public class QualifiedAliasMember : MemberAccess
9457 readonly string alias;
9458 public static readonly string GlobalAlias = "global";
9460 public QualifiedAliasMember (string alias, string identifier, Location l)
9461 : base (null, identifier, l)
9466 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9467 : base (null, identifier, targs, l)
9472 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9473 : base (null, identifier, arity, l)
9478 public string Alias {
9484 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9486 if (alias == GlobalAlias)
9487 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9489 int errors = mc.Module.Compiler.Report.Errors;
9490 var expr = mc.LookupNamespaceAlias (alias);
9492 if (errors == mc.Module.Compiler.Report.Errors)
9493 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9501 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9503 expr = CreateExpressionFromAlias (mc);
9507 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9510 protected override Expression DoResolve (ResolveContext rc)
9512 return ResolveAsTypeOrNamespace (rc, false);
9515 public override string GetSignatureForError ()
9518 if (targs != null) {
9519 name = Name + "<" + targs.GetSignatureForError () + ">";
9522 return alias + "::" + name;
9525 public override bool HasConditionalAccess ()
9530 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9532 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9533 rc.Module.Compiler.Report.Error (687, loc,
9534 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9535 GetSignatureForError ());
9540 return DoResolve (rc);
9543 protected override void CloneTo (CloneContext clonectx, Expression t)
9548 public override object Accept (StructuralVisitor visitor)
9550 return visitor.Visit (this);
9555 /// Implements the member access expression
9557 public class MemberAccess : ATypeNameExpression
9559 protected Expression expr;
9561 public MemberAccess (Expression expr, string id)
9562 : base (id, expr.Location)
9567 public MemberAccess (Expression expr, string identifier, Location loc)
9568 : base (identifier, loc)
9573 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9574 : base (identifier, args, loc)
9579 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9580 : base (identifier, arity, loc)
9585 public Expression LeftExpression {
9591 public override Location StartLocation {
9593 return expr == null ? loc : expr.StartLocation;
9597 protected override Expression DoResolve (ResolveContext rc)
9599 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
9601 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9606 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9608 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9610 if (e is TypeExpr) {
9611 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9616 e = e.ResolveLValue (rc, rhs);
9621 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9623 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9624 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9626 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9629 public override bool HasConditionalAccess ()
9631 return LeftExpression.HasConditionalAccess ();
9634 public static bool IsValidDotExpression (TypeSpec type)
9636 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9637 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9639 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9642 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9644 var sn = expr as SimpleName;
9645 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9648 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9651 // Resolve expression which does have type set as we need expression type
9652 // with disable flow analysis as we don't know whether left side expression
9653 // is used as variable or type
9655 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9656 expr = expr.Resolve (rc);
9657 } else if (expr is TypeParameterExpr) {
9658 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9662 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
9663 expr = expr.Resolve (rc, flags);
9670 var ns = expr as NamespaceExpression;
9672 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9674 if (retval == null) {
9675 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9680 if (HasTypeArguments)
9681 return new GenericTypeExpr (retval.Type, targs, loc);
9683 targs.Resolve (rc, false);
9690 TypeSpec expr_type = expr.Type;
9691 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9692 me = expr as MemberExpr;
9694 me.ResolveInstanceExpression (rc, null);
9696 Arguments args = new Arguments (1);
9697 args.Add (new Argument (expr));
9698 return new DynamicMemberBinder (Name, args, loc);
9701 var cma = this as ConditionalMemberAccess;
9703 if (!IsNullPropagatingValid (expr.Type)) {
9704 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9708 if (expr_type.IsNullableType) {
9709 expr = Nullable.Unwrap.Create (expr, true).Resolve (rc);
9710 expr_type = expr.Type;
9714 if (!IsValidDotExpression (expr_type)) {
9715 Error_OperatorCannotBeApplied (rc, expr_type);
9719 var lookup_arity = Arity;
9720 bool errorMode = false;
9721 Expression member_lookup;
9723 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9724 if (member_lookup == null) {
9726 // Try to look for extension method when member lookup failed
9728 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9729 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9730 if (methods != null) {
9731 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9732 if (HasTypeArguments) {
9733 if (!targs.Resolve (rc, false))
9736 emg.SetTypeArguments (rc, targs);
9740 emg.ConditionalAccess = true;
9742 // TODO: it should really skip the checks bellow
9743 return emg.Resolve (rc);
9749 if (member_lookup == null) {
9750 var dep = expr_type.GetMissingDependencies ();
9752 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9753 } else if (expr is TypeExpr) {
9754 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9756 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9762 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9763 // Leave it to overload resolution to report correct error
9764 } else if (!(member_lookup is TypeExpr)) {
9765 // TODO: rc.SymbolRelatedToPreviousError
9766 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9771 if (member_lookup != null)
9775 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9779 TypeExpr texpr = member_lookup as TypeExpr;
9780 if (texpr != null) {
9781 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9782 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9783 Name, texpr.GetSignatureForError ());
9786 if (!texpr.Type.IsAccessible (rc)) {
9787 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9788 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9792 if (HasTypeArguments) {
9793 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9796 return member_lookup;
9799 me = member_lookup as MemberExpr;
9801 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9806 me.ConditionalAccess = true;
9809 me = me.ResolveMemberAccess (rc, expr, sn);
9812 if (!targs.Resolve (rc, false))
9815 me.SetTypeArguments (rc, targs);
9821 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9823 FullNamedExpression fexpr = expr as FullNamedExpression;
9824 if (fexpr == null) {
9825 expr.ResolveAsType (rc);
9829 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9831 if (expr_resolved == null)
9834 var ns = expr_resolved as NamespaceExpression;
9836 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9838 if (retval == null) {
9839 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9840 } else if (Arity > 0) {
9841 if (HasTypeArguments) {
9842 retval = new GenericTypeExpr (retval.Type, targs, loc);
9843 if (retval.ResolveAsType (rc) == null)
9846 targs.Resolve (rc, allowUnboundTypeArguments);
9848 retval = new GenericOpenTypeExpr (retval.Type, loc);
9855 var tnew_expr = expr_resolved.ResolveAsType (rc);
9856 if (tnew_expr == null)
9859 TypeSpec expr_type = tnew_expr;
9860 if (TypeManager.IsGenericParameter (expr_type)) {
9861 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9862 tnew_expr.GetSignatureForError ());
9866 var qam = this as QualifiedAliasMember;
9868 rc.Module.Compiler.Report.Error (431, loc,
9869 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9874 TypeSpec nested = null;
9875 while (expr_type != null) {
9876 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9877 if (nested == null) {
9878 if (expr_type == tnew_expr) {
9879 Error_IdentifierNotFound (rc, expr_type);
9883 expr_type = tnew_expr;
9884 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9885 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9889 if (nested.IsAccessible (rc))
9893 // Keep looking after inaccessible candidate but only if
9894 // we are not in same context as the definition itself
9896 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9899 expr_type = expr_type.BaseType;
9904 if (HasTypeArguments) {
9905 texpr = new GenericTypeExpr (nested, targs, loc);
9907 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9909 texpr = new GenericOpenTypeExpr (nested, loc);
9911 } else if (expr_resolved is GenericOpenTypeExpr) {
9912 texpr = new GenericOpenTypeExpr (nested, loc);
9914 texpr = new TypeExpression (nested, loc);
9917 if (texpr.ResolveAsType (rc) == null)
9923 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9925 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9927 if (nested != null) {
9928 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9932 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9933 if (any_other_member != null) {
9934 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9938 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9939 Name, expr_type.GetSignatureForError ());
9942 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9944 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9947 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9949 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9950 ec.Report.SymbolRelatedToPreviousError (type);
9952 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9954 // a using directive or an assembly reference
9956 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9958 missing = "an assembly reference";
9961 ec.Report.Error (1061, loc,
9962 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9963 type.GetSignatureForError (), name, missing);
9967 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9970 public override string GetSignatureForError ()
9972 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9975 protected override void CloneTo (CloneContext clonectx, Expression t)
9977 MemberAccess target = (MemberAccess) t;
9979 target.expr = expr.Clone (clonectx);
9982 public override object Accept (StructuralVisitor visitor)
9984 return visitor.Visit (this);
9988 public class ConditionalMemberAccess : MemberAccess
9990 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9991 : base (expr, identifier, args, loc)
9995 public override bool HasConditionalAccess ()
10002 /// Implements checked expressions
10004 public class CheckedExpr : Expression {
10006 public Expression Expr;
10008 public CheckedExpr (Expression e, Location l)
10014 public override bool ContainsEmitWithAwait ()
10016 return Expr.ContainsEmitWithAwait ();
10019 public override Expression CreateExpressionTree (ResolveContext ec)
10021 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10022 return Expr.CreateExpressionTree (ec);
10025 protected override Expression DoResolve (ResolveContext ec)
10027 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10028 Expr = Expr.Resolve (ec);
10033 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10036 eclass = Expr.eclass;
10041 public override void Emit (EmitContext ec)
10043 using (ec.With (EmitContext.Options.CheckedScope, true))
10047 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10049 using (ec.With (EmitContext.Options.CheckedScope, true))
10050 Expr.EmitBranchable (ec, target, on_true);
10053 public override void FlowAnalysis (FlowAnalysisContext fc)
10055 Expr.FlowAnalysis (fc);
10058 public override SLE.Expression MakeExpression (BuilderContext ctx)
10060 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10061 return Expr.MakeExpression (ctx);
10065 protected override void CloneTo (CloneContext clonectx, Expression t)
10067 CheckedExpr target = (CheckedExpr) t;
10069 target.Expr = Expr.Clone (clonectx);
10072 public override object Accept (StructuralVisitor visitor)
10074 return visitor.Visit (this);
10079 /// Implements the unchecked expression
10081 public class UnCheckedExpr : Expression {
10083 public Expression Expr;
10085 public UnCheckedExpr (Expression e, Location l)
10091 public override bool ContainsEmitWithAwait ()
10093 return Expr.ContainsEmitWithAwait ();
10096 public override Expression CreateExpressionTree (ResolveContext ec)
10098 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10099 return Expr.CreateExpressionTree (ec);
10102 protected override Expression DoResolve (ResolveContext ec)
10104 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10105 Expr = Expr.Resolve (ec);
10110 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10113 eclass = Expr.eclass;
10118 public override void Emit (EmitContext ec)
10120 using (ec.With (EmitContext.Options.CheckedScope, false))
10124 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10126 using (ec.With (EmitContext.Options.CheckedScope, false))
10127 Expr.EmitBranchable (ec, target, on_true);
10130 public override void FlowAnalysis (FlowAnalysisContext fc)
10132 Expr.FlowAnalysis (fc);
10135 protected override void CloneTo (CloneContext clonectx, Expression t)
10137 UnCheckedExpr target = (UnCheckedExpr) t;
10139 target.Expr = Expr.Clone (clonectx);
10142 public override object Accept (StructuralVisitor visitor)
10144 return visitor.Visit (this);
10149 /// An Element Access expression.
10151 /// During semantic analysis these are transformed into
10152 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10154 public class ElementAccess : Expression
10156 public Arguments Arguments;
10157 public Expression Expr;
10159 public ElementAccess (Expression e, Arguments args, Location loc)
10163 this.Arguments = args;
10166 public bool ConditionalAccess { get; set; }
10168 public override Location StartLocation {
10170 return Expr.StartLocation;
10174 public override bool ContainsEmitWithAwait ()
10176 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10180 // We perform some simple tests, and then to "split" the emit and store
10181 // code we create an instance of a different class, and return that.
10183 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10185 Expr = Expr.Resolve (ec);
10191 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10192 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10197 return new ArrayAccess (this, loc) {
10198 ConditionalAccess = ConditionalAccess,
10199 ConditionalAccessReceiver = conditionalAccessReceiver
10202 if (type.IsPointer)
10203 return Expr.MakePointerAccess (ec, type, Arguments);
10205 FieldExpr fe = Expr as FieldExpr;
10207 var ff = fe.Spec as FixedFieldSpec;
10209 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10213 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10214 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10215 var indexer = new IndexerExpr (indexers, type, this) {
10216 ConditionalAccess = ConditionalAccess
10219 if (conditionalAccessReceiver)
10220 indexer.SetConditionalAccessReceiver ();
10225 Error_CannotApplyIndexing (ec, type, loc);
10230 public override Expression CreateExpressionTree (ResolveContext ec)
10232 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10233 Expr.CreateExpressionTree (ec));
10235 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10238 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10240 if (type != InternalType.ErrorType) {
10241 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10242 type.GetSignatureForError ());
10246 public override bool HasConditionalAccess ()
10248 return ConditionalAccess || Expr.HasConditionalAccess ();
10251 protected override Expression DoResolve (ResolveContext rc)
10254 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
10255 if (HasConditionalAccess ()) {
10256 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
10257 expr = CreateAccessExpression (rc, true);
10261 return expr.Resolve (rc);
10266 expr = CreateAccessExpression (rc, false);
10270 return expr.Resolve (rc);
10273 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10275 var res = CreateAccessExpression (ec, false);
10279 return res.ResolveLValue (ec, rhs);
10282 public override void Emit (EmitContext ec)
10284 throw new Exception ("Should never be reached");
10287 public override void FlowAnalysis (FlowAnalysisContext fc)
10289 Expr.FlowAnalysis (fc);
10291 if (ConditionalAccess)
10292 fc.BranchConditionalAccessDefiniteAssignment ();
10294 Arguments.FlowAnalysis (fc);
10297 public override string GetSignatureForError ()
10299 return Expr.GetSignatureForError ();
10302 protected override void CloneTo (CloneContext clonectx, Expression t)
10304 ElementAccess target = (ElementAccess) t;
10306 target.Expr = Expr.Clone (clonectx);
10307 if (Arguments != null)
10308 target.Arguments = Arguments.Clone (clonectx);
10311 public override object Accept (StructuralVisitor visitor)
10313 return visitor.Visit (this);
10318 /// Implements array access
10320 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10322 // Points to our "data" repository
10326 LocalTemporary temp;
10328 bool? has_await_args;
10330 public ArrayAccess (ElementAccess ea_data, Location l)
10336 public bool ConditionalAccess { get; set; }
10338 public bool ConditionalAccessReceiver { get; set; }
10340 public void AddressOf (EmitContext ec, AddressOp mode)
10342 var ac = (ArrayContainer) ea.Expr.Type;
10344 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10345 LoadInstanceAndArguments (ec, false, true);
10348 LoadInstanceAndArguments (ec, false, false);
10350 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10351 ec.Emit (OpCodes.Readonly);
10353 ec.EmitArrayAddress (ac);
10356 public override Expression CreateExpressionTree (ResolveContext ec)
10358 if (ConditionalAccess)
10359 Error_NullShortCircuitInsideExpressionTree (ec);
10361 return ea.CreateExpressionTree (ec);
10364 public override bool ContainsEmitWithAwait ()
10366 return ea.ContainsEmitWithAwait ();
10369 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10371 if (ConditionalAccess)
10372 Error_NullPropagatingLValue (ec);
10374 return DoResolve (ec);
10377 protected override Expression DoResolve (ResolveContext ec)
10379 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10381 ea.Arguments.Resolve (ec, out dynamic);
10383 var ac = ea.Expr.Type as ArrayContainer;
10384 int rank = ea.Arguments.Count;
10385 if (ac.Rank != rank) {
10386 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10387 rank.ToString (), ac.Rank.ToString ());
10392 if (type.IsPointer && !ec.IsUnsafe) {
10393 UnsafeError (ec, ea.Location);
10396 if (ConditionalAccessReceiver)
10397 type = LiftMemberType (ec, type);
10399 foreach (Argument a in ea.Arguments) {
10400 var na = a as NamedArgument;
10402 ElementAccess.Error_NamedArgument (na, ec.Report);
10404 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10407 eclass = ExprClass.Variable;
10412 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10414 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10417 public override void FlowAnalysis (FlowAnalysisContext fc)
10419 ea.FlowAnalysis (fc);
10422 public override bool HasConditionalAccess ()
10424 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10428 // Load the array arguments into the stack.
10430 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10432 if (prepareAwait) {
10433 ea.Expr = ea.Expr.EmitToField (ec);
10435 var ie = new InstanceEmitter (ea.Expr, false);
10436 ie.Emit (ec, ConditionalAccess);
10438 if (duplicateArguments) {
10439 ec.Emit (OpCodes.Dup);
10441 var copy = new LocalTemporary (ea.Expr.Type);
10447 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10448 if (dup_args != null)
10449 ea.Arguments = dup_args;
10452 public void Emit (EmitContext ec, bool leave_copy)
10455 ec.EmitLoadFromPtr (type);
10457 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10458 LoadInstanceAndArguments (ec, false, true);
10461 if (ConditionalAccessReceiver)
10462 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10464 var ac = (ArrayContainer) ea.Expr.Type;
10465 LoadInstanceAndArguments (ec, false, false);
10466 ec.EmitArrayLoad (ac);
10468 if (ConditionalAccessReceiver)
10469 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10473 ec.Emit (OpCodes.Dup);
10474 temp = new LocalTemporary (this.type);
10479 public override void Emit (EmitContext ec)
10484 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10486 var ac = (ArrayContainer) ea.Expr.Type;
10487 TypeSpec t = source.Type;
10489 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10492 // When we are dealing with a struct, get the address of it to avoid value copy
10493 // Same cannot be done for reference type because array covariance and the
10494 // check in ldelema requires to specify the type of array element stored at the index
10496 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10497 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10499 if (has_await_args.Value) {
10500 if (source.ContainsEmitWithAwait ()) {
10501 source = source.EmitToField (ec);
10502 isCompound = false;
10506 LoadInstanceAndArguments (ec, isCompound, false);
10511 ec.EmitArrayAddress (ac);
10514 ec.Emit (OpCodes.Dup);
10518 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10520 if (has_await_args.Value) {
10521 if (source.ContainsEmitWithAwait ())
10522 source = source.EmitToField (ec);
10524 LoadInstanceAndArguments (ec, false, false);
10531 var lt = ea.Expr as LocalTemporary;
10537 ec.Emit (OpCodes.Dup);
10538 temp = new LocalTemporary (this.type);
10543 ec.EmitStoreFromPtr (t);
10545 ec.EmitArrayStore (ac);
10548 if (temp != null) {
10554 public override Expression EmitToField (EmitContext ec)
10557 // Have to be specialized for arrays to get access to
10558 // underlying element. Instead of another result copy we
10559 // need direct access to element
10563 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10565 ea.Expr = ea.Expr.EmitToField (ec);
10566 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10570 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10572 #if NET_4_0 || MOBILE_DYNAMIC
10573 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10575 throw new NotImplementedException ();
10579 public override SLE.Expression MakeExpression (BuilderContext ctx)
10581 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10584 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10586 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10587 return Arguments.MakeExpression (ea.Arguments, ctx);
10593 // Indexer access expression
10595 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10597 IList<MemberSpec> indexers;
10598 Arguments arguments;
10599 TypeSpec queried_type;
10601 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10602 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10606 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10609 this.indexers = indexers;
10610 this.queried_type = queriedType;
10611 this.InstanceExpression = instance;
10612 this.arguments = args;
10617 protected override Arguments Arguments {
10626 protected override TypeSpec DeclaringType {
10628 return best_candidate.DeclaringType;
10632 public override bool IsInstance {
10638 public override bool IsStatic {
10644 public override string KindName {
10645 get { return "indexer"; }
10648 public override string Name {
10656 public override bool ContainsEmitWithAwait ()
10658 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10661 public override Expression CreateExpressionTree (ResolveContext ec)
10663 if (ConditionalAccess) {
10664 Error_NullShortCircuitInsideExpressionTree (ec);
10667 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10668 InstanceExpression.CreateExpressionTree (ec),
10669 new TypeOfMethod (Getter, loc));
10671 return CreateExpressionFactoryCall (ec, "Call", args);
10674 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10676 LocalTemporary await_source_arg = null;
10679 emitting_compound_assignment = true;
10680 if (source is DynamicExpressionStatement) {
10685 emitting_compound_assignment = false;
10687 if (has_await_arguments) {
10688 await_source_arg = new LocalTemporary (Type);
10689 await_source_arg.Store (ec);
10691 arguments.Add (new Argument (await_source_arg));
10694 temp = await_source_arg;
10697 has_await_arguments = false;
10702 ec.Emit (OpCodes.Dup);
10703 temp = new LocalTemporary (Type);
10709 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10710 source = source.EmitToField (ec);
10712 temp = new LocalTemporary (Type);
10719 arguments.Add (new Argument (source));
10722 var call = new CallEmitter ();
10723 call.InstanceExpression = InstanceExpression;
10724 if (arguments == null)
10725 call.InstanceExpressionOnStack = true;
10727 call.Emit (ec, Setter, arguments, loc);
10729 if (temp != null) {
10732 } else if (leave_copy) {
10736 if (await_source_arg != null) {
10737 await_source_arg.Release (ec);
10741 public override void FlowAnalysis (FlowAnalysisContext fc)
10743 base.FlowAnalysis (fc);
10744 arguments.FlowAnalysis (fc);
10746 if (conditional_access_receiver)
10747 fc.ConditionalAccessEnd ();
10750 public override string GetSignatureForError ()
10752 return best_candidate.GetSignatureForError ();
10755 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10758 throw new NotSupportedException ();
10760 var value = new[] { source.MakeExpression (ctx) };
10761 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10762 #if NET_4_0 || MOBILE_DYNAMIC
10763 return SLE.Expression.Block (
10764 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10767 return args.First ();
10772 public override SLE.Expression MakeExpression (BuilderContext ctx)
10775 return base.MakeExpression (ctx);
10777 var args = Arguments.MakeExpression (arguments, ctx);
10778 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10782 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10784 if (best_candidate != null)
10787 eclass = ExprClass.IndexerAccess;
10790 arguments.Resolve (rc, out dynamic);
10792 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10795 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10796 res.BaseMembersProvider = this;
10797 res.InstanceQualifier = this;
10799 // TODO: Do I need 2 argument sets?
10800 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10801 if (best_candidate != null)
10802 type = res.BestCandidateReturnType;
10803 else if (!res.BestCandidateIsDynamic)
10808 // It has dynamic arguments
10811 Arguments args = new Arguments (arguments.Count + 1);
10813 rc.Report.Error (1972, loc,
10814 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10816 args.Add (new Argument (InstanceExpression));
10818 args.AddRange (arguments);
10820 best_candidate = null;
10821 return new DynamicIndexBinder (args, loc);
10825 // Try to avoid resolving left expression again
10827 if (right_side != null)
10828 ResolveInstanceExpression (rc, right_side);
10833 protected override void CloneTo (CloneContext clonectx, Expression t)
10835 IndexerExpr target = (IndexerExpr) t;
10837 if (arguments != null)
10838 target.arguments = arguments.Clone (clonectx);
10841 public void SetConditionalAccessReceiver ()
10843 conditional_access_receiver = true;
10846 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10848 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10851 #region IBaseMembersProvider Members
10853 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10855 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10858 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10860 if (queried_type == member.DeclaringType)
10863 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10864 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10867 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10876 // A base access expression
10878 public class BaseThis : This
10880 public BaseThis (Location loc)
10885 public BaseThis (TypeSpec type, Location loc)
10889 eclass = ExprClass.Variable;
10894 public override string Name {
10902 public override Expression CreateExpressionTree (ResolveContext ec)
10904 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10905 return base.CreateExpressionTree (ec);
10908 public override void Emit (EmitContext ec)
10912 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10913 var context_type = ec.CurrentType;
10914 ec.Emit (OpCodes.Ldobj, context_type);
10915 ec.Emit (OpCodes.Box, context_type);
10919 protected override void Error_ThisNotAvailable (ResolveContext ec)
10922 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10924 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10928 public override void ResolveBase (ResolveContext ec)
10930 base.ResolveBase (ec);
10931 type = ec.CurrentType.BaseType;
10934 public override object Accept (StructuralVisitor visitor)
10936 return visitor.Visit (this);
10941 /// This class exists solely to pass the Type around and to be a dummy
10942 /// that can be passed to the conversion functions (this is used by
10943 /// foreach implementation to typecast the object return value from
10944 /// get_Current into the proper type. All code has been generated and
10945 /// we only care about the side effect conversions to be performed
10947 /// This is also now used as a placeholder where a no-action expression
10948 /// is needed (the `New' class).
10950 public class EmptyExpression : Expression
10952 sealed class OutAccessExpression : EmptyExpression
10954 public OutAccessExpression (TypeSpec t)
10959 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10961 rc.Report.Error (206, right_side.Location,
10962 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
10968 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
10969 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
10970 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
10971 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
10972 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
10973 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
10974 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
10975 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
10977 public EmptyExpression (TypeSpec t)
10980 eclass = ExprClass.Value;
10981 loc = Location.Null;
10984 protected override void CloneTo (CloneContext clonectx, Expression target)
10988 public override bool ContainsEmitWithAwait ()
10993 public override Expression CreateExpressionTree (ResolveContext ec)
10995 throw new NotSupportedException ("ET");
10998 protected override Expression DoResolve (ResolveContext ec)
11003 public override void Emit (EmitContext ec)
11005 // nothing, as we only exist to not do anything.
11008 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11012 public override void EmitSideEffect (EmitContext ec)
11016 public override object Accept (StructuralVisitor visitor)
11018 return visitor.Visit (this);
11022 sealed class EmptyAwaitExpression : EmptyExpression
11024 public EmptyAwaitExpression (TypeSpec type)
11029 public override bool ContainsEmitWithAwait ()
11036 // Empty statement expression
11038 public sealed class EmptyExpressionStatement : ExpressionStatement
11040 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11042 private EmptyExpressionStatement ()
11044 loc = Location.Null;
11047 public override bool ContainsEmitWithAwait ()
11052 public override Expression CreateExpressionTree (ResolveContext ec)
11057 public override void EmitStatement (EmitContext ec)
11062 protected override Expression DoResolve (ResolveContext ec)
11064 eclass = ExprClass.Value;
11065 type = ec.BuiltinTypes.Object;
11069 public override void Emit (EmitContext ec)
11074 public override object Accept (StructuralVisitor visitor)
11076 return visitor.Visit (this);
11080 public class ErrorExpression : EmptyExpression
11082 public static readonly ErrorExpression Instance = new ErrorExpression ();
11084 private ErrorExpression ()
11085 : base (InternalType.ErrorType)
11089 public override Expression CreateExpressionTree (ResolveContext ec)
11094 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11099 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11103 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11107 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11111 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11115 public override object Accept (StructuralVisitor visitor)
11117 return visitor.Visit (this);
11121 public class UserCast : Expression {
11125 public UserCast (MethodSpec method, Expression source, Location l)
11127 if (source == null)
11128 throw new ArgumentNullException ("source");
11130 this.method = method;
11131 this.source = source;
11132 type = method.ReturnType;
11136 public Expression Source {
11145 public override bool ContainsEmitWithAwait ()
11147 return source.ContainsEmitWithAwait ();
11150 public override Expression CreateExpressionTree (ResolveContext ec)
11152 Arguments args = new Arguments (3);
11153 args.Add (new Argument (source.CreateExpressionTree (ec)));
11154 args.Add (new Argument (new TypeOf (type, loc)));
11155 args.Add (new Argument (new TypeOfMethod (method, loc)));
11156 return CreateExpressionFactoryCall (ec, "Convert", args);
11159 protected override Expression DoResolve (ResolveContext ec)
11161 ObsoleteAttribute oa = method.GetAttributeObsolete ();
11163 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
11165 eclass = ExprClass.Value;
11169 public override void Emit (EmitContext ec)
11172 ec.MarkCallEntry (loc);
11173 ec.Emit (OpCodes.Call, method);
11176 public override void FlowAnalysis (FlowAnalysisContext fc)
11178 source.FlowAnalysis (fc);
11181 public override string GetSignatureForError ()
11183 return TypeManager.CSharpSignature (method);
11186 public override SLE.Expression MakeExpression (BuilderContext ctx)
11189 return base.MakeExpression (ctx);
11191 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11197 // Holds additional type specifiers like ?, *, []
11199 public class ComposedTypeSpecifier
11201 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11203 public readonly int Dimension;
11204 public readonly Location Location;
11206 public ComposedTypeSpecifier (int specifier, Location loc)
11208 this.Dimension = specifier;
11209 this.Location = loc;
11213 public bool IsNullable {
11215 return Dimension == -1;
11219 public bool IsPointer {
11221 return Dimension == -2;
11225 public ComposedTypeSpecifier Next { get; set; }
11229 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11231 return new ComposedTypeSpecifier (dimension, loc);
11234 public static ComposedTypeSpecifier CreateNullable (Location loc)
11236 return new ComposedTypeSpecifier (-1, loc);
11239 public static ComposedTypeSpecifier CreatePointer (Location loc)
11241 return new ComposedTypeSpecifier (-2, loc);
11244 public string GetSignatureForError ()
11249 ArrayContainer.GetPostfixSignature (Dimension);
11251 return Next != null ? s + Next.GetSignatureForError () : s;
11256 // This class is used to "construct" the type during a typecast
11257 // operation. Since the Type.GetType class in .NET can parse
11258 // the type specification, we just use this to construct the type
11259 // one bit at a time.
11261 public class ComposedCast : TypeExpr {
11262 FullNamedExpression left;
11263 ComposedTypeSpecifier spec;
11265 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11268 throw new ArgumentNullException ("spec");
11272 this.loc = left.Location;
11275 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11277 type = left.ResolveAsType (ec);
11281 eclass = ExprClass.Type;
11283 var single_spec = spec;
11285 if (single_spec.IsNullable) {
11286 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11290 single_spec = single_spec.Next;
11291 } else if (single_spec.IsPointer) {
11292 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11295 if (!ec.IsUnsafe) {
11296 UnsafeError (ec.Module.Compiler.Report, loc);
11300 type = PointerContainer.MakeType (ec.Module, type);
11301 single_spec = single_spec.Next;
11302 } while (single_spec != null && single_spec.IsPointer);
11305 if (single_spec != null && single_spec.Dimension > 0) {
11306 if (type.IsSpecialRuntimeType) {
11307 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11308 } else if (type.IsStatic) {
11309 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11310 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11311 type.GetSignatureForError ());
11313 MakeArray (ec.Module, single_spec);
11320 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11322 if (spec.Next != null)
11323 MakeArray (module, spec.Next);
11325 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11328 public override string GetSignatureForError ()
11330 return left.GetSignatureForError () + spec.GetSignatureForError ();
11333 public override object Accept (StructuralVisitor visitor)
11335 return visitor.Visit (this);
11339 class FixedBufferPtr : Expression
11341 readonly Expression array;
11343 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11345 this.type = array_type;
11346 this.array = array;
11350 public override bool ContainsEmitWithAwait ()
11352 throw new NotImplementedException ();
11355 public override Expression CreateExpressionTree (ResolveContext ec)
11357 Error_PointerInsideExpressionTree (ec);
11361 public override void Emit(EmitContext ec)
11366 protected override Expression DoResolve (ResolveContext ec)
11368 type = PointerContainer.MakeType (ec.Module, type);
11369 eclass = ExprClass.Value;
11376 // This class is used to represent the address of an array, used
11377 // only by the Fixed statement, this generates "&a [0]" construct
11378 // for fixed (char *pa = a)
11380 class ArrayPtr : FixedBufferPtr
11382 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11383 base (array, array_type, l)
11387 public override void Emit (EmitContext ec)
11392 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11397 // Encapsulates a conversion rules required for array indexes
11399 public class ArrayIndexCast : TypeCast
11401 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11402 : base (expr, returnType)
11404 if (expr.Type == returnType) // int -> int
11405 throw new ArgumentException ("unnecessary array index conversion");
11408 public override Expression CreateExpressionTree (ResolveContext ec)
11410 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11411 return base.CreateExpressionTree (ec);
11415 public override void Emit (EmitContext ec)
11419 switch (child.Type.BuiltinType) {
11420 case BuiltinTypeSpec.Type.UInt:
11421 ec.Emit (OpCodes.Conv_U);
11423 case BuiltinTypeSpec.Type.Long:
11424 ec.Emit (OpCodes.Conv_Ovf_I);
11426 case BuiltinTypeSpec.Type.ULong:
11427 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11430 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11436 // Implements the `stackalloc' keyword
11438 public class StackAlloc : Expression {
11443 public StackAlloc (Expression type, Expression count, Location l)
11446 this.count = count;
11450 public Expression TypeExpression {
11456 public Expression CountExpression {
11462 public override bool ContainsEmitWithAwait ()
11467 public override Expression CreateExpressionTree (ResolveContext ec)
11469 throw new NotSupportedException ("ET");
11472 protected override Expression DoResolve (ResolveContext ec)
11474 count = count.Resolve (ec);
11478 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11479 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11484 Constant c = count as Constant;
11485 if (c != null && c.IsNegative) {
11486 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11489 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11490 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11493 otype = t.ResolveAsType (ec);
11497 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11500 type = PointerContainer.MakeType (ec.Module, otype);
11501 eclass = ExprClass.Value;
11506 public override void Emit (EmitContext ec)
11508 int size = BuiltinTypeSpec.GetSize (otype);
11513 ec.Emit (OpCodes.Sizeof, otype);
11517 ec.Emit (OpCodes.Mul_Ovf_Un);
11518 ec.Emit (OpCodes.Localloc);
11521 protected override void CloneTo (CloneContext clonectx, Expression t)
11523 StackAlloc target = (StackAlloc) t;
11524 target.count = count.Clone (clonectx);
11525 target.t = t.Clone (clonectx);
11528 public override object Accept (StructuralVisitor visitor)
11530 return visitor.Visit (this);
11535 // An object initializer expression
11537 public class ElementInitializer : Assign
11539 public readonly string Name;
11541 public ElementInitializer (string name, Expression initializer, Location loc)
11542 : base (null, initializer, loc)
11547 public bool IsDictionaryInitializer {
11549 return Name == null;
11553 protected override void CloneTo (CloneContext clonectx, Expression t)
11555 ElementInitializer target = (ElementInitializer) t;
11556 target.source = source.Clone (clonectx);
11559 public override Expression CreateExpressionTree (ResolveContext ec)
11561 Arguments args = new Arguments (2);
11562 FieldExpr fe = target as FieldExpr;
11564 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11566 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11569 Expression arg_expr;
11570 var cinit = source as CollectionOrObjectInitializers;
11571 if (cinit == null) {
11573 arg_expr = source.CreateExpressionTree (ec);
11575 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11576 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11579 args.Add (new Argument (arg_expr));
11580 return CreateExpressionFactoryCall (ec, mname, args);
11583 protected override Expression DoResolve (ResolveContext ec)
11585 if (source == null)
11586 return EmptyExpressionStatement.Instance;
11588 if (!ResolveElement (ec))
11591 if (source is CollectionOrObjectInitializers) {
11592 Expression previous = ec.CurrentInitializerVariable;
11593 ec.CurrentInitializerVariable = target;
11594 source = source.Resolve (ec);
11595 ec.CurrentInitializerVariable = previous;
11596 if (source == null)
11599 eclass = source.eclass;
11600 type = source.Type;
11604 return base.DoResolve (ec);
11607 public override void EmitStatement (EmitContext ec)
11609 if (source is CollectionOrObjectInitializers)
11612 base.EmitStatement (ec);
11615 protected virtual bool ResolveElement (ResolveContext rc)
11617 var t = rc.CurrentInitializerVariable.Type;
11618 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11619 Arguments args = new Arguments (1);
11620 args.Add (new Argument (rc.CurrentInitializerVariable));
11621 target = new DynamicMemberBinder (Name, args, loc);
11624 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11625 if (member == null) {
11626 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11628 if (member != null) {
11629 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11630 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11635 if (member == null) {
11636 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11640 var me = member as MemberExpr;
11641 if (me is EventExpr) {
11642 me = me.ResolveMemberAccess (rc, null, null);
11643 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11644 rc.Report.Error (1913, loc,
11645 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11646 member.GetSignatureForError ());
11652 rc.Report.Error (1914, loc,
11653 "Static field or property `{0}' cannot be assigned in an object initializer",
11654 me.GetSignatureForError ());
11658 me.InstanceExpression = rc.CurrentInitializerVariable;
11666 // A collection initializer expression
11668 class CollectionElementInitializer : Invocation
11670 public class ElementInitializerArgument : Argument
11672 public ElementInitializerArgument (Expression e)
11678 sealed class AddMemberAccess : MemberAccess
11680 public AddMemberAccess (Expression expr, Location loc)
11681 : base (expr, "Add", loc)
11685 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11687 if (TypeManager.HasElementType (type))
11690 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11694 public CollectionElementInitializer (Expression argument)
11695 : base (null, new Arguments (1))
11697 base.arguments.Add (new ElementInitializerArgument (argument));
11698 this.loc = argument.Location;
11701 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11702 : base (null, new Arguments (arguments.Count))
11704 foreach (Expression e in arguments)
11705 base.arguments.Add (new ElementInitializerArgument (e));
11710 public CollectionElementInitializer (Location loc)
11711 : base (null, null)
11716 public override Expression CreateExpressionTree (ResolveContext ec)
11718 Arguments args = new Arguments (2);
11719 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11721 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11722 foreach (Argument a in arguments)
11723 expr_initializers.Add (a.CreateExpressionTree (ec));
11725 args.Add (new Argument (new ArrayCreation (
11726 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11727 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11730 protected override void CloneTo (CloneContext clonectx, Expression t)
11732 CollectionElementInitializer target = (CollectionElementInitializer) t;
11733 if (arguments != null)
11734 target.arguments = arguments.Clone (clonectx);
11737 protected override Expression DoResolve (ResolveContext ec)
11739 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11741 return base.DoResolve (ec);
11745 class DictionaryElementInitializer : ElementInitializer
11747 readonly Arguments args;
11749 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11750 : base (null, initializer, loc)
11752 this.args = arguments;
11755 public override Expression CreateExpressionTree (ResolveContext ec)
11757 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11761 protected override bool ResolveElement (ResolveContext rc)
11763 var init = rc.CurrentInitializerVariable;
11764 var type = init.Type;
11766 if (type.IsArray) {
11767 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11771 if (type.IsPointer) {
11772 target = init.MakePointerAccess (rc, type, args);
11776 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11777 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11778 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11782 target = new IndexerExpr (indexers, type, init, args, loc).Resolve (rc);
11788 // A block of object or collection initializers
11790 public class CollectionOrObjectInitializers : ExpressionStatement
11792 IList<Expression> initializers;
11793 bool is_collection_initialization;
11795 public CollectionOrObjectInitializers (Location loc)
11796 : this (new Expression[0], loc)
11800 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11802 this.initializers = initializers;
11806 public IList<Expression> Initializers {
11808 return initializers;
11812 public bool IsEmpty {
11814 return initializers.Count == 0;
11818 public bool IsCollectionInitializer {
11820 return is_collection_initialization;
11824 protected override void CloneTo (CloneContext clonectx, Expression target)
11826 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11828 t.initializers = new List<Expression> (initializers.Count);
11829 foreach (var e in initializers)
11830 t.initializers.Add (e.Clone (clonectx));
11833 public override bool ContainsEmitWithAwait ()
11835 foreach (var e in initializers) {
11836 if (e.ContainsEmitWithAwait ())
11843 public override Expression CreateExpressionTree (ResolveContext ec)
11845 return CreateExpressionTree (ec, false);
11848 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11850 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11851 foreach (Expression e in initializers) {
11852 Expression expr = e.CreateExpressionTree (ec);
11854 expr_initializers.Add (expr);
11858 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11860 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11863 protected override Expression DoResolve (ResolveContext ec)
11865 List<string> element_names = null;
11866 for (int i = 0; i < initializers.Count; ++i) {
11867 Expression initializer = initializers [i];
11868 ElementInitializer element_initializer = initializer as ElementInitializer;
11871 if (element_initializer != null) {
11872 element_names = new List<string> (initializers.Count);
11873 if (!element_initializer.IsDictionaryInitializer)
11874 element_names.Add (element_initializer.Name);
11875 } else if (initializer is CompletingExpression) {
11876 initializer.Resolve (ec);
11877 throw new InternalErrorException ("This line should never be reached");
11879 var t = ec.CurrentInitializerVariable.Type;
11880 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11881 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11882 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11883 "object initializer because type `{1}' does not implement `{2}' interface",
11884 ec.CurrentInitializerVariable.GetSignatureForError (),
11885 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11886 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11889 is_collection_initialization = true;
11892 if (is_collection_initialization != (element_initializer == null)) {
11893 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11894 is_collection_initialization ? "collection initializer" : "object initializer");
11898 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11899 if (element_names.Contains (element_initializer.Name)) {
11900 ec.Report.Error (1912, element_initializer.Location,
11901 "An object initializer includes more than one member `{0}' initialization",
11902 element_initializer.Name);
11904 element_names.Add (element_initializer.Name);
11909 Expression e = initializer.Resolve (ec);
11910 if (e == EmptyExpressionStatement.Instance)
11911 initializers.RemoveAt (i--);
11913 initializers [i] = e;
11916 type = ec.CurrentInitializerVariable.Type;
11917 if (is_collection_initialization) {
11918 if (TypeManager.HasElementType (type)) {
11919 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11920 type.GetSignatureForError ());
11924 eclass = ExprClass.Variable;
11928 public override void Emit (EmitContext ec)
11930 EmitStatement (ec);
11933 public override void EmitStatement (EmitContext ec)
11935 foreach (ExpressionStatement e in initializers) {
11936 // TODO: need location region
11937 ec.Mark (e.Location);
11938 e.EmitStatement (ec);
11942 public override void FlowAnalysis (FlowAnalysisContext fc)
11944 foreach (var initializer in initializers) {
11945 if (initializer != null)
11946 initializer.FlowAnalysis (fc);
11952 // New expression with element/object initializers
11954 public class NewInitialize : New
11957 // This class serves as a proxy for variable initializer target instances.
11958 // A real variable is assigned later when we resolve left side of an
11961 sealed class InitializerTargetExpression : Expression, IMemoryLocation
11963 NewInitialize new_instance;
11965 public InitializerTargetExpression (NewInitialize newInstance)
11967 this.type = newInstance.type;
11968 this.loc = newInstance.loc;
11969 this.eclass = newInstance.eclass;
11970 this.new_instance = newInstance;
11973 public override bool ContainsEmitWithAwait ()
11978 public override Expression CreateExpressionTree (ResolveContext ec)
11980 // Should not be reached
11981 throw new NotSupportedException ("ET");
11984 protected override Expression DoResolve (ResolveContext ec)
11989 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
11994 public override void Emit (EmitContext ec)
11996 Expression e = (Expression) new_instance.instance;
12000 public override Expression EmitToField (EmitContext ec)
12002 return (Expression) new_instance.instance;
12005 #region IMemoryLocation Members
12007 public void AddressOf (EmitContext ec, AddressOp mode)
12009 new_instance.instance.AddressOf (ec, mode);
12015 CollectionOrObjectInitializers initializers;
12016 IMemoryLocation instance;
12017 DynamicExpressionStatement dynamic;
12019 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12020 : base (requested_type, arguments, l)
12022 this.initializers = initializers;
12025 public CollectionOrObjectInitializers Initializers {
12027 return initializers;
12031 protected override void CloneTo (CloneContext clonectx, Expression t)
12033 base.CloneTo (clonectx, t);
12035 NewInitialize target = (NewInitialize) t;
12036 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12039 public override bool ContainsEmitWithAwait ()
12041 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12044 public override Expression CreateExpressionTree (ResolveContext ec)
12046 Arguments args = new Arguments (2);
12047 args.Add (new Argument (base.CreateExpressionTree (ec)));
12048 if (!initializers.IsEmpty)
12049 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12051 return CreateExpressionFactoryCall (ec,
12052 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12056 protected override Expression DoResolve (ResolveContext ec)
12058 Expression e = base.DoResolve (ec);
12062 if (type.IsDelegate) {
12063 ec.Report.Error (1958, Initializers.Location,
12064 "Object and collection initializers cannot be used to instantiate a delegate");
12067 Expression previous = ec.CurrentInitializerVariable;
12068 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12069 initializers.Resolve (ec);
12070 ec.CurrentInitializerVariable = previous;
12072 dynamic = e as DynamicExpressionStatement;
12073 if (dynamic != null)
12079 public override void Emit (EmitContext ec)
12081 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12082 var fe = ec.GetTemporaryField (type);
12084 if (!Emit (ec, fe))
12093 public override bool Emit (EmitContext ec, IMemoryLocation target)
12095 bool left_on_stack;
12096 if (dynamic != null) {
12098 left_on_stack = true;
12100 left_on_stack = base.Emit (ec, target);
12103 if (initializers.IsEmpty)
12104 return left_on_stack;
12106 LocalTemporary temp = null;
12108 instance = target as LocalTemporary;
12109 if (instance == null)
12110 instance = target as StackFieldExpr;
12112 if (instance == null) {
12113 if (!left_on_stack) {
12114 VariableReference vr = target as VariableReference;
12116 // FIXME: This still does not work correctly for pre-set variables
12117 if (vr != null && vr.IsRef)
12118 target.AddressOf (ec, AddressOp.Load);
12120 ((Expression) target).Emit (ec);
12121 left_on_stack = true;
12124 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12125 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
12127 temp = new LocalTemporary (type);
12132 if (left_on_stack && temp != null)
12135 initializers.Emit (ec);
12137 if (left_on_stack) {
12138 if (temp != null) {
12142 ((Expression) instance).Emit (ec);
12146 return left_on_stack;
12149 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12151 instance = base.EmitAddressOf (ec, Mode);
12153 if (!initializers.IsEmpty)
12154 initializers.Emit (ec);
12159 public override void FlowAnalysis (FlowAnalysisContext fc)
12161 base.FlowAnalysis (fc);
12162 initializers.FlowAnalysis (fc);
12165 public override object Accept (StructuralVisitor visitor)
12167 return visitor.Visit (this);
12171 public class NewAnonymousType : New
12173 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12175 List<AnonymousTypeParameter> parameters;
12176 readonly TypeContainer parent;
12177 AnonymousTypeClass anonymous_type;
12179 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12180 : base (null, null, loc)
12182 this.parameters = parameters;
12183 this.parent = parent;
12186 public List<AnonymousTypeParameter> Parameters {
12188 return this.parameters;
12192 protected override void CloneTo (CloneContext clonectx, Expression target)
12194 if (parameters == null)
12197 NewAnonymousType t = (NewAnonymousType) target;
12198 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12199 foreach (AnonymousTypeParameter atp in parameters)
12200 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12203 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12205 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12209 type = AnonymousTypeClass.Create (parent, parameters, loc);
12213 int errors = ec.Report.Errors;
12214 type.CreateContainer ();
12215 type.DefineContainer ();
12217 if ((ec.Report.Errors - errors) == 0) {
12218 parent.Module.AddAnonymousType (type);
12219 type.PrepareEmit ();
12225 public override Expression CreateExpressionTree (ResolveContext ec)
12227 if (parameters == null)
12228 return base.CreateExpressionTree (ec);
12230 var init = new ArrayInitializer (parameters.Count, loc);
12231 foreach (var m in anonymous_type.Members) {
12232 var p = m as Property;
12234 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12237 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12238 foreach (Argument a in arguments)
12239 ctor_args.Add (a.CreateExpressionTree (ec));
12241 Arguments args = new Arguments (3);
12242 args.Add (new Argument (new TypeOfMethod (method, loc)));
12243 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12244 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12246 return CreateExpressionFactoryCall (ec, "New", args);
12249 protected override Expression DoResolve (ResolveContext ec)
12251 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12252 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12256 if (parameters == null) {
12257 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12258 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12259 return base.DoResolve (ec);
12262 bool error = false;
12263 arguments = new Arguments (parameters.Count);
12264 var t_args = new TypeSpec [parameters.Count];
12265 for (int i = 0; i < parameters.Count; ++i) {
12266 Expression e = parameters [i].Resolve (ec);
12272 arguments.Add (new Argument (e));
12273 t_args [i] = e.Type;
12279 anonymous_type = CreateAnonymousType (ec, parameters);
12280 if (anonymous_type == null)
12283 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12284 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12285 eclass = ExprClass.Value;
12289 public override object Accept (StructuralVisitor visitor)
12291 return visitor.Visit (this);
12295 public class AnonymousTypeParameter : ShimExpression
12297 public readonly string Name;
12299 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12300 : base (initializer)
12306 public AnonymousTypeParameter (Parameter parameter)
12307 : base (new SimpleName (parameter.Name, parameter.Location))
12309 this.Name = parameter.Name;
12310 this.loc = parameter.Location;
12313 public override bool Equals (object o)
12315 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12316 return other != null && Name == other.Name;
12319 public override int GetHashCode ()
12321 return Name.GetHashCode ();
12324 protected override Expression DoResolve (ResolveContext ec)
12326 Expression e = expr.Resolve (ec);
12330 if (e.eclass == ExprClass.MethodGroup) {
12331 Error_InvalidInitializer (ec, e.ExprClassName);
12336 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12337 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12344 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12346 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12347 Name, initializer);
12351 public class CatchFilterExpression : BooleanExpression
12353 public CatchFilterExpression (Expression expr, Location loc)
12360 public class InterpolatedString : Expression
12362 readonly StringLiteral start, end;
12363 List<Expression> interpolations;
12364 Arguments arguments;
12366 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12368 this.start = start;
12370 this.interpolations = interpolations;
12371 loc = start.Location;
12374 protected override void CloneTo (CloneContext clonectx, Expression t)
12376 InterpolatedString target = (InterpolatedString) t;
12378 if (interpolations != null) {
12379 target.interpolations = new List<Expression> ();
12380 foreach (var interpolation in interpolations) {
12381 target.interpolations.Add (interpolation.Clone (clonectx));
12386 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12388 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12389 if (factory == null)
12392 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12393 var res = new Invocation (ma, arguments).Resolve (rc);
12394 if (res != null && res.Type != type)
12395 res = Convert.ExplicitConversion (rc, res, type, loc);
12400 public override bool ContainsEmitWithAwait ()
12402 if (interpolations == null)
12405 foreach (var expr in interpolations) {
12406 if (expr.ContainsEmitWithAwait ())
12413 public override Expression CreateExpressionTree (ResolveContext rc)
12415 var best = ResolveBestFormatOverload (rc);
12419 Expression instance = new NullLiteral (loc);
12420 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12421 return CreateExpressionFactoryCall (rc, "Call", args);
12424 protected override Expression DoResolve (ResolveContext rc)
12428 if (interpolations == null) {
12430 arguments = new Arguments (1);
12432 for (int i = 0; i < interpolations.Count; i += 2) {
12433 var ipi = (InterpolatedStringInsert)interpolations [i];
12437 arguments = new Arguments (interpolations.Count);
12439 var sb = new StringBuilder (start.Value);
12440 for (int i = 0; i < interpolations.Count; ++i) {
12442 sb.Append ('{').Append (i / 2);
12443 var isi = (InterpolatedStringInsert)interpolations [i];
12444 if (isi.Alignment != null) {
12446 var value = isi.ResolveAligment (rc);
12448 sb.Append (value.Value);
12451 if (isi.Format != null) {
12453 sb.Append (isi.Format);
12457 arguments.Add (new Argument (interpolations [i]));
12459 sb.Append (((StringLiteral)interpolations [i]).Value);
12463 sb.Append (end.Value);
12464 str = sb.ToString ();
12467 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12469 eclass = ExprClass.Value;
12470 type = rc.BuiltinTypes.String;
12474 public override void Emit (EmitContext ec)
12476 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12477 if (interpolations == null) {
12478 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12479 if (str != start.Value)
12480 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12487 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12491 var ca = new CallEmitter ();
12492 ca.Emit (ec, best, arguments, loc);
12495 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12497 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12498 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12499 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12503 public class InterpolatedStringInsert : CompositeExpression
12505 public InterpolatedStringInsert (Expression expr)
12510 public Expression Alignment { get; set; }
12511 public string Format { get; set; }
12513 protected override void CloneTo (CloneContext clonectx, Expression t)
12515 var target = (InterpolatedStringInsert)t;
12516 if (Alignment != null)
12517 target.Alignment = Alignment.Clone (clonectx);
12520 protected override Expression DoResolve (ResolveContext rc)
12522 var expr = base.DoResolve (rc);
12527 // For better error reporting, assumes the built-in implementation uses object
12530 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12533 public int? ResolveAligment (ResolveContext rc)
12535 var c = Alignment.ResolveLabelConstant (rc);
12539 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12543 var value = (int) c.GetValueAsLong ();
12544 if (value > 32767 || value < -32767) {
12545 rc.Report.Warning (8094, 1, Alignment.Location,
12546 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");