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;
19 using MetaType = IKVM.Reflection.Type;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
23 using MetaType = System.Type;
24 using System.Reflection;
25 using System.Reflection.Emit;
31 // This is an user operator expression, automatically created during
34 public class UserOperatorCall : Expression {
35 protected readonly Arguments arguments;
36 protected readonly MethodSpec oper;
37 readonly Func<ResolveContext, Expression, Expression> expr_tree;
39 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
42 this.arguments = args;
43 this.expr_tree = expr_tree;
45 type = oper.ReturnType;
46 eclass = ExprClass.Value;
50 public override bool ContainsEmitWithAwait ()
52 return arguments.ContainsEmitWithAwait ();
55 public override Expression CreateExpressionTree (ResolveContext ec)
57 if (expr_tree != null)
58 return expr_tree (ec, new TypeOfMethod (oper, loc));
60 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
61 new NullLiteral (loc),
62 new TypeOfMethod (oper, loc));
64 return CreateExpressionFactoryCall (ec, "Call", args);
67 protected override void CloneTo (CloneContext context, Expression target)
72 protected override Expression DoResolve (ResolveContext ec)
75 // We are born fully resolved
80 public override void Emit (EmitContext ec)
82 var call = new CallEmitter ();
83 call.EmitPredefined (ec, oper, arguments, loc);
86 public override SLE.Expression MakeExpression (BuilderContext ctx)
89 return base.MakeExpression (ctx);
91 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
96 public class ParenthesizedExpression : ShimExpression
98 public ParenthesizedExpression (Expression expr, Location loc)
104 protected override Expression DoResolve (ResolveContext ec)
106 var res = expr.Resolve (ec);
107 var constant = res as Constant;
108 if (constant != null && constant.IsLiteral)
109 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
114 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
116 return expr.DoResolveLValue (ec, right_side);
119 public override object Accept (StructuralVisitor visitor)
121 return visitor.Visit (this);
126 // Unary implements unary expressions.
128 public class Unary : Expression
130 public enum Operator : byte {
131 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
135 public readonly Operator Oper;
136 public Expression Expr;
137 Expression enum_conversion;
139 public Unary (Operator op, Expression expr, Location loc)
147 // This routine will attempt to simplify the unary expression when the
148 // argument is a constant.
150 Constant TryReduceConstant (ResolveContext ec, Constant constant)
154 while (e is EmptyConstantCast)
155 e = ((EmptyConstantCast) e).child;
157 if (e is SideEffectConstant) {
158 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
159 return r == null ? null : new SideEffectConstant (r, e, r.Location);
162 TypeSpec expr_type = e.Type;
165 case Operator.UnaryPlus:
166 // Unary numeric promotions
167 switch (expr_type.BuiltinType) {
168 case BuiltinTypeSpec.Type.Byte:
169 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
170 case BuiltinTypeSpec.Type.SByte:
171 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
172 case BuiltinTypeSpec.Type.Short:
173 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
174 case BuiltinTypeSpec.Type.UShort:
175 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
176 case BuiltinTypeSpec.Type.Char:
177 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
179 // Predefined operators
180 case BuiltinTypeSpec.Type.Int:
181 case BuiltinTypeSpec.Type.UInt:
182 case BuiltinTypeSpec.Type.Long:
183 case BuiltinTypeSpec.Type.ULong:
184 case BuiltinTypeSpec.Type.Float:
185 case BuiltinTypeSpec.Type.Double:
186 case BuiltinTypeSpec.Type.Decimal:
192 case Operator.UnaryNegation:
193 // Unary numeric promotions
194 switch (expr_type.BuiltinType) {
195 case BuiltinTypeSpec.Type.Byte:
196 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
197 case BuiltinTypeSpec.Type.SByte:
198 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
199 case BuiltinTypeSpec.Type.Short:
200 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
201 case BuiltinTypeSpec.Type.UShort:
202 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
203 case BuiltinTypeSpec.Type.Char:
204 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
206 // Predefined operators
207 case BuiltinTypeSpec.Type.Int:
208 int ivalue = ((IntConstant) e).Value;
209 if (ivalue == int.MinValue) {
210 if (ec.ConstantCheckState) {
211 ConstantFold.Error_CompileTimeOverflow (ec, loc);
216 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
218 case BuiltinTypeSpec.Type.Long:
219 long lvalue = ((LongConstant) e).Value;
220 if (lvalue == long.MinValue) {
221 if (ec.ConstantCheckState) {
222 ConstantFold.Error_CompileTimeOverflow (ec, loc);
227 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
229 case BuiltinTypeSpec.Type.UInt:
230 UIntLiteral uil = constant as UIntLiteral;
232 if (uil.Value == int.MaxValue + (uint) 1)
233 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
234 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
236 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
239 case BuiltinTypeSpec.Type.ULong:
240 ULongLiteral ull = constant as ULongLiteral;
241 if (ull != null && ull.Value == 9223372036854775808)
242 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
245 case BuiltinTypeSpec.Type.Float:
246 FloatLiteral fl = constant as FloatLiteral;
247 // For better error reporting
249 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
251 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
253 case BuiltinTypeSpec.Type.Double:
254 DoubleLiteral dl = constant as DoubleLiteral;
255 // For better error reporting
257 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
259 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
261 case BuiltinTypeSpec.Type.Decimal:
262 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
267 case Operator.LogicalNot:
268 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
271 bool b = (bool)e.GetValue ();
272 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
274 case Operator.OnesComplement:
275 // Unary numeric promotions
276 switch (expr_type.BuiltinType) {
277 case BuiltinTypeSpec.Type.Byte:
278 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
279 case BuiltinTypeSpec.Type.SByte:
280 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
281 case BuiltinTypeSpec.Type.Short:
282 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
283 case BuiltinTypeSpec.Type.UShort:
284 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
285 case BuiltinTypeSpec.Type.Char:
286 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
288 // Predefined operators
289 case BuiltinTypeSpec.Type.Int:
290 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
291 case BuiltinTypeSpec.Type.UInt:
292 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
293 case BuiltinTypeSpec.Type.Long:
294 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
295 case BuiltinTypeSpec.Type.ULong:
296 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
298 if (e is EnumConstant) {
299 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
301 e = new EnumConstant (e, expr_type);
306 throw new Exception ("Can not constant fold: " + Oper.ToString());
309 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
311 eclass = ExprClass.Value;
313 TypeSpec expr_type = expr.Type;
314 Expression best_expr;
316 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
319 // Primitive types first
321 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
322 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
323 if (best_expr == null)
326 type = best_expr.Type;
332 // E operator ~(E x);
334 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
335 return ResolveEnumOperator (ec, expr, predefined);
337 return ResolveUserType (ec, expr, predefined);
340 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
342 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
343 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
344 if (best_expr == null)
348 enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (best_expr.Type), underlying_type);
350 return EmptyCast.Create (this, type);
353 public override bool ContainsEmitWithAwait ()
355 return Expr.ContainsEmitWithAwait ();
358 public override Expression CreateExpressionTree (ResolveContext ec)
360 return CreateExpressionTree (ec, null);
363 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
367 case Operator.AddressOf:
368 Error_PointerInsideExpressionTree (ec);
370 case Operator.UnaryNegation:
371 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
372 method_name = "NegateChecked";
374 method_name = "Negate";
376 case Operator.OnesComplement:
377 case Operator.LogicalNot:
380 case Operator.UnaryPlus:
381 method_name = "UnaryPlus";
384 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
387 Arguments args = new Arguments (2);
388 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
390 args.Add (new Argument (user_op));
392 return CreateExpressionFactoryCall (ec, method_name, args);
395 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
397 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
400 // 7.6.1 Unary plus operator
402 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
403 types.Int, types.UInt,
404 types.Long, types.ULong,
405 types.Float, types.Double,
410 // 7.6.2 Unary minus operator
412 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
413 types.Int, types.Long,
414 types.Float, types.Double,
419 // 7.6.3 Logical negation operator
421 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
426 // 7.6.4 Bitwise complement operator
428 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
429 types.Int, types.UInt,
430 types.Long, types.ULong
433 return predefined_operators;
437 // Unary numeric promotions
439 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
441 TypeSpec expr_type = expr.Type;
442 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
443 switch (expr_type.BuiltinType) {
444 case BuiltinTypeSpec.Type.Byte:
445 case BuiltinTypeSpec.Type.SByte:
446 case BuiltinTypeSpec.Type.Short:
447 case BuiltinTypeSpec.Type.UShort:
448 case BuiltinTypeSpec.Type.Char:
449 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
453 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
454 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
459 protected override Expression DoResolve (ResolveContext ec)
461 if (Oper == Operator.AddressOf) {
462 return ResolveAddressOf (ec);
465 Expr = Expr.Resolve (ec);
469 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
470 Arguments args = new Arguments (1);
471 args.Add (new Argument (Expr));
472 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
475 if (Expr.Type.IsNullableType)
476 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
479 // Attempt to use a constant folding operation.
481 Constant cexpr = Expr as Constant;
483 cexpr = TryReduceConstant (ec, cexpr);
488 Expression expr = ResolveOperator (ec, Expr);
490 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
493 // Reduce unary operator on predefined types
495 if (expr == this && Oper == Operator.UnaryPlus)
501 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
506 public override void Emit (EmitContext ec)
508 EmitOperator (ec, type);
511 protected void EmitOperator (EmitContext ec, TypeSpec type)
514 case Operator.UnaryPlus:
518 case Operator.UnaryNegation:
519 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
520 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
521 Expr = Expr.EmitToField (ec);
524 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
525 ec.Emit (OpCodes.Conv_U8);
527 ec.Emit (OpCodes.Sub_Ovf);
530 ec.Emit (OpCodes.Neg);
535 case Operator.LogicalNot:
538 ec.Emit (OpCodes.Ceq);
541 case Operator.OnesComplement:
543 ec.Emit (OpCodes.Not);
546 case Operator.AddressOf:
547 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
551 throw new Exception ("This should not happen: Operator = "
556 // Same trick as in Binary expression
558 if (enum_conversion != null)
559 enum_conversion.Emit (ec);
562 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
564 if (Oper == Operator.LogicalNot)
565 Expr.EmitBranchable (ec, target, !on_true);
567 base.EmitBranchable (ec, target, on_true);
570 public override void EmitSideEffect (EmitContext ec)
572 Expr.EmitSideEffect (ec);
576 // Converts operator to System.Linq.Expressions.ExpressionType enum name
578 string GetOperatorExpressionTypeName ()
581 case Operator.OnesComplement:
582 return "OnesComplement";
583 case Operator.LogicalNot:
585 case Operator.UnaryNegation:
587 case Operator.UnaryPlus:
590 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
594 static bool IsFloat (TypeSpec t)
596 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
600 // Returns a stringified representation of the Operator
602 public static string OperName (Operator oper)
605 case Operator.UnaryPlus:
607 case Operator.UnaryNegation:
609 case Operator.LogicalNot:
611 case Operator.OnesComplement:
613 case Operator.AddressOf:
617 throw new NotImplementedException (oper.ToString ());
620 public override SLE.Expression MakeExpression (BuilderContext ctx)
622 var expr = Expr.MakeExpression (ctx);
623 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
626 case Operator.UnaryNegation:
627 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
628 case Operator.LogicalNot:
629 return SLE.Expression.Not (expr);
630 #if NET_4_0 || MONODROID
631 case Operator.OnesComplement:
632 return SLE.Expression.OnesComplement (expr);
635 throw new NotImplementedException (Oper.ToString ());
639 Expression ResolveAddressOf (ResolveContext ec)
642 UnsafeError (ec, loc);
644 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
645 if (Expr == null || Expr.eclass != ExprClass.Variable) {
646 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
650 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
654 IVariableReference vr = Expr as IVariableReference;
657 is_fixed = vr.IsFixed;
658 vr.SetHasAddressTaken ();
661 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
664 IFixedExpression fe = Expr as IFixedExpression;
665 is_fixed = fe != null && fe.IsFixed;
668 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
669 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
672 type = PointerContainer.MakeType (ec.Module, Expr.Type);
673 eclass = ExprClass.Value;
677 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
679 expr = DoNumericPromotion (rc, Oper, expr);
680 TypeSpec expr_type = expr.Type;
681 foreach (TypeSpec t in predefined) {
689 // Perform user-operator overload resolution
691 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
693 CSharp.Operator.OpType op_type;
695 case Operator.LogicalNot:
696 op_type = CSharp.Operator.OpType.LogicalNot; break;
697 case Operator.OnesComplement:
698 op_type = CSharp.Operator.OpType.OnesComplement; break;
699 case Operator.UnaryNegation:
700 op_type = CSharp.Operator.OpType.UnaryNegation; break;
701 case Operator.UnaryPlus:
702 op_type = CSharp.Operator.OpType.UnaryPlus; break;
704 throw new InternalErrorException (Oper.ToString ());
707 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
711 Arguments args = new Arguments (1);
712 args.Add (new Argument (expr));
714 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
715 var oper = res.ResolveOperator (ec, ref args);
720 Expr = args [0].Expr;
721 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
725 // Unary user type overload resolution
727 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
729 Expression best_expr = ResolveUserOperator (ec, expr);
730 if (best_expr != null)
733 foreach (TypeSpec t in predefined) {
734 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
735 if (oper_expr == null)
738 if (oper_expr == ErrorExpression.Instance)
742 // decimal type is predefined but has user-operators
744 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
745 oper_expr = ResolveUserType (ec, oper_expr, predefined);
747 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
749 if (oper_expr == null)
752 if (best_expr == null) {
753 best_expr = oper_expr;
757 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
759 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
760 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
761 OperName (Oper), expr.Type.GetSignatureForError ());
763 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
770 best_expr = oper_expr;
773 if (best_expr == null)
777 // HACK: Decimal user-operator is included in standard operators
779 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
783 type = best_expr.Type;
787 protected override void CloneTo (CloneContext clonectx, Expression t)
789 Unary target = (Unary) t;
791 target.Expr = Expr.Clone (clonectx);
794 public override object Accept (StructuralVisitor visitor)
796 return visitor.Visit (this);
802 // Unary operators are turned into Indirection expressions
803 // after semantic analysis (this is so we can take the address
804 // of an indirection).
806 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
808 LocalTemporary temporary;
811 public Indirection (Expression expr, Location l)
817 public Expression Expr {
823 public bool IsFixed {
827 public override Location StartLocation {
829 return expr.StartLocation;
833 protected override void CloneTo (CloneContext clonectx, Expression t)
835 Indirection target = (Indirection) t;
836 target.expr = expr.Clone (clonectx);
839 public override bool ContainsEmitWithAwait ()
841 throw new NotImplementedException ();
844 public override Expression CreateExpressionTree (ResolveContext ec)
846 Error_PointerInsideExpressionTree (ec);
850 public override void Emit (EmitContext ec)
855 ec.EmitLoadFromPtr (Type);
858 public void Emit (EmitContext ec, bool leave_copy)
862 ec.Emit (OpCodes.Dup);
863 temporary = new LocalTemporary (expr.Type);
864 temporary.Store (ec);
868 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
870 prepared = isCompound;
875 ec.Emit (OpCodes.Dup);
879 ec.Emit (OpCodes.Dup);
880 temporary = new LocalTemporary (source.Type);
881 temporary.Store (ec);
884 ec.EmitStoreFromPtr (type);
886 if (temporary != null) {
888 temporary.Release (ec);
892 public void AddressOf (EmitContext ec, AddressOp Mode)
897 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
899 return DoResolve (ec);
902 protected override Expression DoResolve (ResolveContext ec)
904 expr = expr.Resolve (ec);
909 UnsafeError (ec, loc);
911 var pc = expr.Type as PointerContainer;
914 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
920 if (type.Kind == MemberKind.Void) {
921 Error_VoidPointerOperation (ec);
925 eclass = ExprClass.Variable;
929 public override object Accept (StructuralVisitor visitor)
931 return visitor.Visit (this);
936 /// Unary Mutator expressions (pre and post ++ and --)
940 /// UnaryMutator implements ++ and -- expressions. It derives from
941 /// ExpressionStatement becuase the pre/post increment/decrement
942 /// operators can be used in a statement context.
944 /// FIXME: Idea, we could split this up in two classes, one simpler
945 /// for the common case, and one with the extra fields for more complex
946 /// classes (indexers require temporary access; overloaded require method)
949 public class UnaryMutator : ExpressionStatement
951 class DynamicPostMutator : Expression, IAssignMethod
956 public DynamicPostMutator (Expression expr)
959 this.type = expr.Type;
960 this.loc = expr.Location;
963 public override Expression CreateExpressionTree (ResolveContext ec)
965 throw new NotImplementedException ("ET");
968 protected override Expression DoResolve (ResolveContext rc)
970 eclass = expr.eclass;
974 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
976 expr.DoResolveLValue (ec, right_side);
977 return DoResolve (ec);
980 public override void Emit (EmitContext ec)
985 public void Emit (EmitContext ec, bool leave_copy)
987 throw new NotImplementedException ();
991 // Emits target assignment using unmodified source value
993 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
996 // Allocate temporary variable to keep original value before it's modified
998 temp = new LocalTemporary (type);
1002 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1013 public enum Mode : byte {
1020 PreDecrement = IsDecrement,
1021 PostIncrement = IsPost,
1022 PostDecrement = IsPost | IsDecrement
1026 bool is_expr, recurse;
1028 protected Expression expr;
1030 // Holds the real operation
1031 Expression operation;
1033 public UnaryMutator (Mode m, Expression e, Location loc)
1040 public Mode UnaryMutatorMode {
1046 public Expression Expr {
1052 public override Location StartLocation {
1054 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1058 public override bool ContainsEmitWithAwait ()
1060 return expr.ContainsEmitWithAwait ();
1063 public override Expression CreateExpressionTree (ResolveContext ec)
1065 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1068 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1071 // Predefined ++ and -- operators exist for the following types:
1072 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1074 return new TypeSpec[] {
1090 protected override Expression DoResolve (ResolveContext ec)
1092 expr = expr.Resolve (ec);
1097 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1099 // Handle postfix unary operators using local
1100 // temporary variable
1102 if ((mode & Mode.IsPost) != 0)
1103 expr = new DynamicPostMutator (expr);
1105 Arguments args = new Arguments (1);
1106 args.Add (new Argument (expr));
1107 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1110 if (expr.Type.IsNullableType)
1111 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1113 return DoResolveOperation (ec);
1116 protected Expression DoResolveOperation (ResolveContext ec)
1118 eclass = ExprClass.Value;
1121 if (expr is RuntimeValueExpression) {
1124 // Use itself at the top of the stack
1125 operation = new EmptyExpression (type);
1129 // The operand of the prefix/postfix increment decrement operators
1130 // should be an expression that is classified as a variable,
1131 // a property access or an indexer access
1133 // TODO: Move to parser, expr is ATypeNameExpression
1134 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1135 expr = expr.ResolveLValue (ec, expr);
1137 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1141 // Step 1: Try to find a user operator, it has priority over predefined ones
1143 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1144 var methods = MemberCache.GetUserOperator (type, user_op, false);
1146 if (methods != null) {
1147 Arguments args = new Arguments (1);
1148 args.Add (new Argument (expr));
1150 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1151 var method = res.ResolveOperator (ec, ref args);
1155 args[0].Expr = operation;
1156 operation = new UserOperatorCall (method, args, null, loc);
1157 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1162 // Step 2: Try predefined types
1165 Expression source = null;
1166 bool primitive_type;
1169 // Predefined without user conversion first for speed-up
1171 // Predefined ++ and -- operators exist for the following types:
1172 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1174 switch (type.BuiltinType) {
1175 case BuiltinTypeSpec.Type.Byte:
1176 case BuiltinTypeSpec.Type.SByte:
1177 case BuiltinTypeSpec.Type.Short:
1178 case BuiltinTypeSpec.Type.UShort:
1179 case BuiltinTypeSpec.Type.Int:
1180 case BuiltinTypeSpec.Type.UInt:
1181 case BuiltinTypeSpec.Type.Long:
1182 case BuiltinTypeSpec.Type.ULong:
1183 case BuiltinTypeSpec.Type.Char:
1184 case BuiltinTypeSpec.Type.Float:
1185 case BuiltinTypeSpec.Type.Double:
1186 case BuiltinTypeSpec.Type.Decimal:
1188 primitive_type = true;
1191 primitive_type = false;
1193 // ++/-- on pointer variables of all types except void*
1194 if (type.IsPointer) {
1195 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1196 Error_VoidPointerOperation (ec);
1202 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1203 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1205 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1206 if (source != null) {
1212 // ++/-- on enum types
1213 if (source == null && type.IsEnum)
1216 if (source == null) {
1217 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1224 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1225 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1226 operation = new Binary (op, source, one);
1227 operation = operation.Resolve (ec);
1228 if (operation == null)
1229 throw new NotImplementedException ("should not be reached");
1231 if (operation.Type != type) {
1233 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1235 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1241 void EmitCode (EmitContext ec, bool is_expr)
1244 this.is_expr = is_expr;
1245 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1248 public override void Emit (EmitContext ec)
1251 // We use recurse to allow ourselfs to be the source
1252 // of an assignment. This little hack prevents us from
1253 // having to allocate another expression
1256 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1264 EmitCode (ec, true);
1267 protected virtual void EmitOperation (EmitContext ec)
1269 operation.Emit (ec);
1272 public override void EmitStatement (EmitContext ec)
1274 EmitCode (ec, false);
1278 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1280 string GetOperatorExpressionTypeName ()
1282 return IsDecrement ? "Decrement" : "Increment";
1286 get { return (mode & Mode.IsDecrement) != 0; }
1290 #if NET_4_0 || MONODROID
1291 public override SLE.Expression MakeExpression (BuilderContext ctx)
1293 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1294 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1295 return SLE.Expression.Assign (target, source);
1299 protected override void CloneTo (CloneContext clonectx, Expression t)
1301 UnaryMutator target = (UnaryMutator) t;
1303 target.expr = expr.Clone (clonectx);
1306 public override object Accept (StructuralVisitor visitor)
1308 return visitor.Visit (this);
1314 // Base class for the `is' and `as' operators
1316 public abstract class Probe : Expression
1318 public Expression ProbeType;
1319 protected Expression expr;
1320 protected TypeSpec probe_type_expr;
1322 public Probe (Expression expr, Expression probe_type, Location l)
1324 ProbeType = probe_type;
1329 public Expression Expr {
1335 public override bool ContainsEmitWithAwait ()
1337 return expr.ContainsEmitWithAwait ();
1340 protected override Expression DoResolve (ResolveContext ec)
1342 probe_type_expr = ProbeType.ResolveAsType (ec);
1343 if (probe_type_expr == null)
1346 expr = expr.Resolve (ec);
1350 if (probe_type_expr.IsStatic) {
1351 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1355 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1356 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1361 if (expr.Type == InternalType.AnonymousMethod) {
1362 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1370 protected abstract string OperatorName { get; }
1372 protected override void CloneTo (CloneContext clonectx, Expression t)
1374 Probe target = (Probe) t;
1376 target.expr = expr.Clone (clonectx);
1377 target.ProbeType = ProbeType.Clone (clonectx);
1383 /// Implementation of the `is' operator.
1385 public class Is : Probe
1387 Nullable.Unwrap expr_unwrap;
1389 public Is (Expression expr, Expression probe_type, Location l)
1390 : base (expr, probe_type, l)
1394 protected override string OperatorName {
1395 get { return "is"; }
1398 public override Expression CreateExpressionTree (ResolveContext ec)
1400 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1401 expr.CreateExpressionTree (ec),
1402 new TypeOf (probe_type_expr, loc));
1404 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1407 public override void Emit (EmitContext ec)
1409 if (expr_unwrap != null) {
1410 expr_unwrap.EmitCheck (ec);
1416 // Only to make verifier happy
1417 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1418 ec.Emit (OpCodes.Box, expr.Type);
1420 ec.Emit (OpCodes.Isinst, probe_type_expr);
1422 ec.Emit (OpCodes.Cgt_Un);
1425 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1427 if (expr_unwrap != null) {
1428 expr_unwrap.EmitCheck (ec);
1431 ec.Emit (OpCodes.Isinst, probe_type_expr);
1433 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1436 Expression CreateConstantResult (ResolveContext ec, bool result)
1439 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1440 probe_type_expr.GetSignatureForError ());
1442 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1443 probe_type_expr.GetSignatureForError ());
1445 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, result, loc), this);
1448 protected override Expression DoResolve (ResolveContext ec)
1450 if (base.DoResolve (ec) == null)
1453 TypeSpec d = expr.Type;
1454 bool d_is_nullable = false;
1457 // If E is a method group or the null literal, or if the type of E is a reference
1458 // type or a nullable type and the value of E is null, the result is false
1460 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1461 return CreateConstantResult (ec, false);
1463 if (d.IsNullableType) {
1464 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1465 if (!ut.IsGenericParameter) {
1467 d_is_nullable = true;
1471 type = ec.BuiltinTypes.Bool;
1472 eclass = ExprClass.Value;
1473 TypeSpec t = probe_type_expr;
1474 bool t_is_nullable = false;
1475 if (t.IsNullableType) {
1476 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1477 if (!ut.IsGenericParameter) {
1479 t_is_nullable = true;
1486 // D and T are the same value types but D can be null
1488 if (d_is_nullable && !t_is_nullable) {
1489 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1494 // The result is true if D and T are the same value types
1496 return CreateConstantResult (ec, true);
1499 var tp = d as TypeParameterSpec;
1501 return ResolveGenericParameter (ec, t, tp);
1504 // An unboxing conversion exists
1506 if (Convert.ExplicitReferenceConversionExists (d, t))
1509 if (TypeManager.IsGenericParameter (t))
1510 return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
1512 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1513 ec.Report.Warning (1981, 3, loc,
1514 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1515 OperatorName, t.GetSignatureForError ());
1518 if (TypeManager.IsGenericParameter (d))
1519 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1521 if (TypeSpec.IsValueType (d)) {
1522 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1523 if (d_is_nullable && !t_is_nullable) {
1524 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1528 return CreateConstantResult (ec, true);
1531 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1533 // Do not optimize for imported type
1535 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None)
1539 // Turn is check into simple null check for implicitly convertible reference types
1541 return ReducedExpression.Create (
1542 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1546 if (Convert.ExplicitReferenceConversionExists (d, t)) {
1552 return CreateConstantResult (ec, false);
1555 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1557 if (t.IsReferenceType) {
1559 return CreateConstantResult (ec, false);
1562 if (TypeManager.IsGenericParameter (expr.Type)) {
1563 if (expr.Type == d && TypeSpec.IsValueType (t))
1564 return CreateConstantResult (ec, true);
1566 expr = new BoxedCast (expr, d);
1572 public override object Accept (StructuralVisitor visitor)
1574 return visitor.Visit (this);
1579 /// Implementation of the `as' operator.
1581 public class As : Probe {
1582 Expression resolved_type;
1584 public As (Expression expr, Expression probe_type, Location l)
1585 : base (expr, probe_type, l)
1589 protected override string OperatorName {
1590 get { return "as"; }
1593 public override Expression CreateExpressionTree (ResolveContext ec)
1595 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1596 expr.CreateExpressionTree (ec),
1597 new TypeOf (probe_type_expr, loc));
1599 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1602 public override void Emit (EmitContext ec)
1606 ec.Emit (OpCodes.Isinst, type);
1608 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1609 ec.Emit (OpCodes.Unbox_Any, type);
1612 protected override Expression DoResolve (ResolveContext ec)
1614 if (resolved_type == null) {
1615 resolved_type = base.DoResolve (ec);
1617 if (resolved_type == null)
1621 type = probe_type_expr;
1622 eclass = ExprClass.Value;
1623 TypeSpec etype = expr.Type;
1625 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1626 if (TypeManager.IsGenericParameter (type)) {
1627 ec.Report.Error (413, loc,
1628 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1629 probe_type_expr.GetSignatureForError ());
1631 ec.Report.Error (77, loc,
1632 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1633 type.GetSignatureForError ());
1638 if (expr.IsNull && type.IsNullableType) {
1639 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1642 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1643 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1647 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1649 e = EmptyCast.Create (e, type);
1650 return ReducedExpression.Create (e, this).Resolve (ec);
1653 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1654 if (TypeManager.IsGenericParameter (etype))
1655 expr = new BoxedCast (expr, etype);
1660 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1661 expr = new BoxedCast (expr, etype);
1665 if (etype != InternalType.ErrorType) {
1666 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1667 etype.GetSignatureForError (), type.GetSignatureForError ());
1673 public override object Accept (StructuralVisitor visitor)
1675 return visitor.Visit (this);
1680 // This represents a typecast in the source language.
1682 public class Cast : ShimExpression {
1683 Expression target_type;
1685 public Cast (Expression cast_type, Expression expr, Location loc)
1688 this.target_type = cast_type;
1692 public Expression TargetType {
1693 get { return target_type; }
1696 protected override Expression DoResolve (ResolveContext ec)
1698 expr = expr.Resolve (ec);
1702 type = target_type.ResolveAsType (ec);
1706 if (type.IsStatic) {
1707 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
1711 if (type.IsPointer && !ec.IsUnsafe) {
1712 UnsafeError (ec, loc);
1715 eclass = ExprClass.Value;
1717 Constant c = expr as Constant;
1719 c = c.Reduce (ec, type);
1724 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1726 return EmptyCast.Create (res, type);
1731 protected override void CloneTo (CloneContext clonectx, Expression t)
1733 Cast target = (Cast) t;
1735 target.target_type = target_type.Clone (clonectx);
1736 target.expr = expr.Clone (clonectx);
1739 public override object Accept (StructuralVisitor visitor)
1741 return visitor.Visit (this);
1745 public class ImplicitCast : ShimExpression
1749 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1752 this.loc = expr.Location;
1754 this.arrayAccess = arrayAccess;
1757 protected override Expression DoResolve (ResolveContext ec)
1759 expr = expr.Resolve (ec);
1764 expr = ConvertExpressionToArrayIndex (ec, expr);
1766 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1773 // C# 2.0 Default value expression
1775 public class DefaultValueExpression : Expression
1779 public DefaultValueExpression (Expression expr, Location loc)
1785 public Expression Expr {
1791 public override bool IsSideEffectFree {
1797 public override bool ContainsEmitWithAwait ()
1802 public override Expression CreateExpressionTree (ResolveContext ec)
1804 Arguments args = new Arguments (2);
1805 args.Add (new Argument (this));
1806 args.Add (new Argument (new TypeOf (type, loc)));
1807 return CreateExpressionFactoryCall (ec, "Constant", args);
1810 protected override Expression DoResolve (ResolveContext ec)
1812 type = expr.ResolveAsType (ec);
1816 if (type.IsStatic) {
1817 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1821 return new NullLiteral (Location).ConvertImplicitly (type);
1823 if (TypeSpec.IsReferenceType (type))
1824 return new NullConstant (type, loc);
1826 Constant c = New.Constantify (type, expr.Location);
1830 eclass = ExprClass.Variable;
1834 public override void Emit (EmitContext ec)
1836 LocalTemporary temp_storage = new LocalTemporary(type);
1838 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1839 ec.Emit(OpCodes.Initobj, type);
1840 temp_storage.Emit(ec);
1841 temp_storage.Release (ec);
1844 #if (NET_4_0 || MONODROID) && !STATIC
1845 public override SLE.Expression MakeExpression (BuilderContext ctx)
1847 return SLE.Expression.Default (type.GetMetaInfo ());
1851 protected override void CloneTo (CloneContext clonectx, Expression t)
1853 DefaultValueExpression target = (DefaultValueExpression) t;
1855 target.expr = expr.Clone (clonectx);
1858 public override object Accept (StructuralVisitor visitor)
1860 return visitor.Visit (this);
1865 /// Binary operators
1867 public class Binary : Expression, IDynamicBinder
1869 public class PredefinedOperator
1871 protected readonly TypeSpec left;
1872 protected readonly TypeSpec right;
1873 protected readonly TypeSpec left_unwrap;
1874 protected readonly TypeSpec right_unwrap;
1875 public readonly Operator OperatorsMask;
1876 public TypeSpec ReturnType;
1878 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1879 : this (ltype, rtype, op_mask, ltype)
1883 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1884 : this (type, type, op_mask, return_type)
1888 public PredefinedOperator (TypeSpec type, Operator op_mask)
1889 : this (type, type, op_mask, type)
1893 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1895 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1896 throw new InternalErrorException ("Only masked values can be used");
1898 if ((op_mask & Operator.NullableMask) != 0) {
1899 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
1900 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
1902 left_unwrap = ltype;
1903 right_unwrap = rtype;
1908 this.OperatorsMask = op_mask;
1909 this.ReturnType = return_type;
1912 public bool IsLifted {
1914 return (OperatorsMask & Operator.NullableMask) != 0;
1918 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
1922 var left_expr = b.left;
1923 var right_expr = b.right;
1925 b.type = ReturnType;
1928 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
1929 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1930 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1933 if (right_expr.IsNull) {
1934 if ((b.oper & Operator.EqualityMask) != 0) {
1935 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
1936 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
1937 } else if ((b.oper & Operator.BitwiseMask) != 0) {
1938 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
1939 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1941 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1942 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1944 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
1945 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1947 return b.CreateLiftedValueTypeResult (rc, left);
1949 } else if (left_expr.IsNull) {
1950 if ((b.oper & Operator.EqualityMask) != 0) {
1951 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
1952 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
1953 } else if ((b.oper & Operator.BitwiseMask) != 0) {
1954 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
1955 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1957 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1958 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1960 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
1961 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1963 return b.CreateLiftedValueTypeResult (rc, right);
1969 // A user operators does not support multiple user conversions, but decimal type
1970 // is considered to be predefined type therefore we apply predefined operators rules
1971 // and then look for decimal user-operator implementation
1973 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
1974 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1975 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1977 return b.ResolveUserOperator (rc, b.left, b.right);
1980 c = right_expr as Constant;
1982 if (c.IsDefaultValue) {
1986 // (expr + 0) to expr
1987 // (expr - 0) to expr
1988 // (bool? | false) to bool?
1990 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
1991 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
1992 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1993 return ReducedExpression.Create (b.left, b).Resolve (rc);
1999 // (bool? & true) to bool?
2001 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2002 return ReducedExpression.Create (b.left, b).Resolve (rc);
2006 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2007 return ReducedExpression.Create (b.left, b).Resolve (rc);
2009 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2010 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2014 c = b.left as Constant;
2016 if (c.IsDefaultValue) {
2020 // (0 + expr) to expr
2021 // (false | bool?) to bool?
2023 if (b.oper == Operator.Addition ||
2024 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2025 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2026 return ReducedExpression.Create (b.right, b).Resolve (rc);
2032 // (true & bool?) to bool?
2034 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2035 return ReducedExpression.Create (b.right, b).Resolve (rc);
2039 if (b.oper == Operator.Multiply && c.IsOneInteger)
2040 return ReducedExpression.Create (b.right, b).Resolve (rc);
2044 var lifted = new Nullable.LiftedBinaryOperator (b);
2046 TypeSpec ltype, rtype;
2047 if (b.left.Type.IsNullableType) {
2048 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2049 ltype = left_unwrap;
2054 if (b.right.Type.IsNullableType) {
2055 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2056 rtype = right_unwrap;
2061 lifted.Left = b.left.IsNull ?
2063 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2065 lifted.Right = b.right.IsNull ?
2067 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2069 return lifted.Resolve (rc);
2072 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2073 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2078 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2081 // We are dealing with primitive types only
2083 return left == ltype && ltype == rtype;
2086 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2089 if (left == lexpr.Type && right == rexpr.Type)
2092 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2093 Convert.ImplicitConversionExists (ec, rexpr, right);
2096 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2098 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2099 return best_operator;
2101 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2105 if (left != null && best_operator.left != null) {
2106 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2110 // When second argument is same as the first one, the result is same
2112 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2113 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2116 if (result == 0 || result > 2)
2119 return result == 1 ? best_operator : this;
2123 sealed class PredefinedStringOperator : PredefinedOperator
2125 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2126 : base (type, type, op_mask, retType)
2130 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2131 : base (ltype, rtype, op_mask, retType)
2135 public override Expression ConvertResult (ResolveContext ec, Binary b)
2138 // Use original expression for nullable arguments
2140 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2142 b.left = unwrap.Original;
2144 unwrap = b.right as Nullable.Unwrap;
2146 b.right = unwrap.Original;
2148 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2149 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2152 // Start a new concat expression using converted expression
2154 return StringConcat.Create (ec, b.left, b.right, b.loc);
2158 sealed class PredefinedEqualityOperator : PredefinedOperator
2160 MethodSpec equal_method, inequal_method;
2162 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
2163 : base (arg, arg, Operator.EqualityMask, retType)
2167 public override Expression ConvertResult (ResolveContext ec, Binary b)
2169 b.type = ReturnType;
2171 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2172 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2174 Arguments args = new Arguments (2);
2175 args.Add (new Argument (b.left));
2176 args.Add (new Argument (b.right));
2179 if (b.oper == Operator.Equality) {
2180 if (equal_method == null) {
2181 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2182 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2183 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2184 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2186 throw new NotImplementedException (left.GetSignatureForError ());
2189 method = equal_method;
2191 if (inequal_method == null) {
2192 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2193 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2194 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2195 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2197 throw new NotImplementedException (left.GetSignatureForError ());
2200 method = inequal_method;
2203 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2207 class PredefinedPointerOperator : PredefinedOperator
2209 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2210 : base (ltype, rtype, op_mask)
2214 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2215 : base (ltype, rtype, op_mask, retType)
2219 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2220 : base (type, op_mask, return_type)
2224 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2227 if (!lexpr.Type.IsPointer)
2230 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2234 if (right == null) {
2235 if (!rexpr.Type.IsPointer)
2238 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2245 public override Expression ConvertResult (ResolveContext ec, Binary b)
2248 b.left = EmptyCast.Create (b.left, left);
2249 } else if (right != null) {
2250 b.right = EmptyCast.Create (b.right, right);
2253 TypeSpec r_type = ReturnType;
2254 Expression left_arg, right_arg;
2255 if (r_type == null) {
2258 right_arg = b.right;
2259 r_type = b.left.Type;
2263 r_type = b.right.Type;
2267 right_arg = b.right;
2270 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2275 public enum Operator {
2276 Multiply = 0 | ArithmeticMask,
2277 Division = 1 | ArithmeticMask,
2278 Modulus = 2 | ArithmeticMask,
2279 Addition = 3 | ArithmeticMask | AdditionMask,
2280 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2282 LeftShift = 5 | ShiftMask,
2283 RightShift = 6 | ShiftMask,
2285 LessThan = 7 | ComparisonMask | RelationalMask,
2286 GreaterThan = 8 | ComparisonMask | RelationalMask,
2287 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2288 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2289 Equality = 11 | ComparisonMask | EqualityMask,
2290 Inequality = 12 | ComparisonMask | EqualityMask,
2292 BitwiseAnd = 13 | BitwiseMask,
2293 ExclusiveOr = 14 | BitwiseMask,
2294 BitwiseOr = 15 | BitwiseMask,
2296 LogicalAnd = 16 | LogicalMask,
2297 LogicalOr = 17 | LogicalMask,
2302 ValuesOnlyMask = ArithmeticMask - 1,
2303 ArithmeticMask = 1 << 5,
2305 ComparisonMask = 1 << 7,
2306 EqualityMask = 1 << 8,
2307 BitwiseMask = 1 << 9,
2308 LogicalMask = 1 << 10,
2309 AdditionMask = 1 << 11,
2310 SubtractionMask = 1 << 12,
2311 RelationalMask = 1 << 13,
2313 DecomposedMask = 1 << 19,
2314 NullableMask = 1 << 20,
2324 readonly Operator oper;
2325 Expression left, right;
2327 ConvCast.Mode enum_conversion;
2329 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
2330 : this (oper, left, right)
2333 state |= State.Compound;
2336 public Binary (Operator oper, Expression left, Expression right)
2341 this.loc = left.Location;
2346 public bool IsCompound {
2348 return (state & State.Compound) != 0;
2352 public Operator Oper {
2358 public Expression Left {
2364 public Expression Right {
2370 public override Location StartLocation {
2372 return left.StartLocation;
2379 /// Returns a stringified representation of the Operator
2381 string OperName (Operator oper)
2385 case Operator.Multiply:
2388 case Operator.Division:
2391 case Operator.Modulus:
2394 case Operator.Addition:
2397 case Operator.Subtraction:
2400 case Operator.LeftShift:
2403 case Operator.RightShift:
2406 case Operator.LessThan:
2409 case Operator.GreaterThan:
2412 case Operator.LessThanOrEqual:
2415 case Operator.GreaterThanOrEqual:
2418 case Operator.Equality:
2421 case Operator.Inequality:
2424 case Operator.BitwiseAnd:
2427 case Operator.BitwiseOr:
2430 case Operator.ExclusiveOr:
2433 case Operator.LogicalOr:
2436 case Operator.LogicalAnd:
2440 s = oper.ToString ();
2450 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2452 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2455 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2457 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
2461 l = left.Type.GetSignatureForError ();
2462 r = right.Type.GetSignatureForError ();
2464 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2468 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2470 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2474 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2476 string GetOperatorExpressionTypeName ()
2479 case Operator.Addition:
2480 return IsCompound ? "AddAssign" : "Add";
2481 case Operator.BitwiseAnd:
2482 return IsCompound ? "AndAssign" : "And";
2483 case Operator.BitwiseOr:
2484 return IsCompound ? "OrAssign" : "Or";
2485 case Operator.Division:
2486 return IsCompound ? "DivideAssign" : "Divide";
2487 case Operator.ExclusiveOr:
2488 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2489 case Operator.Equality:
2491 case Operator.GreaterThan:
2492 return "GreaterThan";
2493 case Operator.GreaterThanOrEqual:
2494 return "GreaterThanOrEqual";
2495 case Operator.Inequality:
2497 case Operator.LeftShift:
2498 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2499 case Operator.LessThan:
2501 case Operator.LessThanOrEqual:
2502 return "LessThanOrEqual";
2503 case Operator.LogicalAnd:
2505 case Operator.LogicalOr:
2507 case Operator.Modulus:
2508 return IsCompound ? "ModuloAssign" : "Modulo";
2509 case Operator.Multiply:
2510 return IsCompound ? "MultiplyAssign" : "Multiply";
2511 case Operator.RightShift:
2512 return IsCompound ? "RightShiftAssign" : "RightShift";
2513 case Operator.Subtraction:
2514 return IsCompound ? "SubtractAssign" : "Subtract";
2516 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2520 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2523 case Operator.Addition:
2524 return CSharp.Operator.OpType.Addition;
2525 case Operator.BitwiseAnd:
2526 case Operator.LogicalAnd:
2527 return CSharp.Operator.OpType.BitwiseAnd;
2528 case Operator.BitwiseOr:
2529 case Operator.LogicalOr:
2530 return CSharp.Operator.OpType.BitwiseOr;
2531 case Operator.Division:
2532 return CSharp.Operator.OpType.Division;
2533 case Operator.Equality:
2534 return CSharp.Operator.OpType.Equality;
2535 case Operator.ExclusiveOr:
2536 return CSharp.Operator.OpType.ExclusiveOr;
2537 case Operator.GreaterThan:
2538 return CSharp.Operator.OpType.GreaterThan;
2539 case Operator.GreaterThanOrEqual:
2540 return CSharp.Operator.OpType.GreaterThanOrEqual;
2541 case Operator.Inequality:
2542 return CSharp.Operator.OpType.Inequality;
2543 case Operator.LeftShift:
2544 return CSharp.Operator.OpType.LeftShift;
2545 case Operator.LessThan:
2546 return CSharp.Operator.OpType.LessThan;
2547 case Operator.LessThanOrEqual:
2548 return CSharp.Operator.OpType.LessThanOrEqual;
2549 case Operator.Modulus:
2550 return CSharp.Operator.OpType.Modulus;
2551 case Operator.Multiply:
2552 return CSharp.Operator.OpType.Multiply;
2553 case Operator.RightShift:
2554 return CSharp.Operator.OpType.RightShift;
2555 case Operator.Subtraction:
2556 return CSharp.Operator.OpType.Subtraction;
2558 throw new InternalErrorException (op.ToString ());
2562 public override bool ContainsEmitWithAwait ()
2564 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2567 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
2572 case Operator.Multiply:
2573 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2574 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2575 opcode = OpCodes.Mul_Ovf;
2576 else if (!IsFloat (l))
2577 opcode = OpCodes.Mul_Ovf_Un;
2579 opcode = OpCodes.Mul;
2581 opcode = OpCodes.Mul;
2585 case Operator.Division:
2587 opcode = OpCodes.Div_Un;
2589 opcode = OpCodes.Div;
2592 case Operator.Modulus:
2594 opcode = OpCodes.Rem_Un;
2596 opcode = OpCodes.Rem;
2599 case Operator.Addition:
2600 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2601 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2602 opcode = OpCodes.Add_Ovf;
2603 else if (!IsFloat (l))
2604 opcode = OpCodes.Add_Ovf_Un;
2606 opcode = OpCodes.Add;
2608 opcode = OpCodes.Add;
2611 case Operator.Subtraction:
2612 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2613 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2614 opcode = OpCodes.Sub_Ovf;
2615 else if (!IsFloat (l))
2616 opcode = OpCodes.Sub_Ovf_Un;
2618 opcode = OpCodes.Sub;
2620 opcode = OpCodes.Sub;
2623 case Operator.RightShift:
2624 if (!(right is IntConstant)) {
2625 ec.EmitInt (GetShiftMask (l));
2626 ec.Emit (OpCodes.And);
2630 opcode = OpCodes.Shr_Un;
2632 opcode = OpCodes.Shr;
2635 case Operator.LeftShift:
2636 if (!(right is IntConstant)) {
2637 ec.EmitInt (GetShiftMask (l));
2638 ec.Emit (OpCodes.And);
2641 opcode = OpCodes.Shl;
2644 case Operator.Equality:
2645 opcode = OpCodes.Ceq;
2648 case Operator.Inequality:
2649 ec.Emit (OpCodes.Ceq);
2652 opcode = OpCodes.Ceq;
2655 case Operator.LessThan:
2657 opcode = OpCodes.Clt_Un;
2659 opcode = OpCodes.Clt;
2662 case Operator.GreaterThan:
2664 opcode = OpCodes.Cgt_Un;
2666 opcode = OpCodes.Cgt;
2669 case Operator.LessThanOrEqual:
2670 if (IsUnsigned (l) || IsFloat (l))
2671 ec.Emit (OpCodes.Cgt_Un);
2673 ec.Emit (OpCodes.Cgt);
2676 opcode = OpCodes.Ceq;
2679 case Operator.GreaterThanOrEqual:
2680 if (IsUnsigned (l) || IsFloat (l))
2681 ec.Emit (OpCodes.Clt_Un);
2683 ec.Emit (OpCodes.Clt);
2687 opcode = OpCodes.Ceq;
2690 case Operator.BitwiseOr:
2691 opcode = OpCodes.Or;
2694 case Operator.BitwiseAnd:
2695 opcode = OpCodes.And;
2698 case Operator.ExclusiveOr:
2699 opcode = OpCodes.Xor;
2703 throw new InternalErrorException (oper.ToString ());
2709 static int GetShiftMask (TypeSpec type)
2711 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
2714 static bool IsUnsigned (TypeSpec t)
2716 switch (t.BuiltinType) {
2717 case BuiltinTypeSpec.Type.Char:
2718 case BuiltinTypeSpec.Type.UInt:
2719 case BuiltinTypeSpec.Type.ULong:
2720 case BuiltinTypeSpec.Type.UShort:
2721 case BuiltinTypeSpec.Type.Byte:
2728 static bool IsFloat (TypeSpec t)
2730 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2733 public Expression ResolveOperator (ResolveContext rc)
2735 eclass = ExprClass.Value;
2737 TypeSpec l = left.Type;
2738 TypeSpec r = right.Type;
2740 bool primitives_only = false;
2743 // Handles predefined primitive types
2745 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
2746 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
2747 if ((oper & Operator.ShiftMask) == 0) {
2748 if (!DoBinaryOperatorPromotion (rc))
2751 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
2755 if (l.IsPointer || r.IsPointer)
2756 return ResolveOperatorPointer (rc, l, r);
2759 expr = ResolveUserOperator (rc, left, right);
2764 bool lenum = l.IsEnum;
2765 bool renum = r.IsEnum;
2766 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2770 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2771 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
2776 if ((oper & Operator.BitwiseMask) != 0) {
2777 expr = EmptyCast.Create (expr, type);
2778 AddEnumResultCast (type);
2780 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
2781 expr = OptimizeAndOperation (expr);
2785 left = ConvertEnumOperandToUnderlyingType (rc, left);
2786 right = ConvertEnumOperandToUnderlyingType (rc, right);
2789 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
2790 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2794 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
2797 // We cannot break here there is also Enum + String possible match
2798 // which is not ambiguous with predefined enum operators
2801 left = ConvertEnumOperandToUnderlyingType (rc, left);
2802 right = ConvertEnumOperandToUnderlyingType (rc, right);
2806 } else if (l.IsDelegate || r.IsDelegate) {
2810 expr = ResolveOperatorDelegate (rc, l, r);
2812 // TODO: Can this be ambiguous
2820 // Equality operators are more complicated
2822 if ((oper & Operator.EqualityMask) != 0) {
2823 return ResolveEquality (rc, l, r, primitives_only);
2826 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
2830 if (primitives_only)
2834 // Lifted operators have lower priority
2836 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
2839 static bool IsEnumOrNullableEnum (TypeSpec type)
2841 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
2845 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2846 // if 'left' is not an enumeration constant, create one from the type of 'right'
2847 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2850 case Operator.BitwiseOr:
2851 case Operator.BitwiseAnd:
2852 case Operator.ExclusiveOr:
2853 case Operator.Equality:
2854 case Operator.Inequality:
2855 case Operator.LessThan:
2856 case Operator.LessThanOrEqual:
2857 case Operator.GreaterThan:
2858 case Operator.GreaterThanOrEqual:
2859 if (left.Type.IsEnum)
2862 if (left.IsZeroInteger)
2863 return left.Reduce (ec, right.Type);
2867 case Operator.Addition:
2868 case Operator.Subtraction:
2871 case Operator.Multiply:
2872 case Operator.Division:
2873 case Operator.Modulus:
2874 case Operator.LeftShift:
2875 case Operator.RightShift:
2876 if (right.Type.IsEnum || left.Type.IsEnum)
2885 // The `|' operator used on types which were extended is dangerous
2887 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2889 OpcodeCast lcast = left as OpcodeCast;
2890 if (lcast != null) {
2891 if (IsUnsigned (lcast.UnderlyingType))
2895 OpcodeCast rcast = right as OpcodeCast;
2896 if (rcast != null) {
2897 if (IsUnsigned (rcast.UnderlyingType))
2901 if (lcast == null && rcast == null)
2904 // FIXME: consider constants
2906 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
2907 ec.Report.Warning (675, 3, loc,
2908 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2909 ltype.GetSignatureForError ());
2912 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
2914 return new PredefinedOperator[] {
2916 // Pointer arithmetic:
2918 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2919 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2920 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2921 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2923 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
2924 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
2925 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
2926 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
2929 // T* operator + (int y, T* x);
2930 // T* operator + (uint y, T *x);
2931 // T* operator + (long y, T *x);
2932 // T* operator + (ulong y, T *x);
2934 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
2935 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
2936 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
2937 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
2940 // long operator - (T* x, T *y)
2942 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
2946 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
2948 TypeSpec bool_type = types.Bool;
2951 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
2952 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
2953 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
2954 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
2955 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
2956 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
2957 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
2959 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
2960 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
2961 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
2962 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
2963 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
2964 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
2965 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
2967 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
2968 // Remaining string operators are in lifted tables
2970 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
2972 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
2973 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
2974 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
2978 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
2980 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
2981 if (nullable == null)
2982 return new PredefinedOperator [0];
2984 var types = module.Compiler.BuiltinTypes;
2985 var bool_type = types.Bool;
2987 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
2988 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
2989 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
2990 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
2991 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
2992 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
2993 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
2994 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
2997 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
2998 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
2999 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3000 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3001 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3002 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3003 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3005 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3006 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3007 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3008 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3009 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3010 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3011 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3013 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3015 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3016 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3017 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3020 // Not strictly lifted but need to be in second group otherwise expressions like
3021 // int + null would resolve to +(object, string) instead of +(int?, int?)
3023 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3024 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3029 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3031 TypeSpec bool_type = types.Bool;
3034 new PredefinedEqualityOperator (types.String, bool_type),
3035 new PredefinedEqualityOperator (types.Delegate, bool_type),
3036 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3037 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3038 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3039 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3040 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3041 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3042 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3043 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3047 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3049 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3051 if (nullable == null)
3052 return new PredefinedOperator [0];
3054 var types = module.Compiler.BuiltinTypes;
3055 var bool_type = types.Bool;
3056 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3057 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3058 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3059 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3060 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3061 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3062 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3063 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3066 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3067 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3068 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3069 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3070 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3071 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3072 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3073 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3078 // 7.2.6.2 Binary numeric promotions
3080 bool DoBinaryOperatorPromotion (ResolveContext rc)
3082 TypeSpec ltype = left.Type;
3083 if (ltype.IsNullableType) {
3084 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
3088 // This is numeric promotion code only
3090 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
3093 TypeSpec rtype = right.Type;
3094 if (rtype.IsNullableType) {
3095 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
3098 var lb = ltype.BuiltinType;
3099 var rb = rtype.BuiltinType;
3103 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
3104 type = rc.BuiltinTypes.Decimal;
3105 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
3106 type = rc.BuiltinTypes.Double;
3107 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
3108 type = rc.BuiltinTypes.Float;
3109 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
3110 type = rc.BuiltinTypes.ULong;
3112 if (IsSignedType (lb)) {
3113 expr = ConvertSignedConstant (left, type);
3117 } else if (IsSignedType (rb)) {
3118 expr = ConvertSignedConstant (right, type);
3124 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
3125 type = rc.BuiltinTypes.Long;
3126 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
3127 type = rc.BuiltinTypes.UInt;
3129 if (IsSignedType (lb)) {
3130 expr = ConvertSignedConstant (left, type);
3132 type = rc.BuiltinTypes.Long;
3133 } else if (IsSignedType (rb)) {
3134 expr = ConvertSignedConstant (right, type);
3136 type = rc.BuiltinTypes.Long;
3139 type = rc.BuiltinTypes.Int;
3142 if (ltype != type) {
3143 expr = PromoteExpression (rc, left, type);
3150 if (rtype != type) {
3151 expr = PromoteExpression (rc, right, type);
3161 static bool IsSignedType (BuiltinTypeSpec.Type type)
3164 case BuiltinTypeSpec.Type.Int:
3165 case BuiltinTypeSpec.Type.Short:
3166 case BuiltinTypeSpec.Type.SByte:
3167 case BuiltinTypeSpec.Type.Long:
3174 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
3176 var c = expr as Constant;
3180 return c.ConvertImplicitly (type);
3183 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
3185 if (expr.Type.IsNullableType) {
3186 return Convert.ImplicitConversionStandard (rc, expr,
3187 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
3190 var c = expr as Constant;
3192 return c.ConvertImplicitly (type);
3194 return Convert.ImplicitNumericConversion (expr, type);
3197 protected override Expression DoResolve (ResolveContext ec)
3202 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
3203 left = ((ParenthesizedExpression) left).Expr;
3204 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
3208 if (left.eclass == ExprClass.Type) {
3209 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
3213 left = left.Resolve (ec);
3218 Constant lc = left as Constant;
3220 if (lc != null && lc.Type.BuiltinType == BuiltinTypeSpec.Type.Bool &&
3221 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
3222 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
3224 // FIXME: resolve right expression as unreachable
3225 // right.Resolve (ec);
3227 ec.Report.Warning (429, 4, right.StartLocation, "Unreachable expression code detected");
3231 right = right.Resolve (ec);
3235 Constant rc = right as Constant;
3237 // The conversion rules are ignored in enum context but why
3238 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
3239 lc = EnumLiftUp (ec, lc, rc, loc);
3241 rc = EnumLiftUp (ec, rc, lc, loc);
3244 if (rc != null && lc != null) {
3245 int prev_e = ec.Report.Errors;
3246 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
3247 if (e != null || ec.Report.Errors != prev_e)
3251 // Comparison warnings
3252 if ((oper & Operator.ComparisonMask) != 0) {
3253 if (left.Equals (right)) {
3254 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
3256 CheckOutOfRangeComparison (ec, lc, right.Type);
3257 CheckOutOfRangeComparison (ec, rc, left.Type);
3260 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3262 var rt = right.Type;
3263 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
3264 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
3265 Error_OperatorCannotBeApplied (ec, left, right);
3272 // Special handling for logical boolean operators which require rhs not to be
3273 // evaluated based on lhs value
3275 if ((oper & Operator.LogicalMask) != 0) {
3276 Expression cond_left, cond_right, expr;
3278 args = new Arguments (2);
3280 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3281 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, ec.CurrentBlock, loc);
3283 var cond_args = new Arguments (1);
3284 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left).Resolve (ec)));
3287 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
3288 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
3290 left = temp.CreateReferenceExpression (ec, loc);
3291 if (oper == Operator.LogicalAnd) {
3292 expr = DynamicUnaryConversion.CreateIsFalse (ec, cond_args, loc);
3295 expr = DynamicUnaryConversion.CreateIsTrue (ec, cond_args, loc);
3299 args.Add (new Argument (left));
3300 args.Add (new Argument (right));
3301 cond_right = new DynamicExpressionStatement (this, args, loc);
3303 LocalVariable temp = LocalVariable.CreateCompilerGenerated (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
3305 args.Add (new Argument (temp.CreateReferenceExpression (ec, loc).Resolve (ec)));
3306 args.Add (new Argument (right));
3307 right = new DynamicExpressionStatement (this, args, loc);
3310 // bool && dynamic => (temp = left) ? temp && right : temp;
3311 // bool || dynamic => (temp = left) ? temp : temp || right;
3313 if (oper == Operator.LogicalAnd) {
3315 cond_right = temp.CreateReferenceExpression (ec, loc);
3317 cond_left = temp.CreateReferenceExpression (ec, loc);
3321 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left));
3324 return new Conditional (expr, cond_left, cond_right, loc).Resolve (ec);
3327 args = new Arguments (2);
3328 args.Add (new Argument (left));
3329 args.Add (new Argument (right));
3330 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
3333 return DoResolveCore (ec, left, right);
3336 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3338 Expression expr = ResolveOperator (ec);
3340 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3342 if (left == null || right == null)
3343 throw new InternalErrorException ("Invalid conversion");
3345 if (oper == Operator.BitwiseOr)
3346 CheckBitwiseOrOnSignExtended (ec);
3351 public override SLE.Expression MakeExpression (BuilderContext ctx)
3353 return MakeExpression (ctx, left, right);
3356 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
3358 var le = left.MakeExpression (ctx);
3359 var re = right.MakeExpression (ctx);
3360 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3363 case Operator.Addition:
3364 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3365 case Operator.BitwiseAnd:
3366 return SLE.Expression.And (le, re);
3367 case Operator.BitwiseOr:
3368 return SLE.Expression.Or (le, re);
3369 case Operator.Division:
3370 return SLE.Expression.Divide (le, re);
3371 case Operator.Equality:
3372 return SLE.Expression.Equal (le, re);
3373 case Operator.ExclusiveOr:
3374 return SLE.Expression.ExclusiveOr (le, re);
3375 case Operator.GreaterThan:
3376 return SLE.Expression.GreaterThan (le, re);
3377 case Operator.GreaterThanOrEqual:
3378 return SLE.Expression.GreaterThanOrEqual (le, re);
3379 case Operator.Inequality:
3380 return SLE.Expression.NotEqual (le, re);
3381 case Operator.LeftShift:
3382 return SLE.Expression.LeftShift (le, re);
3383 case Operator.LessThan:
3384 return SLE.Expression.LessThan (le, re);
3385 case Operator.LessThanOrEqual:
3386 return SLE.Expression.LessThanOrEqual (le, re);
3387 case Operator.LogicalAnd:
3388 return SLE.Expression.AndAlso (le, re);
3389 case Operator.LogicalOr:
3390 return SLE.Expression.OrElse (le, re);
3391 case Operator.Modulus:
3392 return SLE.Expression.Modulo (le, re);
3393 case Operator.Multiply:
3394 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3395 case Operator.RightShift:
3396 return SLE.Expression.RightShift (le, re);
3397 case Operator.Subtraction:
3398 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3400 throw new NotImplementedException (oper.ToString ());
3405 // D operator + (D x, D y)
3406 // D operator - (D x, D y)
3408 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3410 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3412 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3413 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3418 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3419 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3429 MethodSpec method = null;
3430 Arguments args = new Arguments (2);
3431 args.Add (new Argument (left));
3432 args.Add (new Argument (right));
3434 if (oper == Operator.Addition) {
3435 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3436 } else if (oper == Operator.Subtraction) {
3437 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3441 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3443 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
3444 return new ClassCast (expr, l);
3448 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
3450 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3453 // bool operator == (E x, E y);
3454 // bool operator != (E x, E y);
3455 // bool operator < (E x, E y);
3456 // bool operator > (E x, E y);
3457 // bool operator <= (E x, E y);
3458 // bool operator >= (E x, E y);
3460 // E operator & (E x, E y);
3461 // E operator | (E x, E y);
3462 // E operator ^ (E x, E y);
3465 if ((oper & Operator.ComparisonMask) != 0) {
3466 type = rc.BuiltinTypes.Bool;
3472 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3478 if (ltype == rtype) {
3482 var lifted = new Nullable.LiftedBinaryOperator (this);
3484 lifted.Right = right;
3485 return lifted.Resolve (rc);
3488 if (renum && !ltype.IsNullableType) {
3489 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
3494 } else if (lenum && !rtype.IsNullableType) {
3495 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
3503 // Now try lifted version of predefined operator
3505 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
3506 if (nullable_type != null) {
3507 if (renum && !ltype.IsNullableType) {
3508 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
3510 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3513 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3516 if ((oper & Operator.BitwiseMask) != 0)
3520 if ((oper & Operator.BitwiseMask) != 0)
3521 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3523 return CreateLiftedValueTypeResult (rc, rtype);
3527 var lifted = new Nullable.LiftedBinaryOperator (this);
3529 lifted.Right = right;
3530 return lifted.Resolve (rc);
3532 } else if (lenum && !rtype.IsNullableType) {
3533 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
3535 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3538 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3541 if ((oper & Operator.BitwiseMask) != 0)
3545 if ((oper & Operator.BitwiseMask) != 0)
3546 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3548 return CreateLiftedValueTypeResult (rc, ltype);
3552 var lifted = new Nullable.LiftedBinaryOperator (this);
3554 lifted.Right = expr;
3555 return lifted.Resolve (rc);
3557 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
3559 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3560 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
3562 if ((oper & Operator.RelationalMask) != 0)
3563 return CreateLiftedValueTypeResult (rc, rtype);
3565 if ((oper & Operator.BitwiseMask) != 0)
3566 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3568 // Equality operators are valid between E? and null
3571 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
3577 var lifted = new Nullable.LiftedBinaryOperator (this);
3579 lifted.Right = right;
3580 return lifted.Resolve (rc);
3582 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
3584 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3585 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
3587 if ((oper & Operator.RelationalMask) != 0)
3588 return CreateLiftedValueTypeResult (rc, ltype);
3590 if ((oper & Operator.BitwiseMask) != 0)
3591 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3593 // Equality operators are valid between E? and null
3596 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
3602 var lifted = new Nullable.LiftedBinaryOperator (this);
3604 lifted.Right = expr;
3605 return lifted.Resolve (rc);
3613 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr)
3615 TypeSpec underlying_type;
3616 if (expr.Type.IsNullableType) {
3617 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
3619 underlying_type = EnumSpec.GetUnderlyingType (nt);
3621 underlying_type = nt;
3622 } else if (expr.Type.IsEnum) {
3623 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
3625 underlying_type = expr.Type;
3628 switch (underlying_type.BuiltinType) {
3629 case BuiltinTypeSpec.Type.SByte:
3630 case BuiltinTypeSpec.Type.Byte:
3631 case BuiltinTypeSpec.Type.Short:
3632 case BuiltinTypeSpec.Type.UShort:
3633 underlying_type = rc.BuiltinTypes.Int;
3637 if (expr.Type.IsNullableType)
3638 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
3640 if (expr.Type == underlying_type)
3643 return EmptyCast.Create (expr, underlying_type);
3646 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3649 // U operator - (E e, E f)
3650 // E operator - (E e, U x) // Internal decomposition operator
3651 // E operator - (U x, E e) // Internal decomposition operator
3653 // E operator + (E e, U x)
3654 // E operator + (U x, E e)
3663 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3669 if (!enum_type.IsNullableType) {
3670 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
3672 if (oper == Operator.Subtraction)
3673 expr = ConvertEnumSubtractionResult (rc, expr);
3675 expr = ConvertEnumAdditionalResult (expr, enum_type);
3677 AddEnumResultCast (expr.Type);
3682 enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
3685 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
3687 if (oper == Operator.Subtraction)
3688 expr = ConvertEnumSubtractionResult (rc, expr);
3690 expr = ConvertEnumAdditionalResult (expr, enum_type);
3692 AddEnumResultCast (expr.Type);
3698 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
3700 return EmptyCast.Create (expr, enumType);
3703 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
3706 // Enumeration subtraction has different result type based on
3709 TypeSpec result_type;
3710 if (left.Type == right.Type) {
3711 var c = right as EnumConstant;
3712 if (c != null && c.IsZeroInteger) {
3714 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
3715 // E which is not what expressions E - 1 or 0 - E return
3717 result_type = left.Type;
3719 result_type = left.Type.IsNullableType ?
3720 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
3721 EnumSpec.GetUnderlyingType (left.Type);
3724 if (IsEnumOrNullableEnum (left.Type)) {
3725 result_type = left.Type;
3727 result_type = right.Type;
3730 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
3731 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
3734 return EmptyCast.Create (expr, result_type);
3737 void AddEnumResultCast (TypeSpec type)
3739 if (type.IsNullableType)
3740 type = Nullable.NullableInfo.GetUnderlyingType (type);
3743 type = EnumSpec.GetUnderlyingType (type);
3745 switch (type.BuiltinType) {
3746 case BuiltinTypeSpec.Type.SByte:
3747 enum_conversion = ConvCast.Mode.I4_I1;
3749 case BuiltinTypeSpec.Type.Byte:
3750 enum_conversion = ConvCast.Mode.I4_U1;
3752 case BuiltinTypeSpec.Type.Short:
3753 enum_conversion = ConvCast.Mode.I4_I2;
3755 case BuiltinTypeSpec.Type.UShort:
3756 enum_conversion = ConvCast.Mode.I4_U2;
3762 // Equality operators rules
3764 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
3767 type = ec.BuiltinTypes.Bool;
3768 bool no_arg_conv = false;
3770 if (!primitives_only) {
3773 // a, Both operands are reference-type values or the value null
3774 // b, One operand is a value of type T where T is a type-parameter and
3775 // the other operand is the value null. Furthermore T does not have the
3776 // value type constraint
3778 // LAMESPEC: Very confusing details in the specification, basically any
3779 // reference like type-parameter is allowed
3781 var tparam_l = l as TypeParameterSpec;
3782 var tparam_r = r as TypeParameterSpec;
3783 if (tparam_l != null) {
3784 if (right is NullLiteral) {
3785 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3788 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3792 if (!tparam_l.IsReferenceType)
3795 l = tparam_l.GetEffectiveBase ();
3796 left = new BoxedCast (left, l);
3797 } else if (left is NullLiteral && tparam_r == null) {
3798 if (TypeSpec.IsReferenceType (r))
3801 if (r.Kind == MemberKind.InternalCompilerType)
3805 if (tparam_r != null) {
3806 if (left is NullLiteral) {
3807 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3810 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3814 if (!tparam_r.IsReferenceType)
3817 r = tparam_r.GetEffectiveBase ();
3818 right = new BoxedCast (right, r);
3819 } else if (right is NullLiteral) {
3820 if (TypeSpec.IsReferenceType (l))
3823 if (l.Kind == MemberKind.InternalCompilerType)
3828 // LAMESPEC: method groups can be compared when they convert to other side delegate
3831 if (right.eclass == ExprClass.MethodGroup) {
3832 result = Convert.ImplicitConversion (ec, right, l, loc);
3838 } else if (r.IsDelegate && l != r) {
3841 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3842 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3849 no_arg_conv = l == r && !l.IsStruct;
3854 // bool operator != (string a, string b)
3855 // bool operator == (string a, string b)
3857 // bool operator != (Delegate a, Delegate b)
3858 // bool operator == (Delegate a, Delegate b)
3860 // bool operator != (bool a, bool b)
3861 // bool operator == (bool a, bool b)
3863 // LAMESPEC: Reference equality comparison can apply to value/reference types when
3864 // they implement an implicit conversion to any of types above. This does
3865 // not apply when both operands are of same reference type
3867 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3868 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
3873 // Now try lifted version of predefined operators
3875 if (no_arg_conv && !l.IsNullableType) {
3877 // Optimizes cases which won't match
3880 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
3886 // The == and != operators permit one operand to be a value of a nullable
3887 // type and the other to be the null literal, even if no predefined or user-defined
3888 // operator (in unlifted or lifted form) exists for the operation.
3890 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
3891 var lifted = new Nullable.LiftedBinaryOperator (this);
3893 lifted.Right = right;
3894 return lifted.Resolve (ec);
3899 // bool operator != (object a, object b)
3900 // bool operator == (object a, object b)
3902 // An explicit reference conversion exists from the
3903 // type of either operand to the type of the other operand.
3906 // Optimize common path
3908 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3911 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3912 !Convert.ExplicitReferenceConversionExists (r, l))
3915 // Reject allowed explicit conversions like int->object
3916 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
3919 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3920 ec.Report.Warning (253, 2, loc,
3921 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3922 l.GetSignatureForError ());
3924 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3925 ec.Report.Warning (252, 2, loc,
3926 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3927 r.GetSignatureForError ());
3933 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3936 // bool operator == (void* x, void* y);
3937 // bool operator != (void* x, void* y);
3938 // bool operator < (void* x, void* y);
3939 // bool operator > (void* x, void* y);
3940 // bool operator <= (void* x, void* y);
3941 // bool operator >= (void* x, void* y);
3943 if ((oper & Operator.ComparisonMask) != 0) {
3946 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3953 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3959 type = ec.BuiltinTypes.Bool;
3963 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
3967 // Build-in operators method overloading
3969 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
3971 PredefinedOperator best_operator = null;
3972 TypeSpec l = left.Type;
3973 TypeSpec r = right.Type;
3974 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3976 foreach (PredefinedOperator po in operators) {
3977 if ((po.OperatorsMask & oper_mask) == 0)
3980 if (primitives_only) {
3981 if (!po.IsPrimitiveApplicable (l, r))
3984 if (!po.IsApplicable (ec, left, right))
3988 if (best_operator == null) {
3990 if (primitives_only)
3996 best_operator = po.ResolveBetterOperator (ec, best_operator);
3998 if (best_operator == null) {
3999 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4000 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4007 if (best_operator == null)
4010 var expr = best_operator.ConvertResult (ec, this);
4012 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) && !best_operator.IsLifted) {
4013 expr = OptimizeAndOperation (expr);
4020 // Optimize &/&& constant expressions with 0 value
4022 Expression OptimizeAndOperation (Expression expr)
4024 Constant rc = right as Constant;
4025 Constant lc = left as Constant;
4026 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4028 // The result is a constant with side-effect
4030 Constant side_effect = rc == null ?
4031 new SideEffectConstant (lc, right, loc) :
4032 new SideEffectConstant (rc, left, loc);
4034 return ReducedExpression.Create (side_effect, expr);
4041 // Value types can be compared with the null literal because of the lifting
4042 // language rules. However the result is always true or false.
4044 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4046 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4047 type = rc.BuiltinTypes.Bool;
4051 // FIXME: Handle side effect constants
4052 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4054 if ((Oper & Operator.EqualityMask) != 0) {
4055 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4056 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4058 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4059 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4066 // Performs user-operator overloading
4068 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4070 Expression oper_expr;
4072 var op = ConvertBinaryToUserOperator (oper);
4074 if (l.IsNullableType)
4075 l = Nullable.NullableInfo.GetUnderlyingType (l);
4077 if (r.IsNullableType)
4078 r = Nullable.NullableInfo.GetUnderlyingType (r);
4080 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
4081 IList<MemberSpec> right_operators = null;
4084 right_operators = MemberCache.GetUserOperator (r, op, false);
4085 if (right_operators == null && left_operators == null)
4087 } else if (left_operators == null) {
4091 Arguments args = new Arguments (2);
4092 Argument larg = new Argument (left);
4094 Argument rarg = new Argument (right);
4098 // User-defined operator implementations always take precedence
4099 // over predefined operator implementations
4101 if (left_operators != null && right_operators != null) {
4102 left_operators = CombineUserOperators (left_operators, right_operators);
4103 } else if (right_operators != null) {
4104 left_operators = right_operators;
4107 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
4108 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
4110 var res = new OverloadResolver (left_operators, restr, loc);
4112 var oper_method = res.ResolveOperator (rc, ref args);
4113 if (oper_method == null) {
4115 // Logical && and || cannot be lifted
4117 if ((oper & Operator.LogicalMask) != 0)
4121 // Apply lifted user operators only for liftable types. Implicit conversion
4122 // to nullable types is not allowed
4124 if (!IsLiftedOperatorApplicable ())
4127 // TODO: Cache the result in module container
4128 var lifted_methods = CreateLiftedOperators (rc, left_operators);
4129 if (lifted_methods == null)
4132 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
4134 oper_method = res.ResolveOperator (rc, ref args);
4135 if (oper_method == null)
4138 MethodSpec best_original = null;
4139 foreach (MethodSpec ms in left_operators) {
4140 if (ms.MemberDefinition == oper_method.MemberDefinition) {
4146 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4148 // Expression trees use lifted notation in this case
4150 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
4151 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
4154 var ptypes = best_original.Parameters.Types;
4156 if (left.IsNull || right.IsNull) {
4158 // The lifted operator produces the value false if one or both operands are null for
4159 // relational operators.
4161 if ((oper & Operator.ComparisonMask) != 0) {
4163 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
4164 // because return type is actually bool
4166 // For some reason CSC does not report this warning for equality operators
4168 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
4171 // The lifted operator produces a null value if one or both operands are null
4173 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
4174 type = oper_method.ReturnType;
4175 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4179 type = oper_method.ReturnType;
4180 var lifted = new Nullable.LiftedBinaryOperator (this);
4181 lifted.UserOperator = best_original;
4183 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
4184 lifted.UnwrapLeft = new Nullable.Unwrap (left);
4187 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
4188 lifted.UnwrapRight = new Nullable.Unwrap (right);
4191 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
4192 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
4194 return lifted.Resolve (rc);
4197 if ((oper & Operator.LogicalMask) != 0) {
4198 // TODO: CreateExpressionTree is allocated every time
4199 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
4200 oper == Operator.LogicalAnd, loc).Resolve (rc);
4202 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
4205 this.left = larg.Expr;
4206 this.right = rarg.Expr;
4211 bool IsLiftedOperatorApplicable ()
4213 if (left.Type.IsNullableType) {
4214 if ((oper & Operator.EqualityMask) != 0)
4215 return !right.IsNull;
4220 if (right.Type.IsNullableType) {
4221 if ((oper & Operator.EqualityMask) != 0)
4222 return !left.IsNull;
4227 if (TypeSpec.IsValueType (left.Type))
4228 return right.IsNull;
4230 if (TypeSpec.IsValueType (right.Type))
4236 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
4238 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4239 if (nullable_type == null)
4243 // Lifted operators permit predefined and user-defined operators that operate
4244 // on non-nullable value types to also be used with nullable forms of those types.
4245 // Lifted operators are constructed from predefined and user-defined operators
4246 // that meet certain requirements
4248 List<MemberSpec> lifted = null;
4249 foreach (MethodSpec oper in operators) {
4251 if ((Oper & Operator.ComparisonMask) != 0) {
4253 // Result type must be of type bool for lifted comparison operators
4255 rt = oper.ReturnType;
4256 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
4259 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
4265 var ptypes = oper.Parameters.Types;
4266 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
4270 // LAMESPEC: I am not sure why but for equality operators to be lifted
4271 // both types have to match
4273 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
4277 lifted = new List<MemberSpec> ();
4280 // The lifted form is constructed by adding a single ? modifier to each operand and
4281 // result type except for comparison operators where return type is bool
4284 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
4286 var parameters = ParametersCompiled.CreateFullyResolved (
4287 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
4288 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
4290 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
4291 rt, parameters, oper.Modifiers);
4293 lifted.Add (lifted_op);
4300 // Merge two sets of user operators into one, they are mostly distinguish
4301 // except when they share base type and it contains an operator
4303 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
4305 var combined = new List<MemberSpec> (left.Count + right.Count);
4306 combined.AddRange (left);
4307 foreach (var r in right) {
4309 foreach (var l in left) {
4310 if (l.DeclaringType == r.DeclaringType) {
4323 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
4325 if (c is IntegralConstant || c is CharConstant) {
4327 c.ConvertExplicitly (true, type);
4328 } catch (OverflowException) {
4329 ec.Report.Warning (652, 2, loc,
4330 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
4331 type.GetSignatureForError ());
4337 /// EmitBranchable is called from Statement.EmitBoolExpression in the
4338 /// context of a conditional bool expression. This function will return
4339 /// false if it is was possible to use EmitBranchable, or true if it was.
4341 /// The expression's code is generated, and we will generate a branch to `target'
4342 /// if the resulting expression value is equal to isTrue
4344 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
4346 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4347 left = left.EmitToField (ec);
4349 if ((oper & Operator.LogicalMask) == 0) {
4350 right = right.EmitToField (ec);
4355 // This is more complicated than it looks, but its just to avoid
4356 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
4357 // but on top of that we want for == and != to use a special path
4358 // if we are comparing against null
4360 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
4361 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
4364 // put the constant on the rhs, for simplicity
4366 if (left is Constant) {
4367 Expression swap = right;
4373 // brtrue/brfalse works with native int only
4375 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
4376 left.EmitBranchable (ec, target, my_on_true);
4379 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
4380 // right is a boolean, and it's not 'false' => it is 'true'
4381 left.EmitBranchable (ec, target, !my_on_true);
4385 } else if (oper == Operator.LogicalAnd) {
4388 Label tests_end = ec.DefineLabel ();
4390 left.EmitBranchable (ec, tests_end, false);
4391 right.EmitBranchable (ec, target, true);
4392 ec.MarkLabel (tests_end);
4395 // This optimizes code like this
4396 // if (true && i > 4)
4398 if (!(left is Constant))
4399 left.EmitBranchable (ec, target, false);
4401 if (!(right is Constant))
4402 right.EmitBranchable (ec, target, false);
4407 } else if (oper == Operator.LogicalOr){
4409 left.EmitBranchable (ec, target, true);
4410 right.EmitBranchable (ec, target, true);
4413 Label tests_end = ec.DefineLabel ();
4414 left.EmitBranchable (ec, tests_end, true);
4415 right.EmitBranchable (ec, target, false);
4416 ec.MarkLabel (tests_end);
4421 } else if ((oper & Operator.ComparisonMask) == 0) {
4422 base.EmitBranchable (ec, target, on_true);
4429 TypeSpec t = left.Type;
4430 bool is_float = IsFloat (t);
4431 bool is_unsigned = is_float || IsUnsigned (t);
4434 case Operator.Equality:
4436 ec.Emit (OpCodes.Beq, target);
4438 ec.Emit (OpCodes.Bne_Un, target);
4441 case Operator.Inequality:
4443 ec.Emit (OpCodes.Bne_Un, target);
4445 ec.Emit (OpCodes.Beq, target);
4448 case Operator.LessThan:
4450 if (is_unsigned && !is_float)
4451 ec.Emit (OpCodes.Blt_Un, target);
4453 ec.Emit (OpCodes.Blt, target);
4456 ec.Emit (OpCodes.Bge_Un, target);
4458 ec.Emit (OpCodes.Bge, target);
4461 case Operator.GreaterThan:
4463 if (is_unsigned && !is_float)
4464 ec.Emit (OpCodes.Bgt_Un, target);
4466 ec.Emit (OpCodes.Bgt, target);
4469 ec.Emit (OpCodes.Ble_Un, target);
4471 ec.Emit (OpCodes.Ble, target);
4474 case Operator.LessThanOrEqual:
4476 if (is_unsigned && !is_float)
4477 ec.Emit (OpCodes.Ble_Un, target);
4479 ec.Emit (OpCodes.Ble, target);
4482 ec.Emit (OpCodes.Bgt_Un, target);
4484 ec.Emit (OpCodes.Bgt, target);
4488 case Operator.GreaterThanOrEqual:
4490 if (is_unsigned && !is_float)
4491 ec.Emit (OpCodes.Bge_Un, target);
4493 ec.Emit (OpCodes.Bge, target);
4496 ec.Emit (OpCodes.Blt_Un, target);
4498 ec.Emit (OpCodes.Blt, target);
4501 throw new InternalErrorException (oper.ToString ());
4505 public override void Emit (EmitContext ec)
4507 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4508 left = left.EmitToField (ec);
4510 if ((oper & Operator.LogicalMask) == 0) {
4511 right = right.EmitToField (ec);
4516 // Handle short-circuit operators differently
4519 if ((oper & Operator.LogicalMask) != 0) {
4520 Label load_result = ec.DefineLabel ();
4521 Label end = ec.DefineLabel ();
4523 bool is_or = oper == Operator.LogicalOr;
4524 left.EmitBranchable (ec, load_result, is_or);
4526 ec.Emit (OpCodes.Br_S, end);
4528 ec.MarkLabel (load_result);
4529 ec.EmitInt (is_or ? 1 : 0);
4535 // Optimize zero-based operations which cannot be optimized at expression level
4537 if (oper == Operator.Subtraction) {
4538 var lc = left as IntegralConstant;
4539 if (lc != null && lc.IsDefaultValue) {
4541 ec.Emit (OpCodes.Neg);
4546 EmitOperator (ec, left, right);
4549 public void EmitOperator (EmitContext ec, Expression left, Expression right)
4554 EmitOperatorOpcode (ec, oper, left.Type, right);
4557 // Emit result enumerable conversion this way because it's quite complicated get it
4558 // to resolved tree because expression tree cannot see it.
4560 if (enum_conversion != 0)
4561 ConvCast.Emit (ec, enum_conversion);
4564 public override void EmitSideEffect (EmitContext ec)
4566 if ((oper & Operator.LogicalMask) != 0 ||
4567 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
4568 base.EmitSideEffect (ec);
4570 left.EmitSideEffect (ec);
4571 right.EmitSideEffect (ec);
4575 public override Expression EmitToField (EmitContext ec)
4577 if ((oper & Operator.LogicalMask) == 0) {
4578 var await_expr = left as Await;
4579 if (await_expr != null && right.IsSideEffectFree) {
4580 await_expr.Statement.EmitPrologue (ec);
4581 left = await_expr.Statement.GetResultExpression (ec);
4585 await_expr = right as Await;
4586 if (await_expr != null && left.IsSideEffectFree) {
4587 await_expr.Statement.EmitPrologue (ec);
4588 right = await_expr.Statement.GetResultExpression (ec);
4593 return base.EmitToField (ec);
4596 protected override void CloneTo (CloneContext clonectx, Expression t)
4598 Binary target = (Binary) t;
4600 target.left = left.Clone (clonectx);
4601 target.right = right.Clone (clonectx);
4604 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
4606 Arguments binder_args = new Arguments (4);
4608 MemberAccess sle = new MemberAccess (new MemberAccess (
4609 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
4611 CSharpBinderFlags flags = 0;
4612 if (ec.HasSet (ResolveContext.Options.CheckedScope))
4613 flags = CSharpBinderFlags.CheckedContext;
4615 if ((oper & Operator.LogicalMask) != 0)
4616 flags |= CSharpBinderFlags.BinaryOperationLogical;
4618 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
4619 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
4620 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
4621 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
4623 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
4626 public override Expression CreateExpressionTree (ResolveContext ec)
4628 return CreateExpressionTree (ec, null);
4631 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
4634 bool lift_arg = false;
4637 case Operator.Addition:
4638 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4639 method_name = "AddChecked";
4641 method_name = "Add";
4643 case Operator.BitwiseAnd:
4644 method_name = "And";
4646 case Operator.BitwiseOr:
4649 case Operator.Division:
4650 method_name = "Divide";
4652 case Operator.Equality:
4653 method_name = "Equal";
4656 case Operator.ExclusiveOr:
4657 method_name = "ExclusiveOr";
4659 case Operator.GreaterThan:
4660 method_name = "GreaterThan";
4663 case Operator.GreaterThanOrEqual:
4664 method_name = "GreaterThanOrEqual";
4667 case Operator.Inequality:
4668 method_name = "NotEqual";
4671 case Operator.LeftShift:
4672 method_name = "LeftShift";
4674 case Operator.LessThan:
4675 method_name = "LessThan";
4678 case Operator.LessThanOrEqual:
4679 method_name = "LessThanOrEqual";
4682 case Operator.LogicalAnd:
4683 method_name = "AndAlso";
4685 case Operator.LogicalOr:
4686 method_name = "OrElse";
4688 case Operator.Modulus:
4689 method_name = "Modulo";
4691 case Operator.Multiply:
4692 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4693 method_name = "MultiplyChecked";
4695 method_name = "Multiply";
4697 case Operator.RightShift:
4698 method_name = "RightShift";
4700 case Operator.Subtraction:
4701 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4702 method_name = "SubtractChecked";
4704 method_name = "Subtract";
4708 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4711 Arguments args = new Arguments (2);
4712 args.Add (new Argument (left.CreateExpressionTree (ec)));
4713 args.Add (new Argument (right.CreateExpressionTree (ec)));
4714 if (method != null) {
4716 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4718 args.Add (new Argument (method));
4721 return CreateExpressionFactoryCall (ec, method_name, args);
4724 public override object Accept (StructuralVisitor visitor)
4726 return visitor.Visit (this);
4732 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4733 // b, c, d... may be strings or objects.
4735 public class StringConcat : Expression
4737 Arguments arguments;
4739 StringConcat (Location loc)
4742 arguments = new Arguments (2);
4745 public override bool ContainsEmitWithAwait ()
4747 return arguments.ContainsEmitWithAwait ();
4750 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4752 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4753 throw new ArgumentException ();
4755 var s = new StringConcat (loc);
4756 s.type = rc.BuiltinTypes.String;
4757 s.eclass = ExprClass.Value;
4759 s.Append (rc, left);
4760 s.Append (rc, right);
4764 public override Expression CreateExpressionTree (ResolveContext ec)
4766 Argument arg = arguments [0];
4767 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4771 // Creates nested calls tree from an array of arguments used for IL emit
4773 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4775 Arguments concat_args = new Arguments (2);
4776 Arguments add_args = new Arguments (3);
4778 concat_args.Add (left);
4779 add_args.Add (new Argument (left_etree));
4781 concat_args.Add (arguments [pos]);
4782 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4784 var methods = GetConcatMethodCandidates ();
4785 if (methods == null)
4788 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4789 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4793 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4795 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4796 if (++pos == arguments.Count)
4799 left = new Argument (new EmptyExpression (method.ReturnType));
4800 return CreateExpressionAddCall (ec, left, expr, pos);
4803 protected override Expression DoResolve (ResolveContext ec)
4808 void Append (ResolveContext rc, Expression operand)
4813 StringConstant sc = operand as StringConstant;
4815 if (arguments.Count != 0) {
4816 Argument last_argument = arguments [arguments.Count - 1];
4817 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4818 if (last_expr_constant != null) {
4819 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4825 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4827 StringConcat concat_oper = operand as StringConcat;
4828 if (concat_oper != null) {
4829 arguments.AddRange (concat_oper.arguments);
4834 arguments.Add (new Argument (operand));
4837 IList<MemberSpec> GetConcatMethodCandidates ()
4839 return MemberCache.FindMembers (type, "Concat", true);
4842 public override void Emit (EmitContext ec)
4844 // Optimize by removing any extra null arguments, they are no-op
4845 for (int i = 0; i < arguments.Count; ++i) {
4846 if (arguments[i].Expr is NullConstant)
4847 arguments.RemoveAt (i--);
4850 var members = GetConcatMethodCandidates ();
4851 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4852 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4853 if (method != null) {
4854 var call = new CallEmitter ();
4855 call.EmitPredefined (ec, method, arguments);
4859 public override SLE.Expression MakeExpression (BuilderContext ctx)
4861 if (arguments.Count != 2)
4862 throw new NotImplementedException ("arguments.Count != 2");
4864 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4865 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4870 // User-defined conditional logical operator
4872 public class ConditionalLogicalOperator : UserOperatorCall
4874 readonly bool is_and;
4875 Expression oper_expr;
4877 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4878 : base (oper, arguments, expr_tree, loc)
4880 this.is_and = is_and;
4881 eclass = ExprClass.Unresolved;
4884 protected override Expression DoResolve (ResolveContext ec)
4886 AParametersCollection pd = oper.Parameters;
4887 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4888 ec.Report.Error (217, loc,
4889 "A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
4890 oper.GetSignatureForError ());
4894 Expression left_dup = new EmptyExpression (type);
4895 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4896 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4897 if (op_true == null || op_false == null) {
4898 ec.Report.Error (218, loc,
4899 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4900 type.GetSignatureForError (), oper.GetSignatureForError ());
4904 oper_expr = is_and ? op_false : op_true;
4905 eclass = ExprClass.Value;
4909 public override void Emit (EmitContext ec)
4911 Label end_target = ec.DefineLabel ();
4914 // Emit and duplicate left argument
4916 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
4917 if (right_contains_await) {
4918 arguments[0] = arguments[0].EmitToField (ec, false);
4919 arguments[0].Expr.Emit (ec);
4921 arguments[0].Expr.Emit (ec);
4922 ec.Emit (OpCodes.Dup);
4923 arguments.RemoveAt (0);
4926 oper_expr.EmitBranchable (ec, end_target, true);
4930 if (right_contains_await) {
4932 // Special handling when right expression contains await and left argument
4933 // could not be left on stack before logical branch
4935 Label skip_left_load = ec.DefineLabel ();
4936 ec.Emit (OpCodes.Br_S, skip_left_load);
4937 ec.MarkLabel (end_target);
4938 arguments[0].Expr.Emit (ec);
4939 ec.MarkLabel (skip_left_load);
4941 ec.MarkLabel (end_target);
4946 public class PointerArithmetic : Expression {
4947 Expression left, right;
4951 // We assume that `l' is always a pointer
4953 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4962 public override bool ContainsEmitWithAwait ()
4964 throw new NotImplementedException ();
4967 public override Expression CreateExpressionTree (ResolveContext ec)
4969 Error_PointerInsideExpressionTree (ec);
4973 protected override Expression DoResolve (ResolveContext ec)
4975 eclass = ExprClass.Variable;
4977 var pc = left.Type as PointerContainer;
4978 if (pc != null && pc.Element.Kind == MemberKind.Void) {
4979 Error_VoidPointerOperation (ec);
4986 public override void Emit (EmitContext ec)
4988 TypeSpec op_type = left.Type;
4990 // It must be either array or fixed buffer
4992 if (TypeManager.HasElementType (op_type)) {
4993 element = TypeManager.GetElementType (op_type);
4995 FieldExpr fe = left as FieldExpr;
4997 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5002 int size = BuiltinTypeSpec.GetSize(element);
5003 TypeSpec rtype = right.Type;
5005 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5007 // handle (pointer - pointer)
5011 ec.Emit (OpCodes.Sub);
5015 ec.Emit (OpCodes.Sizeof, element);
5018 ec.Emit (OpCodes.Div);
5020 ec.Emit (OpCodes.Conv_I8);
5023 // handle + and - on (pointer op int)
5025 Constant left_const = left as Constant;
5026 if (left_const != null) {
5028 // Optimize ((T*)null) pointer operations
5030 if (left_const.IsDefaultValue) {
5031 left = EmptyExpression.Null;
5039 var right_const = right as Constant;
5040 if (right_const != null) {
5042 // Optimize 0-based arithmetic
5044 if (right_const.IsDefaultValue)
5048 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5050 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5052 // TODO: Should be the checks resolve context sensitive?
5053 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5054 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5060 switch (rtype.BuiltinType) {
5061 case BuiltinTypeSpec.Type.SByte:
5062 case BuiltinTypeSpec.Type.Byte:
5063 case BuiltinTypeSpec.Type.Short:
5064 case BuiltinTypeSpec.Type.UShort:
5065 ec.Emit (OpCodes.Conv_I);
5067 case BuiltinTypeSpec.Type.UInt:
5068 ec.Emit (OpCodes.Conv_U);
5072 if (right_const == null && size != 1){
5074 ec.Emit (OpCodes.Sizeof, element);
5077 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5078 ec.Emit (OpCodes.Conv_I8);
5080 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
5083 if (left_const == null) {
5084 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
5085 ec.Emit (OpCodes.Conv_I);
5086 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5087 ec.Emit (OpCodes.Conv_U);
5089 Binary.EmitOperatorOpcode (ec, op, op_type, right);
5096 // A boolean-expression is an expression that yields a result
5099 public class BooleanExpression : ShimExpression
5101 public BooleanExpression (Expression expr)
5104 this.loc = expr.Location;
5107 public override Expression CreateExpressionTree (ResolveContext ec)
5109 // TODO: We should emit IsTrue (v4) instead of direct user operator
5110 // call but that would break csc compatibility
5111 return base.CreateExpressionTree (ec);
5114 protected override Expression DoResolve (ResolveContext ec)
5116 // A boolean-expression is required to be of a type
5117 // that can be implicitly converted to bool or of
5118 // a type that implements operator true
5120 expr = expr.Resolve (ec);
5124 Assign ass = expr as Assign;
5125 if (ass != null && ass.Source is Constant) {
5126 ec.Report.Warning (665, 3, loc,
5127 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
5130 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
5133 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5134 Arguments args = new Arguments (1);
5135 args.Add (new Argument (expr));
5136 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
5139 type = ec.BuiltinTypes.Bool;
5140 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
5141 if (converted != null)
5145 // If no implicit conversion to bool exists, try using `operator true'
5147 converted = GetOperatorTrue (ec, expr, loc);
5148 if (converted == null) {
5149 expr.Error_ValueCannotBeConverted (ec, type, false);
5156 public override object Accept (StructuralVisitor visitor)
5158 return visitor.Visit (this);
5162 public class BooleanExpressionFalse : Unary
5164 public BooleanExpressionFalse (Expression expr)
5165 : base (Operator.LogicalNot, expr, expr.Location)
5169 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
5171 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
5176 /// Implements the ternary conditional operator (?:)
5178 public class Conditional : Expression {
5179 Expression expr, true_expr, false_expr;
5181 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
5184 this.true_expr = true_expr;
5185 this.false_expr = false_expr;
5191 public Expression Expr {
5197 public Expression TrueExpr {
5203 public Expression FalseExpr {
5211 public override bool ContainsEmitWithAwait ()
5213 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
5216 public override Expression CreateExpressionTree (ResolveContext ec)
5218 Arguments args = new Arguments (3);
5219 args.Add (new Argument (expr.CreateExpressionTree (ec)));
5220 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
5221 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
5222 return CreateExpressionFactoryCall (ec, "Condition", args);
5225 protected override Expression DoResolve (ResolveContext ec)
5227 expr = expr.Resolve (ec);
5230 // Unreachable code needs different resolve path. For instance for await
5231 // expression to not generate unreachable resumable statement
5233 Constant c = expr as Constant;
5234 if (c != null && ec.CurrentBranching != null) {
5235 bool unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
5237 if (c.IsDefaultValue) {
5238 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
5239 true_expr = true_expr.Resolve (ec);
5240 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
5242 false_expr = false_expr.Resolve (ec);
5244 true_expr = true_expr.Resolve (ec);
5246 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
5247 false_expr = false_expr.Resolve (ec);
5248 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
5251 true_expr = true_expr.Resolve (ec);
5252 false_expr = false_expr.Resolve (ec);
5255 if (true_expr == null || false_expr == null || expr == null)
5258 eclass = ExprClass.Value;
5259 TypeSpec true_type = true_expr.Type;
5260 TypeSpec false_type = false_expr.Type;
5264 // First, if an implicit conversion exists from true_expr
5265 // to false_expr, then the result type is of type false_expr.Type
5267 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
5268 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
5269 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5271 // Check if both can convert implicitly to each other's type
5275 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5276 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
5278 // LAMESPEC: There seems to be hardcoded promotition to int type when
5279 // both sides are numeric constants and one side is int constant and
5280 // other side is numeric constant convertible to int.
5282 // var res = condition ? (short)1 : 1;
5284 // Type of res is int even if according to the spec the conversion is
5285 // ambiguous because 1 literal can be converted to short.
5287 if (conv_false_expr != null) {
5288 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
5290 conv_false_expr = null;
5291 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
5292 conv_false_expr = null;
5296 if (conv_false_expr != null) {
5297 ec.Report.Error (172, true_expr.Location,
5298 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
5299 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5304 if (true_expr.Type != type)
5305 true_expr = EmptyCast.Create (true_expr, type);
5306 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
5309 ec.Report.Error (173, true_expr.Location,
5310 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
5311 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5317 bool is_false = c.IsDefaultValue;
5320 // Don't issue the warning for constant expressions
5322 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
5323 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location,
5324 "Unreachable expression code detected");
5327 return ReducedExpression.Create (
5328 is_false ? false_expr : true_expr, this,
5329 false_expr is Constant && true_expr is Constant).Resolve (ec);
5335 public override void Emit (EmitContext ec)
5337 Label false_target = ec.DefineLabel ();
5338 Label end_target = ec.DefineLabel ();
5340 expr.EmitBranchable (ec, false_target, false);
5341 true_expr.Emit (ec);
5344 // Verifier doesn't support interface merging. When there are two types on
5345 // the stack without common type hint and the common type is an interface.
5346 // Use temporary local to give verifier hint on what type to unify the stack
5348 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
5349 var temp = ec.GetTemporaryLocal (type);
5350 ec.Emit (OpCodes.Stloc, temp);
5351 ec.Emit (OpCodes.Ldloc, temp);
5352 ec.FreeTemporaryLocal (temp, type);
5355 ec.Emit (OpCodes.Br, end_target);
5356 ec.MarkLabel (false_target);
5357 false_expr.Emit (ec);
5358 ec.MarkLabel (end_target);
5361 protected override void CloneTo (CloneContext clonectx, Expression t)
5363 Conditional target = (Conditional) t;
5365 target.expr = expr.Clone (clonectx);
5366 target.true_expr = true_expr.Clone (clonectx);
5367 target.false_expr = false_expr.Clone (clonectx);
5371 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
5373 LocalTemporary temp;
5376 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
5377 public abstract void SetHasAddressTaken ();
5378 public abstract void VerifyAssigned (ResolveContext rc);
5380 public abstract bool IsLockedByStatement { get; set; }
5382 public abstract bool IsFixed { get; }
5383 public abstract bool IsRef { get; }
5384 public abstract string Name { get; }
5387 // Variable IL data, it has to be protected to encapsulate hoisted variables
5389 protected abstract ILocalVariable Variable { get; }
5392 // Variable flow-analysis data
5394 public abstract VariableInfo VariableInfo { get; }
5397 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5399 HoistedVariable hv = GetHoistedVariable (ec);
5401 hv.AddressOf (ec, mode);
5405 Variable.EmitAddressOf (ec);
5408 public override bool ContainsEmitWithAwait ()
5413 public override Expression CreateExpressionTree (ResolveContext ec)
5415 HoistedVariable hv = GetHoistedVariable (ec);
5417 return hv.CreateExpressionTree ();
5419 Arguments arg = new Arguments (1);
5420 arg.Add (new Argument (this));
5421 return CreateExpressionFactoryCall (ec, "Constant", arg);
5424 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
5426 if (IsLockedByStatement) {
5427 rc.Report.Warning (728, 2, loc,
5428 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
5435 public override void Emit (EmitContext ec)
5440 public override void EmitSideEffect (EmitContext ec)
5446 // This method is used by parameters that are references, that are
5447 // being passed as references: we only want to pass the pointer (that
5448 // is already stored in the parameter, not the address of the pointer,
5449 // and not the value of the variable).
5451 public void EmitLoad (EmitContext ec)
5456 public void Emit (EmitContext ec, bool leave_copy)
5458 HoistedVariable hv = GetHoistedVariable (ec);
5460 hv.Emit (ec, leave_copy);
5468 // If we are a reference, we loaded on the stack a pointer
5469 // Now lets load the real value
5471 ec.EmitLoadFromPtr (type);
5475 ec.Emit (OpCodes.Dup);
5478 temp = new LocalTemporary (Type);
5484 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
5485 bool prepare_for_load)
5487 HoistedVariable hv = GetHoistedVariable (ec);
5489 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
5493 New n_source = source as New;
5494 if (n_source != null) {
5495 if (!n_source.Emit (ec, this)) {
5499 ec.EmitLoadFromPtr (type);
5511 ec.Emit (OpCodes.Dup);
5513 temp = new LocalTemporary (Type);
5519 ec.EmitStoreFromPtr (type);
5521 Variable.EmitAssign (ec);
5529 public override Expression EmitToField (EmitContext ec)
5531 HoistedVariable hv = GetHoistedVariable (ec);
5533 return hv.EmitToField (ec);
5536 return base.EmitToField (ec);
5539 public HoistedVariable GetHoistedVariable (ResolveContext rc)
5541 return GetHoistedVariable (rc.CurrentAnonymousMethod);
5544 public HoistedVariable GetHoistedVariable (EmitContext ec)
5546 return GetHoistedVariable (ec.CurrentAnonymousMethod);
5549 public override string GetSignatureForError ()
5554 public bool IsHoisted {
5555 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
5560 // Resolved reference to a local variable
5562 public class LocalVariableReference : VariableReference
5564 public LocalVariable local_info;
5566 public LocalVariableReference (LocalVariable li, Location l)
5568 this.local_info = li;
5572 public override VariableInfo VariableInfo {
5573 get { return local_info.VariableInfo; }
5576 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5578 return local_info.HoistedVariant;
5584 // A local variable is always fixed
5586 public override bool IsFixed {
5592 public override bool IsLockedByStatement {
5594 return local_info.IsLocked;
5597 local_info.IsLocked = value;
5601 public override bool IsRef {
5602 get { return false; }
5605 public override string Name {
5606 get { return local_info.Name; }
5611 public override void VerifyAssigned (ResolveContext rc)
5613 VariableInfo variable_info = local_info.VariableInfo;
5614 if (variable_info == null)
5617 if (variable_info.IsAssigned (rc))
5620 rc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
5621 variable_info.SetAssigned (rc);
5624 public override void SetHasAddressTaken ()
5626 local_info.SetHasAddressTaken ();
5629 void DoResolveBase (ResolveContext ec)
5632 // If we are referencing a variable from the external block
5633 // flag it for capturing
5635 if (ec.MustCaptureVariable (local_info)) {
5636 if (local_info.AddressTaken) {
5637 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5638 } else if (local_info.IsFixed) {
5639 ec.Report.Error (1764, loc,
5640 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
5641 GetSignatureForError ());
5644 if (ec.IsVariableCapturingRequired) {
5645 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
5646 storey.CaptureLocalVariable (ec, local_info);
5650 eclass = ExprClass.Variable;
5651 type = local_info.Type;
5654 protected override Expression DoResolve (ResolveContext ec)
5656 local_info.SetIsUsed ();
5658 VerifyAssigned (ec);
5664 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5667 // Don't be too pedantic when variable is used as out param or for some broken code
5668 // which uses property/indexer access to run some initialization
5670 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5671 local_info.SetIsUsed ();
5673 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5676 if (rhs == EmptyExpression.OutAccess) {
5677 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5678 } else if (rhs == EmptyExpression.LValueMemberAccess) {
5679 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
5680 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5681 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5682 } else if (rhs == EmptyExpression.UnaryAddress) {
5683 code = 459; msg = "Cannot take the address of {1} `{0}'";
5685 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5687 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5688 } else if (VariableInfo != null) {
5689 VariableInfo.SetAssigned (ec);
5692 if (eclass == ExprClass.Unresolved)
5695 return base.DoResolveLValue (ec, rhs);
5698 public override int GetHashCode ()
5700 return local_info.GetHashCode ();
5703 public override bool Equals (object obj)
5705 LocalVariableReference lvr = obj as LocalVariableReference;
5709 return local_info == lvr.local_info;
5712 protected override ILocalVariable Variable {
5713 get { return local_info; }
5716 public override string ToString ()
5718 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5721 protected override void CloneTo (CloneContext clonectx, Expression t)
5728 /// This represents a reference to a parameter in the intermediate
5731 public class ParameterReference : VariableReference
5733 protected ParametersBlock.ParameterInfo pi;
5735 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5743 public override bool IsLockedByStatement {
5748 pi.IsLocked = value;
5752 public override bool IsRef {
5753 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5756 bool HasOutModifier {
5757 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5760 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5762 return pi.Parameter.HoistedVariant;
5766 // A ref or out parameter is classified as a moveable variable, even
5767 // if the argument given for the parameter is a fixed variable
5769 public override bool IsFixed {
5770 get { return !IsRef; }
5773 public override string Name {
5774 get { return Parameter.Name; }
5777 public Parameter Parameter {
5778 get { return pi.Parameter; }
5781 public override VariableInfo VariableInfo {
5782 get { return pi.VariableInfo; }
5785 protected override ILocalVariable Variable {
5786 get { return Parameter; }
5791 public override void AddressOf (EmitContext ec, AddressOp mode)
5794 // ParameterReferences might already be a reference
5801 base.AddressOf (ec, mode);
5804 public override void SetHasAddressTaken ()
5806 Parameter.HasAddressTaken = true;
5809 void SetAssigned (ResolveContext ec)
5811 if (Parameter.HoistedVariant != null)
5812 Parameter.HoistedVariant.IsAssigned = true;
5814 if (HasOutModifier && ec.DoFlowAnalysis)
5815 ec.CurrentBranching.SetAssigned (VariableInfo);
5818 bool DoResolveBase (ResolveContext ec)
5820 if (eclass != ExprClass.Unresolved)
5823 type = pi.ParameterType;
5824 eclass = ExprClass.Variable;
5827 // If we are referencing a parameter from the external block
5828 // flag it for capturing
5830 if (ec.MustCaptureVariable (pi)) {
5831 if (Parameter.HasAddressTaken)
5832 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5835 ec.Report.Error (1628, loc,
5836 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5837 Name, ec.CurrentAnonymousMethod.ContainerType);
5840 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5841 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5842 storey.CaptureParameter (ec, pi, this);
5849 public override int GetHashCode ()
5851 return Name.GetHashCode ();
5854 public override bool Equals (object obj)
5856 ParameterReference pr = obj as ParameterReference;
5860 return Name == pr.Name;
5863 protected override void CloneTo (CloneContext clonectx, Expression target)
5869 public override Expression CreateExpressionTree (ResolveContext ec)
5871 HoistedVariable hv = GetHoistedVariable (ec);
5873 return hv.CreateExpressionTree ();
5875 return Parameter.ExpressionTreeVariableReference ();
5879 // Notice that for ref/out parameters, the type exposed is not the
5880 // same type exposed externally.
5883 // externally we expose "int&"
5884 // here we expose "int".
5886 // We record this in "is_ref". This means that the type system can treat
5887 // the type as it is expected, but when we generate the code, we generate
5888 // the alternate kind of code.
5890 protected override Expression DoResolve (ResolveContext ec)
5892 if (!DoResolveBase (ec))
5895 VerifyAssigned (ec);
5899 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5901 if (!DoResolveBase (ec))
5905 return base.DoResolveLValue (ec, right_side);
5908 public override void VerifyAssigned (ResolveContext rc)
5910 // HACK: Variables are not captured in probing mode
5911 if (rc.IsInProbingMode)
5914 if (HasOutModifier && !VariableInfo.IsAssigned (rc)) {
5915 rc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
5921 /// Invocation of methods or delegates.
5923 public class Invocation : ExpressionStatement
5925 protected Arguments arguments;
5926 protected Expression expr;
5927 protected MethodGroupExpr mg;
5929 public Invocation (Expression expr, Arguments arguments)
5932 this.arguments = arguments;
5934 loc = expr.Location;
5939 public Arguments Arguments {
5945 public Expression Exp {
5951 public MethodGroupExpr MethodGroup {
5957 public override Location StartLocation {
5959 return expr.StartLocation;
5965 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
5967 if (MethodGroup == null)
5970 var candidate = MethodGroup.BestCandidate;
5971 if (candidate == null || !(candidate.IsStatic || Exp is This))
5974 var args_count = arguments == null ? 0 : arguments.Count;
5975 if (args_count != body.Parameters.Count)
5978 var lambda_parameters = body.Block.Parameters.FixedParameters;
5979 for (int i = 0; i < args_count; ++i) {
5980 var pr = arguments[i].Expr as ParameterReference;
5984 if (lambda_parameters[i] != pr.Parameter)
5987 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
5991 var emg = MethodGroup as ExtensionMethodGroupExpr;
5993 return MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
5999 protected override void CloneTo (CloneContext clonectx, Expression t)
6001 Invocation target = (Invocation) t;
6003 if (arguments != null)
6004 target.arguments = arguments.Clone (clonectx);
6006 target.expr = expr.Clone (clonectx);
6009 public override bool ContainsEmitWithAwait ()
6011 if (arguments != null && arguments.ContainsEmitWithAwait ())
6014 return mg.ContainsEmitWithAwait ();
6017 public override Expression CreateExpressionTree (ResolveContext ec)
6019 Expression instance = mg.IsInstance ?
6020 mg.InstanceExpression.CreateExpressionTree (ec) :
6021 new NullLiteral (loc);
6023 var args = Arguments.CreateForExpressionTree (ec, arguments,
6025 mg.CreateExpressionTree (ec));
6027 return CreateExpressionFactoryCall (ec, "Call", args);
6030 protected override Expression DoResolve (ResolveContext ec)
6032 Expression member_expr;
6033 var atn = expr as ATypeNameExpression;
6035 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
6036 if (member_expr != null)
6037 member_expr = member_expr.Resolve (ec);
6039 member_expr = expr.Resolve (ec);
6042 if (member_expr == null)
6046 // Next, evaluate all the expressions in the argument list
6048 bool dynamic_arg = false;
6049 if (arguments != null)
6050 arguments.Resolve (ec, out dynamic_arg);
6052 TypeSpec expr_type = member_expr.Type;
6053 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6054 return DoResolveDynamic (ec, member_expr);
6056 mg = member_expr as MethodGroupExpr;
6057 Expression invoke = null;
6060 if (expr_type != null && expr_type.IsDelegate) {
6061 invoke = new DelegateInvocation (member_expr, arguments, loc);
6062 invoke = invoke.Resolve (ec);
6063 if (invoke == null || !dynamic_arg)
6066 if (member_expr is RuntimeValueExpression) {
6067 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
6068 member_expr.Type.GetSignatureForError ()); ;
6072 MemberExpr me = member_expr as MemberExpr;
6074 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
6078 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
6079 member_expr.GetSignatureForError ());
6084 if (invoke == null) {
6085 mg = DoResolveOverload (ec);
6091 return DoResolveDynamic (ec, member_expr);
6093 var method = mg.BestCandidate;
6094 type = mg.BestCandidateReturnType;
6096 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
6098 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
6100 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
6104 IsSpecialMethodInvocation (ec, method, loc);
6106 eclass = ExprClass.Value;
6110 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
6113 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
6115 args = dmb.Arguments;
6116 if (arguments != null)
6117 args.AddRange (arguments);
6118 } else if (mg == null) {
6119 if (arguments == null)
6120 args = new Arguments (1);
6124 args.Insert (0, new Argument (memberExpr));
6128 ec.Report.Error (1971, loc,
6129 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
6134 if (arguments == null)
6135 args = new Arguments (1);
6139 MemberAccess ma = expr as MemberAccess;
6141 var left_type = ma.LeftExpression as TypeExpr;
6142 if (left_type != null) {
6143 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6146 // Any value type has to be pass as by-ref to get back the same
6147 // instance on which the member was called
6149 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
6150 Argument.AType.Ref : Argument.AType.None;
6151 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
6153 } else { // is SimpleName
6155 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6157 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
6162 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
6165 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
6167 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
6170 public override string GetSignatureForError ()
6172 return mg.GetSignatureForError ();
6176 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
6177 // or the type dynamic, then the member is invocable
6179 public static bool IsMemberInvocable (MemberSpec member)
6181 switch (member.Kind) {
6182 case MemberKind.Event:
6184 case MemberKind.Field:
6185 case MemberKind.Property:
6186 var m = member as IInterfaceMemberSpec;
6187 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
6193 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
6195 if (!method.IsReservedMethod)
6198 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
6201 ec.Report.SymbolRelatedToPreviousError (method);
6202 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
6203 method.GetSignatureForError ());
6208 public override void Emit (EmitContext ec)
6210 mg.EmitCall (ec, arguments);
6213 public override void EmitStatement (EmitContext ec)
6218 // Pop the return value if there is one
6220 if (type.Kind != MemberKind.Void)
6221 ec.Emit (OpCodes.Pop);
6224 public override SLE.Expression MakeExpression (BuilderContext ctx)
6226 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
6229 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
6232 throw new NotSupportedException ();
6234 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
6235 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
6239 public override object Accept (StructuralVisitor visitor)
6241 return visitor.Visit (this);
6246 // Implements simple new expression
6248 public class New : ExpressionStatement, IMemoryLocation
6250 protected Arguments arguments;
6253 // During bootstrap, it contains the RequestedType,
6254 // but if `type' is not null, it *might* contain a NewDelegate
6255 // (because of field multi-initialization)
6257 protected Expression RequestedType;
6259 protected MethodSpec method;
6261 public New (Expression requested_type, Arguments arguments, Location l)
6263 RequestedType = requested_type;
6264 this.arguments = arguments;
6269 public Arguments Arguments {
6276 // Returns true for resolved `new S()'
6278 public bool IsDefaultStruct {
6280 return arguments == null && type.IsStruct && GetType () == typeof (New);
6284 public Expression TypeExpression {
6286 return RequestedType;
6293 /// Converts complex core type syntax like 'new int ()' to simple constant
6295 public static Constant Constantify (TypeSpec t, Location loc)
6297 switch (t.BuiltinType) {
6298 case BuiltinTypeSpec.Type.Int:
6299 return new IntConstant (t, 0, loc);
6300 case BuiltinTypeSpec.Type.UInt:
6301 return new UIntConstant (t, 0, loc);
6302 case BuiltinTypeSpec.Type.Long:
6303 return new LongConstant (t, 0, loc);
6304 case BuiltinTypeSpec.Type.ULong:
6305 return new ULongConstant (t, 0, loc);
6306 case BuiltinTypeSpec.Type.Float:
6307 return new FloatConstant (t, 0, loc);
6308 case BuiltinTypeSpec.Type.Double:
6309 return new DoubleConstant (t, 0, loc);
6310 case BuiltinTypeSpec.Type.Short:
6311 return new ShortConstant (t, 0, loc);
6312 case BuiltinTypeSpec.Type.UShort:
6313 return new UShortConstant (t, 0, loc);
6314 case BuiltinTypeSpec.Type.SByte:
6315 return new SByteConstant (t, 0, loc);
6316 case BuiltinTypeSpec.Type.Byte:
6317 return new ByteConstant (t, 0, loc);
6318 case BuiltinTypeSpec.Type.Char:
6319 return new CharConstant (t, '\0', loc);
6320 case BuiltinTypeSpec.Type.Bool:
6321 return new BoolConstant (t, false, loc);
6322 case BuiltinTypeSpec.Type.Decimal:
6323 return new DecimalConstant (t, 0, loc);
6327 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
6329 if (t.IsNullableType)
6330 return Nullable.LiftedNull.Create (t, loc);
6335 public override bool ContainsEmitWithAwait ()
6337 return arguments != null && arguments.ContainsEmitWithAwait ();
6341 // Checks whether the type is an interface that has the
6342 // [ComImport, CoClass] attributes and must be treated
6345 public Expression CheckComImport (ResolveContext ec)
6347 if (!type.IsInterface)
6351 // Turn the call into:
6352 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
6354 var real_class = type.MemberDefinition.GetAttributeCoClass ();
6355 if (real_class == null)
6358 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
6359 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
6360 return cast.Resolve (ec);
6363 public override Expression CreateExpressionTree (ResolveContext ec)
6366 if (method == null) {
6367 args = new Arguments (1);
6368 args.Add (new Argument (new TypeOf (type, loc)));
6370 args = Arguments.CreateForExpressionTree (ec,
6371 arguments, new TypeOfMethod (method, loc));
6374 return CreateExpressionFactoryCall (ec, "New", args);
6377 protected override Expression DoResolve (ResolveContext ec)
6379 type = RequestedType.ResolveAsType (ec);
6383 eclass = ExprClass.Value;
6385 if (type.IsPointer) {
6386 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
6387 type.GetSignatureForError ());
6391 if (arguments == null) {
6392 Constant c = Constantify (type, RequestedType.Location);
6394 return ReducedExpression.Create (c, this);
6397 if (type.IsDelegate) {
6398 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
6401 var tparam = type as TypeParameterSpec;
6402 if (tparam != null) {
6404 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
6405 // where type parameter constraint is inflated to struct
6407 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
6408 ec.Report.Error (304, loc,
6409 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
6410 type.GetSignatureForError ());
6413 if ((arguments != null) && (arguments.Count != 0)) {
6414 ec.Report.Error (417, loc,
6415 "`{0}': cannot provide arguments when creating an instance of a variable type",
6416 type.GetSignatureForError ());
6422 if (type.IsStatic) {
6423 ec.Report.SymbolRelatedToPreviousError (type);
6424 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
6428 if (type.IsInterface || type.IsAbstract){
6429 if (!TypeManager.IsGenericType (type)) {
6430 RequestedType = CheckComImport (ec);
6431 if (RequestedType != null)
6432 return RequestedType;
6435 ec.Report.SymbolRelatedToPreviousError (type);
6436 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
6441 // Any struct always defines parameterless constructor
6443 if (type.IsStruct && arguments == null)
6447 if (arguments != null) {
6448 arguments.Resolve (ec, out dynamic);
6453 method = ConstructorLookup (ec, type, ref arguments, loc);
6456 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6457 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
6463 bool DoEmitTypeParameter (EmitContext ec)
6465 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
6469 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
6470 var tparam = (TypeParameterSpec) type;
6472 if (tparam.IsReferenceType) {
6473 ec.Emit (OpCodes.Call, ctor_factory);
6477 // Allow DoEmit() to be called multiple times.
6478 // We need to create a new LocalTemporary each time since
6479 // you can't share LocalBuilders among ILGeneators.
6480 LocalTemporary temp = new LocalTemporary (type);
6482 Label label_activator = ec.DefineLabel ();
6483 Label label_end = ec.DefineLabel ();
6485 temp.AddressOf (ec, AddressOp.Store);
6486 ec.Emit (OpCodes.Initobj, type);
6489 ec.Emit (OpCodes.Box, type);
6490 ec.Emit (OpCodes.Brfalse, label_activator);
6492 temp.AddressOf (ec, AddressOp.Store);
6493 ec.Emit (OpCodes.Initobj, type);
6496 ec.Emit (OpCodes.Br_S, label_end);
6498 ec.MarkLabel (label_activator);
6500 ec.Emit (OpCodes.Call, ctor_factory);
6501 ec.MarkLabel (label_end);
6506 // This Emit can be invoked in two contexts:
6507 // * As a mechanism that will leave a value on the stack (new object)
6508 // * As one that wont (init struct)
6510 // If we are dealing with a ValueType, we have a few
6511 // situations to deal with:
6513 // * The target is a ValueType, and we have been provided
6514 // the instance (this is easy, we are being assigned).
6516 // * The target of New is being passed as an argument,
6517 // to a boxing operation or a function that takes a
6520 // In this case, we need to create a temporary variable
6521 // that is the argument of New.
6523 // Returns whether a value is left on the stack
6525 // *** Implementation note ***
6527 // To benefit from this optimization, each assignable expression
6528 // has to manually cast to New and call this Emit.
6530 // TODO: It's worth to implement it for arrays and fields
6532 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
6534 bool is_value_type = TypeSpec.IsValueType (type);
6535 VariableReference vr = target as VariableReference;
6537 if (target != null && is_value_type && (vr != null || method == null)) {
6538 target.AddressOf (ec, AddressOp.Store);
6539 } else if (vr != null && vr.IsRef) {
6543 if (arguments != null) {
6544 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
6545 arguments = arguments.Emit (ec, false, true);
6547 arguments.Emit (ec);
6550 if (is_value_type) {
6551 if (method == null) {
6552 ec.Emit (OpCodes.Initobj, type);
6557 ec.MarkCallEntry (loc);
6558 ec.Emit (OpCodes.Call, method);
6563 if (type is TypeParameterSpec)
6564 return DoEmitTypeParameter (ec);
6566 ec.MarkCallEntry (loc);
6567 ec.Emit (OpCodes.Newobj, method);
6571 public override void Emit (EmitContext ec)
6573 LocalTemporary v = null;
6574 if (method == null && TypeSpec.IsValueType (type)) {
6575 // TODO: Use temporary variable from pool
6576 v = new LocalTemporary (type);
6583 public override void EmitStatement (EmitContext ec)
6585 LocalTemporary v = null;
6586 if (method == null && TypeSpec.IsValueType (type)) {
6587 // TODO: Use temporary variable from pool
6588 v = new LocalTemporary (type);
6592 ec.Emit (OpCodes.Pop);
6595 public void AddressOf (EmitContext ec, AddressOp mode)
6597 EmitAddressOf (ec, mode);
6600 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
6602 LocalTemporary value_target = new LocalTemporary (type);
6604 if (type is TypeParameterSpec) {
6605 DoEmitTypeParameter (ec);
6606 value_target.Store (ec);
6607 value_target.AddressOf (ec, mode);
6608 return value_target;
6611 value_target.AddressOf (ec, AddressOp.Store);
6613 if (method == null) {
6614 ec.Emit (OpCodes.Initobj, type);
6616 if (arguments != null)
6617 arguments.Emit (ec);
6619 ec.Emit (OpCodes.Call, method);
6622 value_target.AddressOf (ec, mode);
6623 return value_target;
6626 protected override void CloneTo (CloneContext clonectx, Expression t)
6628 New target = (New) t;
6630 target.RequestedType = RequestedType.Clone (clonectx);
6631 if (arguments != null){
6632 target.arguments = arguments.Clone (clonectx);
6636 public override SLE.Expression MakeExpression (BuilderContext ctx)
6639 return base.MakeExpression (ctx);
6641 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
6645 public override object Accept (StructuralVisitor visitor)
6647 return visitor.Visit (this);
6652 // Array initializer expression, the expression is allowed in
6653 // variable or field initialization only which makes it tricky as
6654 // the type has to be infered based on the context either from field
6655 // type or variable type (think of multiple declarators)
6657 public class ArrayInitializer : Expression
6659 List<Expression> elements;
6660 BlockVariable variable;
6662 public ArrayInitializer (List<Expression> init, Location loc)
6668 public ArrayInitializer (int count, Location loc)
6669 : this (new List<Expression> (count), loc)
6673 public ArrayInitializer (Location loc)
6681 get { return elements.Count; }
6684 public List<Expression> Elements {
6690 public Expression this [int index] {
6692 return elements [index];
6696 public BlockVariable VariableDeclaration {
6707 public void Add (Expression expr)
6709 elements.Add (expr);
6712 public override bool ContainsEmitWithAwait ()
6714 throw new NotSupportedException ();
6717 public override Expression CreateExpressionTree (ResolveContext ec)
6719 throw new NotSupportedException ("ET");
6722 protected override void CloneTo (CloneContext clonectx, Expression t)
6724 var target = (ArrayInitializer) t;
6726 target.elements = new List<Expression> (elements.Count);
6727 foreach (var element in elements)
6728 target.elements.Add (element.Clone (clonectx));
6731 protected override Expression DoResolve (ResolveContext rc)
6733 var current_field = rc.CurrentMemberDefinition as FieldBase;
6734 TypeExpression type;
6735 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6736 type = new TypeExpression (current_field.MemberType, current_field.Location);
6737 } else if (variable != null) {
6738 if (variable.TypeExpression is VarExpr) {
6739 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6740 return EmptyExpression.Null;
6743 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6745 throw new NotImplementedException ("Unexpected array initializer context");
6748 return new ArrayCreation (type, this).Resolve (rc);
6751 public override void Emit (EmitContext ec)
6753 throw new InternalErrorException ("Missing Resolve call");
6756 public override object Accept (StructuralVisitor visitor)
6758 return visitor.Visit (this);
6763 /// 14.5.10.2: Represents an array creation expression.
6767 /// There are two possible scenarios here: one is an array creation
6768 /// expression that specifies the dimensions and optionally the
6769 /// initialization data and the other which does not need dimensions
6770 /// specified but where initialization data is mandatory.
6772 public class ArrayCreation : Expression
6774 FullNamedExpression requested_base_type;
6775 ArrayInitializer initializers;
6778 // The list of Argument types.
6779 // This is used to construct the `newarray' or constructor signature
6781 protected List<Expression> arguments;
6783 protected TypeSpec array_element_type;
6784 int num_arguments = 0;
6785 protected int dimensions;
6786 protected readonly ComposedTypeSpecifier rank;
6787 Expression first_emit;
6788 LocalTemporary first_emit_temp;
6790 protected List<Expression> array_data;
6792 Dictionary<int, int> bounds;
6795 // The number of constants in array initializers
6796 int const_initializers_count;
6797 bool only_constant_initializers;
6799 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6800 : this (requested_base_type, rank, initializers, l)
6802 arguments = new List<Expression> (exprs);
6803 num_arguments = arguments.Count;
6807 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6809 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6811 this.requested_base_type = requested_base_type;
6813 this.initializers = initializers;
6817 num_arguments = rank.Dimension;
6821 // For compiler generated single dimensional arrays only
6823 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6824 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6829 // For expressions like int[] foo = { 1, 2, 3 };
6831 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6832 : this (requested_base_type, null, initializers, initializers.Location)
6836 public ComposedTypeSpecifier Rank {
6842 public FullNamedExpression TypeExpression {
6844 return this.requested_base_type;
6848 public ArrayInitializer Initializers {
6850 return this.initializers;
6854 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6856 if (initializers != null && bounds == null) {
6858 // We use this to store all the data values in the order in which we
6859 // will need to store them in the byte blob later
6861 array_data = new List<Expression> (probe.Count);
6862 bounds = new Dictionary<int, int> ();
6865 if (specified_dims) {
6866 Expression a = arguments [idx];
6871 a = ConvertExpressionToArrayIndex (ec, a);
6877 if (initializers != null) {
6878 Constant c = a as Constant;
6879 if (c == null && a is ArrayIndexCast)
6880 c = ((ArrayIndexCast) a).Child as Constant;
6883 ec.Report.Error (150, a.Location, "A constant value is expected");
6889 value = System.Convert.ToInt32 (c.GetValue ());
6891 ec.Report.Error (150, a.Location, "A constant value is expected");
6895 // TODO: probe.Count does not fit ulong in
6896 if (value != probe.Count) {
6897 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6901 bounds[idx] = value;
6905 if (initializers == null)
6908 for (int i = 0; i < probe.Count; ++i) {
6910 if (o is ArrayInitializer) {
6911 var sub_probe = o as ArrayInitializer;
6912 if (idx + 1 >= dimensions){
6913 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6917 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
6918 if (!bounds.ContainsKey(idx + 1))
6919 bounds[idx + 1] = sub_probe.Count;
6921 if (bounds[idx + 1] != sub_probe.Count) {
6922 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
6926 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6929 } else if (child_bounds > 1) {
6930 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6932 Expression element = ResolveArrayElement (ec, o);
6933 if (element == null)
6936 // Initializers with the default values can be ignored
6937 Constant c = element as Constant;
6939 if (!c.IsDefaultInitializer (array_element_type)) {
6940 ++const_initializers_count;
6943 only_constant_initializers = false;
6946 array_data.Add (element);
6953 public override bool ContainsEmitWithAwait ()
6955 foreach (var arg in arguments) {
6956 if (arg.ContainsEmitWithAwait ())
6960 return InitializersContainAwait ();
6963 public override Expression CreateExpressionTree (ResolveContext ec)
6967 if (array_data == null) {
6968 args = new Arguments (arguments.Count + 1);
6969 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6970 foreach (Expression a in arguments)
6971 args.Add (new Argument (a.CreateExpressionTree (ec)));
6973 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6976 if (dimensions > 1) {
6977 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6981 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6982 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6983 if (array_data != null) {
6984 for (int i = 0; i < array_data.Count; ++i) {
6985 Expression e = array_data [i];
6986 args.Add (new Argument (e.CreateExpressionTree (ec)));
6990 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6993 void UpdateIndices (ResolveContext rc)
6996 for (var probe = initializers; probe != null;) {
6997 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
6999 bounds[i++] = probe.Count;
7001 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7002 probe = (ArrayInitializer) probe[0];
7003 } else if (dimensions > i) {
7011 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7013 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
7016 bool InitializersContainAwait ()
7018 if (array_data == null)
7021 foreach (var expr in array_data) {
7022 if (expr.ContainsEmitWithAwait ())
7029 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
7031 element = element.Resolve (ec);
7032 if (element == null)
7035 if (element is CompoundAssign.TargetExpression) {
7036 if (first_emit != null)
7037 throw new InternalErrorException ("Can only handle one mutator at a time");
7038 first_emit = element;
7039 element = first_emit_temp = new LocalTemporary (element.Type);
7042 return Convert.ImplicitConversionRequired (
7043 ec, element, array_element_type, loc);
7046 protected bool ResolveInitializers (ResolveContext ec)
7049 only_constant_initializers = true;
7052 if (arguments != null) {
7054 for (int i = 0; i < arguments.Count; ++i) {
7055 res &= CheckIndices (ec, initializers, i, true, dimensions);
7056 if (initializers != null)
7063 arguments = new List<Expression> ();
7065 if (!CheckIndices (ec, initializers, 0, false, dimensions))
7074 // Resolved the type of the array
7076 bool ResolveArrayType (ResolveContext ec)
7081 FullNamedExpression array_type_expr;
7082 if (num_arguments > 0) {
7083 array_type_expr = new ComposedCast (requested_base_type, rank);
7085 array_type_expr = requested_base_type;
7088 type = array_type_expr.ResolveAsType (ec);
7089 if (array_type_expr == null)
7092 var ac = type as ArrayContainer;
7094 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
7098 array_element_type = ac.Element;
7099 dimensions = ac.Rank;
7104 protected override Expression DoResolve (ResolveContext ec)
7109 if (!ResolveArrayType (ec))
7113 // validate the initializers and fill in any missing bits
7115 if (!ResolveInitializers (ec))
7118 eclass = ExprClass.Value;
7122 byte [] MakeByteBlob ()
7127 int count = array_data.Count;
7129 TypeSpec element_type = array_element_type;
7130 if (element_type.IsEnum)
7131 element_type = EnumSpec.GetUnderlyingType (element_type);
7133 factor = BuiltinTypeSpec.GetSize (element_type);
7135 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
7137 data = new byte [(count * factor + 3) & ~3];
7140 for (int i = 0; i < count; ++i) {
7141 var c = array_data[i] as Constant;
7147 object v = c.GetValue ();
7149 switch (element_type.BuiltinType) {
7150 case BuiltinTypeSpec.Type.Long:
7151 long lval = (long) v;
7153 for (int j = 0; j < factor; ++j) {
7154 data[idx + j] = (byte) (lval & 0xFF);
7158 case BuiltinTypeSpec.Type.ULong:
7159 ulong ulval = (ulong) v;
7161 for (int j = 0; j < factor; ++j) {
7162 data[idx + j] = (byte) (ulval & 0xFF);
7163 ulval = (ulval >> 8);
7166 case BuiltinTypeSpec.Type.Float:
7167 var fval = SingleConverter.SingleToInt32Bits((float) v);
7169 data[idx] = (byte) (fval & 0xff);
7170 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
7171 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
7172 data[idx + 3] = (byte) (fval >> 24);
7174 case BuiltinTypeSpec.Type.Double:
7175 element = BitConverter.GetBytes ((double) v);
7177 for (int j = 0; j < factor; ++j)
7178 data[idx + j] = element[j];
7180 // FIXME: Handle the ARM float format.
7181 if (!BitConverter.IsLittleEndian)
7182 System.Array.Reverse (data, idx, 8);
7184 case BuiltinTypeSpec.Type.Char:
7185 int chval = (int) ((char) v);
7187 data[idx] = (byte) (chval & 0xff);
7188 data[idx + 1] = (byte) (chval >> 8);
7190 case BuiltinTypeSpec.Type.Short:
7191 int sval = (int) ((short) v);
7193 data[idx] = (byte) (sval & 0xff);
7194 data[idx + 1] = (byte) (sval >> 8);
7196 case BuiltinTypeSpec.Type.UShort:
7197 int usval = (int) ((ushort) v);
7199 data[idx] = (byte) (usval & 0xff);
7200 data[idx + 1] = (byte) (usval >> 8);
7202 case BuiltinTypeSpec.Type.Int:
7205 data[idx] = (byte) (val & 0xff);
7206 data[idx + 1] = (byte) ((val >> 8) & 0xff);
7207 data[idx + 2] = (byte) ((val >> 16) & 0xff);
7208 data[idx + 3] = (byte) (val >> 24);
7210 case BuiltinTypeSpec.Type.UInt:
7211 uint uval = (uint) v;
7213 data[idx] = (byte) (uval & 0xff);
7214 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
7215 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
7216 data[idx + 3] = (byte) (uval >> 24);
7218 case BuiltinTypeSpec.Type.SByte:
7219 data[idx] = (byte) (sbyte) v;
7221 case BuiltinTypeSpec.Type.Byte:
7222 data[idx] = (byte) v;
7224 case BuiltinTypeSpec.Type.Bool:
7225 data[idx] = (byte) ((bool) v ? 1 : 0);
7227 case BuiltinTypeSpec.Type.Decimal:
7228 int[] bits = Decimal.GetBits ((decimal) v);
7231 // FIXME: For some reason, this doesn't work on the MS runtime.
7232 int[] nbits = new int[4];
7238 for (int j = 0; j < 4; j++) {
7239 data[p++] = (byte) (nbits[j] & 0xff);
7240 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
7241 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
7242 data[p++] = (byte) (nbits[j] >> 24);
7246 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
7255 #if NET_4_0 || MONODROID
7256 public override SLE.Expression MakeExpression (BuilderContext ctx)
7259 return base.MakeExpression (ctx);
7261 var initializers = new SLE.Expression [array_data.Count];
7262 for (var i = 0; i < initializers.Length; i++) {
7263 if (array_data [i] == null)
7264 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
7266 initializers [i] = array_data [i].MakeExpression (ctx);
7269 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
7275 // Emits the initializers for the array
7277 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
7279 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
7284 // First, the static data
7286 byte [] data = MakeByteBlob ();
7287 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
7289 if (stackArray == null) {
7290 ec.Emit (OpCodes.Dup);
7292 stackArray.Emit (ec);
7295 ec.Emit (OpCodes.Ldtoken, fb);
7296 ec.Emit (OpCodes.Call, m);
7301 // Emits pieces of the array that can not be computed at compile
7302 // time (variables and string locations).
7304 // This always expect the top value on the stack to be the array
7306 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
7308 int dims = bounds.Count;
7309 var current_pos = new int [dims];
7311 for (int i = 0; i < array_data.Count; i++){
7313 Expression e = array_data [i];
7314 var c = e as Constant;
7316 // Constant can be initialized via StaticInitializer
7317 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
7321 if (stackArray != null) {
7322 if (e.ContainsEmitWithAwait ()) {
7323 e = e.EmitToField (ec);
7326 stackArray.Emit (ec);
7328 ec.Emit (OpCodes.Dup);
7331 for (int idx = 0; idx < dims; idx++)
7332 ec.EmitInt (current_pos [idx]);
7335 // If we are dealing with a struct, get the
7336 // address of it, so we can store it.
7338 if (dims == 1 && etype.IsStruct) {
7339 switch (etype.BuiltinType) {
7340 case BuiltinTypeSpec.Type.Byte:
7341 case BuiltinTypeSpec.Type.SByte:
7342 case BuiltinTypeSpec.Type.Bool:
7343 case BuiltinTypeSpec.Type.Short:
7344 case BuiltinTypeSpec.Type.UShort:
7345 case BuiltinTypeSpec.Type.Char:
7346 case BuiltinTypeSpec.Type.Int:
7347 case BuiltinTypeSpec.Type.UInt:
7348 case BuiltinTypeSpec.Type.Long:
7349 case BuiltinTypeSpec.Type.ULong:
7350 case BuiltinTypeSpec.Type.Float:
7351 case BuiltinTypeSpec.Type.Double:
7354 ec.Emit (OpCodes.Ldelema, etype);
7361 ec.EmitArrayStore ((ArrayContainer) type);
7367 for (int j = dims - 1; j >= 0; j--){
7369 if (current_pos [j] < bounds [j])
7371 current_pos [j] = 0;
7376 public override void Emit (EmitContext ec)
7378 EmitToFieldSource (ec);
7381 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
7383 if (first_emit != null) {
7384 first_emit.Emit (ec);
7385 first_emit_temp.Store (ec);
7388 FieldExpr await_stack_field;
7389 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
7390 await_stack_field = ec.GetTemporaryField (type);
7393 await_stack_field = null;
7396 EmitExpressionsList (ec, arguments);
7398 ec.EmitArrayNew ((ArrayContainer) type);
7400 if (initializers == null)
7401 return await_stack_field;
7403 if (await_stack_field != null)
7404 await_stack_field.EmitAssignFromStack (ec);
7408 // Emit static initializer for arrays which contain more than 2 items and
7409 // the static initializer will initialize at least 25% of array values or there
7410 // is more than 10 items to be initialized
7412 // NOTE: const_initializers_count does not contain default constant values.
7414 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
7415 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
7416 EmitStaticInitializers (ec, await_stack_field);
7418 if (!only_constant_initializers)
7419 EmitDynamicInitializers (ec, false, await_stack_field);
7423 EmitDynamicInitializers (ec, true, await_stack_field);
7426 if (first_emit_temp != null)
7427 first_emit_temp.Release (ec);
7429 return await_stack_field;
7432 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7434 // no multi dimensional or jagged arrays
7435 if (arguments.Count != 1 || array_element_type.IsArray) {
7436 base.EncodeAttributeValue (rc, enc, targetType);
7440 // No array covariance, except for array -> object
7441 if (type != targetType) {
7442 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
7443 base.EncodeAttributeValue (rc, enc, targetType);
7447 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
7448 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7453 // Single dimensional array of 0 size
7454 if (array_data == null) {
7455 IntConstant ic = arguments[0] as IntConstant;
7456 if (ic == null || !ic.IsDefaultValue) {
7457 base.EncodeAttributeValue (rc, enc, targetType);
7465 enc.Encode (array_data.Count);
7466 foreach (var element in array_data) {
7467 element.EncodeAttributeValue (rc, enc, array_element_type);
7471 protected override void CloneTo (CloneContext clonectx, Expression t)
7473 ArrayCreation target = (ArrayCreation) t;
7475 if (requested_base_type != null)
7476 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
7478 if (arguments != null){
7479 target.arguments = new List<Expression> (arguments.Count);
7480 foreach (Expression e in arguments)
7481 target.arguments.Add (e.Clone (clonectx));
7484 if (initializers != null)
7485 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
7488 public override object Accept (StructuralVisitor visitor)
7490 return visitor.Visit (this);
7495 // Represents an implicitly typed array epxression
7497 class ImplicitlyTypedArrayCreation : ArrayCreation
7499 TypeInferenceContext best_type_inference;
7501 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7502 : base (null, rank, initializers, loc)
7506 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
7507 : base (null, initializers, loc)
7511 protected override Expression DoResolve (ResolveContext ec)
7516 dimensions = rank.Dimension;
7518 best_type_inference = new TypeInferenceContext ();
7520 if (!ResolveInitializers (ec))
7523 best_type_inference.FixAllTypes (ec);
7524 array_element_type = best_type_inference.InferredTypeArguments[0];
7525 best_type_inference = null;
7527 if (array_element_type == null ||
7528 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
7529 arguments.Count != rank.Dimension) {
7530 ec.Report.Error (826, loc,
7531 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
7536 // At this point we found common base type for all initializer elements
7537 // but we have to be sure that all static initializer elements are of
7540 UnifyInitializerElement (ec);
7542 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
7543 eclass = ExprClass.Value;
7548 // Converts static initializer only
7550 void UnifyInitializerElement (ResolveContext ec)
7552 for (int i = 0; i < array_data.Count; ++i) {
7553 Expression e = array_data[i];
7555 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
7559 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
7561 element = element.Resolve (ec);
7562 if (element != null)
7563 best_type_inference.AddCommonTypeBound (element.Type);
7569 sealed class CompilerGeneratedThis : This
7571 public CompilerGeneratedThis (TypeSpec type, Location loc)
7575 eclass = ExprClass.Variable;
7578 protected override Expression DoResolve (ResolveContext ec)
7583 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7590 /// Represents the `this' construct
7593 public class This : VariableReference
7595 sealed class ThisVariable : ILocalVariable
7597 public static readonly ILocalVariable Instance = new ThisVariable ();
7599 public void Emit (EmitContext ec)
7604 public void EmitAssign (EmitContext ec)
7606 throw new InvalidOperationException ();
7609 public void EmitAddressOf (EmitContext ec)
7615 VariableInfo variable_info;
7617 public This (Location loc)
7624 public override string Name {
7625 get { return "this"; }
7628 public override bool IsLockedByStatement {
7636 public override bool IsRef {
7637 get { return type.IsStruct; }
7640 public override bool IsSideEffectFree {
7646 protected override ILocalVariable Variable {
7647 get { return ThisVariable.Instance; }
7650 public override VariableInfo VariableInfo {
7651 get { return variable_info; }
7654 public override bool IsFixed {
7655 get { return false; }
7660 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
7663 // It's null for all cases when we don't need to check `this'
7664 // definitive assignment
7666 if (variable_info == null)
7669 if (rc.OmitStructFlowAnalysis)
7672 if (!variable_info.IsAssigned (rc)) {
7673 rc.Report.Error (188, loc,
7674 "The `this' object cannot be used before all of its fields are assigned to");
7678 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7680 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7681 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7682 } else if (ec.CurrentAnonymousMethod != null) {
7683 ec.Report.Error (1673, loc,
7684 "Anonymous methods inside structs cannot access instance members of `this'. " +
7685 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7687 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7691 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7696 AnonymousMethodStorey storey = ae.Storey;
7697 return storey != null ? storey.HoistedThis : null;
7700 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7702 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7705 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7708 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7714 public virtual void ResolveBase (ResolveContext ec)
7716 eclass = ExprClass.Variable;
7717 type = ec.CurrentType;
7719 if (!IsThisAvailable (ec, false)) {
7720 Error_ThisNotAvailable (ec);
7724 var block = ec.CurrentBlock;
7725 if (block != null) {
7726 var top = block.ParametersBlock.TopBlock;
7727 if (top.ThisVariable != null)
7728 variable_info = top.ThisVariable.VariableInfo;
7730 AnonymousExpression am = ec.CurrentAnonymousMethod;
7731 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7733 // Hoisted this is almost like hoisted variable but not exactly. When
7734 // there is no variable hoisted we can simply emit an instance method
7735 // without lifting this into a storey. Unfotunatelly this complicates
7736 // things in other cases because we don't know where this will be hoisted
7737 // until top-level block is fully resolved
7739 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7740 am.SetHasThisAccess ();
7745 protected override Expression DoResolve (ResolveContext ec)
7749 CheckStructThisDefiniteAssignment (ec);
7754 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7756 if (eclass == ExprClass.Unresolved)
7759 if (variable_info != null)
7760 variable_info.SetAssigned (ec);
7763 if (right_side == EmptyExpression.UnaryAddress)
7764 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7765 else if (right_side == EmptyExpression.OutAccess)
7766 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7768 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7774 public override int GetHashCode()
7776 throw new NotImplementedException ();
7779 public override bool Equals (object obj)
7781 This t = obj as This;
7788 protected override void CloneTo (CloneContext clonectx, Expression t)
7793 public override void SetHasAddressTaken ()
7798 public override void VerifyAssigned (ResolveContext rc)
7802 public override object Accept (StructuralVisitor visitor)
7804 return visitor.Visit (this);
7809 /// Represents the `__arglist' construct
7811 public class ArglistAccess : Expression
7813 public ArglistAccess (Location loc)
7818 protected override void CloneTo (CloneContext clonectx, Expression target)
7823 public override bool ContainsEmitWithAwait ()
7828 public override Expression CreateExpressionTree (ResolveContext ec)
7830 throw new NotSupportedException ("ET");
7833 protected override Expression DoResolve (ResolveContext ec)
7835 eclass = ExprClass.Variable;
7836 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
7838 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7839 ec.Report.Error (190, loc,
7840 "The __arglist construct is valid only within a variable argument method");
7846 public override void Emit (EmitContext ec)
7848 ec.Emit (OpCodes.Arglist);
7851 public override object Accept (StructuralVisitor visitor)
7853 return visitor.Visit (this);
7858 /// Represents the `__arglist (....)' construct
7860 public class Arglist : Expression
7862 Arguments arguments;
7864 public Arglist (Location loc)
7869 public Arglist (Arguments args, Location l)
7875 public Arguments Arguments {
7881 public MetaType[] ArgumentTypes {
7883 if (arguments == null)
7884 return MetaType.EmptyTypes;
7886 var retval = new MetaType[arguments.Count];
7887 for (int i = 0; i < retval.Length; i++)
7888 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
7894 public override bool ContainsEmitWithAwait ()
7896 throw new NotImplementedException ();
7899 public override Expression CreateExpressionTree (ResolveContext ec)
7901 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7905 protected override Expression DoResolve (ResolveContext ec)
7907 eclass = ExprClass.Variable;
7908 type = InternalType.Arglist;
7909 if (arguments != null) {
7910 bool dynamic; // Can be ignored as there is always only 1 overload
7911 arguments.Resolve (ec, out dynamic);
7917 public override void Emit (EmitContext ec)
7919 if (arguments != null)
7920 arguments.Emit (ec);
7923 protected override void CloneTo (CloneContext clonectx, Expression t)
7925 Arglist target = (Arglist) t;
7927 if (arguments != null)
7928 target.arguments = arguments.Clone (clonectx);
7931 public override object Accept (StructuralVisitor visitor)
7933 return visitor.Visit (this);
7937 public class RefValueExpr : ShimExpression, IAssignMethod
7939 FullNamedExpression texpr;
7941 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7948 public FullNamedExpression TypeExpression {
7954 public override bool ContainsEmitWithAwait ()
7959 protected override Expression DoResolve (ResolveContext rc)
7961 expr = expr.Resolve (rc);
7962 type = texpr.ResolveAsType (rc);
7963 if (expr == null || type == null)
7966 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7967 eclass = ExprClass.Value;
7971 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7973 return DoResolve (rc);
7976 public override void Emit (EmitContext ec)
7979 ec.Emit (OpCodes.Refanyval, type);
7980 ec.EmitLoadFromPtr (type);
7983 public void Emit (EmitContext ec, bool leave_copy)
7985 throw new NotImplementedException ();
7988 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7991 ec.Emit (OpCodes.Refanyval, type);
7994 LocalTemporary temporary = null;
7996 ec.Emit (OpCodes.Dup);
7997 temporary = new LocalTemporary (source.Type);
7998 temporary.Store (ec);
8001 ec.EmitStoreFromPtr (type);
8003 if (temporary != null) {
8004 temporary.Emit (ec);
8005 temporary.Release (ec);
8009 public override object Accept (StructuralVisitor visitor)
8011 return visitor.Visit (this);
8015 public class RefTypeExpr : ShimExpression
8017 public RefTypeExpr (Expression expr, Location loc)
8023 protected override Expression DoResolve (ResolveContext rc)
8025 expr = expr.Resolve (rc);
8029 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8033 type = rc.BuiltinTypes.Type;
8034 eclass = ExprClass.Value;
8038 public override void Emit (EmitContext ec)
8041 ec.Emit (OpCodes.Refanytype);
8042 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8044 ec.Emit (OpCodes.Call, m);
8047 public override object Accept (StructuralVisitor visitor)
8049 return visitor.Visit (this);
8053 public class MakeRefExpr : ShimExpression
8055 public MakeRefExpr (Expression expr, Location loc)
8061 public override bool ContainsEmitWithAwait ()
8063 throw new NotImplementedException ();
8066 protected override Expression DoResolve (ResolveContext rc)
8068 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8069 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8070 eclass = ExprClass.Value;
8074 public override void Emit (EmitContext ec)
8076 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8077 ec.Emit (OpCodes.Mkrefany, expr.Type);
8080 public override object Accept (StructuralVisitor visitor)
8082 return visitor.Visit (this);
8087 /// Implements the typeof operator
8089 public class TypeOf : Expression {
8090 FullNamedExpression QueriedType;
8093 public TypeOf (FullNamedExpression queried_type, Location l)
8095 QueriedType = queried_type;
8100 // Use this constructor for any compiler generated typeof expression
8102 public TypeOf (TypeSpec type, Location loc)
8104 this.typearg = type;
8110 public override bool IsSideEffectFree {
8116 public TypeSpec TypeArgument {
8122 public FullNamedExpression TypeExpression {
8131 protected override void CloneTo (CloneContext clonectx, Expression t)
8133 TypeOf target = (TypeOf) t;
8134 if (QueriedType != null)
8135 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
8138 public override bool ContainsEmitWithAwait ()
8143 public override Expression CreateExpressionTree (ResolveContext ec)
8145 Arguments args = new Arguments (2);
8146 args.Add (new Argument (this));
8147 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8148 return CreateExpressionFactoryCall (ec, "Constant", args);
8151 protected override Expression DoResolve (ResolveContext ec)
8153 if (eclass != ExprClass.Unresolved)
8156 if (typearg == null) {
8158 // Pointer types are allowed without explicit unsafe, they are just tokens
8160 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
8161 typearg = QueriedType.ResolveAsType (ec);
8164 if (typearg == null)
8167 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8168 ec.Report.Error (1962, QueriedType.Location,
8169 "The typeof operator cannot be used on the dynamic type");
8173 type = ec.BuiltinTypes.Type;
8175 // Even though what is returned is a type object, it's treated as a value by the compiler.
8176 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
8177 eclass = ExprClass.Value;
8181 static bool ContainsDynamicType (TypeSpec type)
8183 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
8186 var element_container = type as ElementTypeSpec;
8187 if (element_container != null)
8188 return ContainsDynamicType (element_container.Element);
8190 foreach (var t in type.TypeArguments) {
8191 if (ContainsDynamicType (t)) {
8199 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
8201 // Target type is not System.Type therefore must be object
8202 // and we need to use different encoding sequence
8203 if (targetType != type)
8206 if (typearg is InflatedTypeSpec) {
8209 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
8210 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
8211 typearg.GetSignatureForError ());
8215 gt = gt.DeclaringType;
8216 } while (gt != null);
8219 if (ContainsDynamicType (typearg)) {
8220 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8224 enc.EncodeTypeName (typearg);
8227 public override void Emit (EmitContext ec)
8229 ec.Emit (OpCodes.Ldtoken, typearg);
8230 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8232 ec.Emit (OpCodes.Call, m);
8235 public override object Accept (StructuralVisitor visitor)
8237 return visitor.Visit (this);
8241 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
8243 public TypeOfMethod (MethodSpec method, Location loc)
8244 : base (method, loc)
8248 protected override Expression DoResolve (ResolveContext ec)
8250 if (member.IsConstructor) {
8251 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
8253 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
8259 return base.DoResolve (ec);
8262 public override void Emit (EmitContext ec)
8264 ec.Emit (OpCodes.Ldtoken, member);
8267 ec.Emit (OpCodes.Castclass, type);
8270 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8272 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
8275 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8277 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
8281 abstract class TypeOfMember<T> : Expression where T : MemberSpec
8283 protected readonly T member;
8285 protected TypeOfMember (T member, Location loc)
8287 this.member = member;
8291 public override bool IsSideEffectFree {
8297 public override bool ContainsEmitWithAwait ()
8302 public override Expression CreateExpressionTree (ResolveContext ec)
8304 Arguments args = new Arguments (2);
8305 args.Add (new Argument (this));
8306 args.Add (new Argument (new TypeOf (type, loc)));
8307 return CreateExpressionFactoryCall (ec, "Constant", args);
8310 protected override Expression DoResolve (ResolveContext ec)
8312 eclass = ExprClass.Value;
8316 public override void Emit (EmitContext ec)
8318 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
8319 PredefinedMember<MethodSpec> p;
8321 p = GetTypeFromHandleGeneric (ec);
8322 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
8324 p = GetTypeFromHandle (ec);
8327 var mi = p.Resolve (loc);
8329 ec.Emit (OpCodes.Call, mi);
8332 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
8333 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
8336 sealed class TypeOfField : TypeOfMember<FieldSpec>
8338 public TypeOfField (FieldSpec field, Location loc)
8343 protected override Expression DoResolve (ResolveContext ec)
8345 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
8349 return base.DoResolve (ec);
8352 public override void Emit (EmitContext ec)
8354 ec.Emit (OpCodes.Ldtoken, member);
8358 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8360 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
8363 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8365 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
8370 /// Implements the sizeof expression
8372 public class SizeOf : Expression {
8373 readonly Expression texpr;
8374 TypeSpec type_queried;
8376 public SizeOf (Expression queried_type, Location l)
8378 this.texpr = queried_type;
8382 public override bool IsSideEffectFree {
8388 public Expression TypeExpression {
8394 public override bool ContainsEmitWithAwait ()
8399 public override Expression CreateExpressionTree (ResolveContext ec)
8401 Error_PointerInsideExpressionTree (ec);
8405 protected override Expression DoResolve (ResolveContext ec)
8407 type_queried = texpr.ResolveAsType (ec);
8408 if (type_queried == null)
8411 if (type_queried.IsEnum)
8412 type_queried = EnumSpec.GetUnderlyingType (type_queried);
8414 int size_of = BuiltinTypeSpec.GetSize (type_queried);
8416 return new IntConstant (ec.BuiltinTypes, size_of, loc);
8419 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
8424 ec.Report.Error (233, loc,
8425 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
8426 type_queried.GetSignatureForError ());
8429 type = ec.BuiltinTypes.Int;
8430 eclass = ExprClass.Value;
8434 public override void Emit (EmitContext ec)
8436 ec.Emit (OpCodes.Sizeof, type_queried);
8439 protected override void CloneTo (CloneContext clonectx, Expression t)
8443 public override object Accept (StructuralVisitor visitor)
8445 return visitor.Visit (this);
8450 /// Implements the qualified-alias-member (::) expression.
8452 public class QualifiedAliasMember : MemberAccess
8454 readonly string alias;
8455 public static readonly string GlobalAlias = "global";
8457 public QualifiedAliasMember (string alias, string identifier, Location l)
8458 : base (null, identifier, l)
8463 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
8464 : base (null, identifier, targs, l)
8469 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
8470 : base (null, identifier, arity, l)
8475 public string Alias {
8481 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
8483 if (alias == GlobalAlias) {
8484 expr = ec.Module.GlobalRootNamespace;
8485 return base.ResolveAsTypeOrNamespace (ec);
8488 int errors = ec.Module.Compiler.Report.Errors;
8489 expr = ec.LookupNamespaceAlias (alias);
8491 if (errors == ec.Module.Compiler.Report.Errors)
8492 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
8496 return base.ResolveAsTypeOrNamespace (ec);
8499 protected override Expression DoResolve (ResolveContext ec)
8501 return ResolveAsTypeOrNamespace (ec);
8504 public override string GetSignatureForError ()
8507 if (targs != null) {
8508 name = Name + "<" + targs.GetSignatureForError () + ">";
8511 return alias + "::" + name;
8514 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8516 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
8517 rc.Module.Compiler.Report.Error (687, loc,
8518 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
8519 GetSignatureForError ());
8524 return DoResolve (rc);
8527 protected override void CloneTo (CloneContext clonectx, Expression t)
8532 public override object Accept (StructuralVisitor visitor)
8534 return visitor.Visit (this);
8539 /// Implements the member access expression
8541 public class MemberAccess : ATypeNameExpression
8543 protected Expression expr;
8545 public MemberAccess (Expression expr, string id)
8546 : base (id, expr.Location)
8551 public MemberAccess (Expression expr, string identifier, Location loc)
8552 : base (identifier, loc)
8557 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
8558 : base (identifier, args, loc)
8563 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
8564 : base (identifier, arity, loc)
8569 public Expression LeftExpression {
8575 public override Location StartLocation {
8577 return expr == null ? loc : expr.StartLocation;
8581 protected override Expression DoResolve (ResolveContext rc)
8583 var e = DoResolveName (rc, null);
8585 if (!rc.OmitStructFlowAnalysis) {
8586 var fe = e as FieldExpr;
8588 fe.VerifyAssignedStructField (rc, null);
8595 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
8597 var e = DoResolveName (rc, rhs);
8599 if (!rc.OmitStructFlowAnalysis) {
8600 var fe = e as FieldExpr;
8601 if (fe != null && fe.InstanceExpression is FieldExpr) {
8602 fe = (FieldExpr) fe.InstanceExpression;
8603 fe.VerifyAssignedStructField (rc, rhs);
8610 Expression DoResolveName (ResolveContext rc, Expression right_side)
8612 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
8616 if (right_side != null) {
8617 if (e is TypeExpr) {
8618 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8622 e = e.ResolveLValue (rc, right_side);
8624 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
8630 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8632 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8633 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8635 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8638 public static bool IsValidDotExpression (TypeSpec type)
8640 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8641 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8643 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8646 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8648 var sn = expr as SimpleName;
8649 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8652 // Resolve the expression with flow analysis turned off, we'll do the definite
8653 // assignment checks later. This is because we don't know yet what the expression
8654 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
8655 // definite assignment check on the actual field and not on the whole struct.
8657 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
8659 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8662 // Resolve expression which does have type set as we need expression type
8663 // with disable flow analysis as we don't know whether left side expression
8664 // is used as variable or type
8666 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8667 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
8668 expr = expr.Resolve (rc);
8670 } else if (expr is TypeParameterExpr) {
8671 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8675 expr = expr.Resolve (rc, flags);
8682 Namespace ns = expr as Namespace;
8684 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8686 if (retval == null) {
8687 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8691 if (HasTypeArguments)
8692 return new GenericTypeExpr (retval.Type, targs, loc);
8698 TypeSpec expr_type = expr.Type;
8699 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8700 me = expr as MemberExpr;
8702 me.ResolveInstanceExpression (rc, null);
8705 // Run defined assigned checks on expressions resolved with
8706 // disabled flow-analysis
8709 var vr = expr as VariableReference;
8711 vr.VerifyAssigned (rc);
8714 Arguments args = new Arguments (1);
8715 args.Add (new Argument (expr));
8716 return new DynamicMemberBinder (Name, args, loc);
8719 if (!IsValidDotExpression (expr_type)) {
8720 Error_OperatorCannotBeApplied (rc, expr_type);
8724 var lookup_arity = Arity;
8725 bool errorMode = false;
8726 Expression member_lookup;
8728 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8729 if (member_lookup == null) {
8731 // Try to look for extension method when member lookup failed
8733 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8734 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8735 if (methods != null) {
8736 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8737 if (HasTypeArguments) {
8738 if (!targs.Resolve (rc))
8741 emg.SetTypeArguments (rc, targs);
8745 // Run defined assigned checks on expressions resolved with
8746 // disabled flow-analysis
8748 if (sn != null && !errorMode) {
8749 var vr = expr as VariableReference;
8751 vr.VerifyAssigned (rc);
8754 // TODO: it should really skip the checks bellow
8755 return emg.Resolve (rc);
8761 if (member_lookup == null) {
8762 var dep = expr_type.GetMissingDependencies ();
8764 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8765 } else if (expr is TypeExpr) {
8766 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8768 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8774 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8775 // Leave it to overload resolution to report correct error
8776 } else if (!(member_lookup is TypeExpr)) {
8777 // TODO: rc.SymbolRelatedToPreviousError
8778 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8783 if (member_lookup != null)
8787 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8791 TypeExpr texpr = member_lookup as TypeExpr;
8792 if (texpr != null) {
8793 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8794 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8795 Name, texpr.GetSignatureForError ());
8798 if (!texpr.Type.IsAccessible (rc)) {
8799 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8800 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8804 if (HasTypeArguments) {
8805 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8808 return member_lookup;
8811 me = member_lookup as MemberExpr;
8813 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8817 me = me.ResolveMemberAccess (rc, expr, sn);
8820 if (!targs.Resolve (rc))
8823 me.SetTypeArguments (rc, targs);
8827 // Run defined assigned checks on expressions resolved with
8828 // disabled flow-analysis
8830 if (sn != null && !(me is FieldExpr && TypeSpec.IsValueType (expr_type))) {
8831 var vr = expr as VariableReference;
8833 vr.VerifyAssigned (rc);
8839 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8841 FullNamedExpression fexpr = expr as FullNamedExpression;
8842 if (fexpr == null) {
8843 expr.ResolveAsType (rc);
8847 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8849 if (expr_resolved == null)
8852 Namespace ns = expr_resolved as Namespace;
8854 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8856 if (retval == null) {
8857 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8858 } else if (HasTypeArguments) {
8859 retval = new GenericTypeExpr (retval.Type, targs, loc);
8860 if (retval.ResolveAsType (rc) == null)
8867 var tnew_expr = expr_resolved.ResolveAsType (rc);
8868 if (tnew_expr == null)
8871 TypeSpec expr_type = tnew_expr;
8872 if (TypeManager.IsGenericParameter (expr_type)) {
8873 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8874 tnew_expr.GetSignatureForError ());
8878 var qam = this as QualifiedAliasMember;
8880 rc.Module.Compiler.Report.Error (431, loc,
8881 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8886 TypeSpec nested = null;
8887 while (expr_type != null) {
8888 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8889 if (nested == null) {
8890 if (expr_type == tnew_expr) {
8891 Error_IdentifierNotFound (rc, expr_type, Name);
8895 expr_type = tnew_expr;
8896 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8897 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
8901 if (nested.IsAccessible (rc))
8905 // Keep looking after inaccessible candidate but only if
8906 // we are not in same context as the definition itself
8908 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
8911 expr_type = expr_type.BaseType;
8916 if (HasTypeArguments) {
8917 texpr = new GenericTypeExpr (nested, targs, loc);
8919 texpr = new GenericOpenTypeExpr (nested, loc);
8922 texpr = new TypeExpression (nested, loc);
8925 if (texpr.ResolveAsType (rc) == null)
8931 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
8933 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
8935 if (nested != null) {
8936 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
8940 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
8941 if (any_other_member != null) {
8942 any_other_member.Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
8946 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
8947 Name, expr_type.GetSignatureForError ());
8950 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
8952 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
8955 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
8957 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8958 ec.Report.SymbolRelatedToPreviousError (type);
8960 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, type, name, Arity);
8962 // a using directive or an assembly reference
8964 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
8966 missing = "an assembly reference";
8969 ec.Report.Error (1061, loc,
8970 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
8971 type.GetSignatureForError (), name, missing);
8975 base.Error_TypeDoesNotContainDefinition (ec, type, name);
8978 public override string GetSignatureForError ()
8980 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
8983 protected override void CloneTo (CloneContext clonectx, Expression t)
8985 MemberAccess target = (MemberAccess) t;
8987 target.expr = expr.Clone (clonectx);
8990 public override object Accept (StructuralVisitor visitor)
8992 return visitor.Visit (this);
8997 /// Implements checked expressions
8999 public class CheckedExpr : Expression {
9001 public Expression Expr;
9003 public CheckedExpr (Expression e, Location l)
9009 public override bool ContainsEmitWithAwait ()
9011 return Expr.ContainsEmitWithAwait ();
9014 public override Expression CreateExpressionTree (ResolveContext ec)
9016 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9017 return Expr.CreateExpressionTree (ec);
9020 protected override Expression DoResolve (ResolveContext ec)
9022 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9023 Expr = Expr.Resolve (ec);
9028 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9031 eclass = Expr.eclass;
9036 public override void Emit (EmitContext ec)
9038 using (ec.With (EmitContext.Options.CheckedScope, true))
9042 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9044 using (ec.With (EmitContext.Options.CheckedScope, true))
9045 Expr.EmitBranchable (ec, target, on_true);
9048 public override SLE.Expression MakeExpression (BuilderContext ctx)
9050 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9051 return Expr.MakeExpression (ctx);
9055 protected override void CloneTo (CloneContext clonectx, Expression t)
9057 CheckedExpr target = (CheckedExpr) t;
9059 target.Expr = Expr.Clone (clonectx);
9062 public override object Accept (StructuralVisitor visitor)
9064 return visitor.Visit (this);
9069 /// Implements the unchecked expression
9071 public class UnCheckedExpr : Expression {
9073 public Expression Expr;
9075 public UnCheckedExpr (Expression e, Location l)
9081 public override bool ContainsEmitWithAwait ()
9083 return Expr.ContainsEmitWithAwait ();
9086 public override Expression CreateExpressionTree (ResolveContext ec)
9088 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9089 return Expr.CreateExpressionTree (ec);
9092 protected override Expression DoResolve (ResolveContext ec)
9094 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9095 Expr = Expr.Resolve (ec);
9100 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9103 eclass = Expr.eclass;
9108 public override void Emit (EmitContext ec)
9110 using (ec.With (EmitContext.Options.CheckedScope, false))
9114 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9116 using (ec.With (EmitContext.Options.CheckedScope, false))
9117 Expr.EmitBranchable (ec, target, on_true);
9120 protected override void CloneTo (CloneContext clonectx, Expression t)
9122 UnCheckedExpr target = (UnCheckedExpr) t;
9124 target.Expr = Expr.Clone (clonectx);
9127 public override object Accept (StructuralVisitor visitor)
9129 return visitor.Visit (this);
9134 /// An Element Access expression.
9136 /// During semantic analysis these are transformed into
9137 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
9139 public class ElementAccess : Expression
9141 public Arguments Arguments;
9142 public Expression Expr;
9144 public ElementAccess (Expression e, Arguments args, Location loc)
9148 this.Arguments = args;
9151 public override Location StartLocation {
9153 return Expr.StartLocation;
9157 public override bool ContainsEmitWithAwait ()
9159 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
9163 // We perform some simple tests, and then to "split" the emit and store
9164 // code we create an instance of a different class, and return that.
9166 Expression CreateAccessExpression (ResolveContext ec)
9169 return (new ArrayAccess (this, loc));
9172 return MakePointerAccess (ec, type);
9174 FieldExpr fe = Expr as FieldExpr;
9176 var ff = fe.Spec as FixedFieldSpec;
9178 return MakePointerAccess (ec, ff.ElementType);
9182 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
9183 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9184 return new IndexerExpr (indexers, type, this);
9187 if (type != InternalType.ErrorType) {
9188 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
9189 type.GetSignatureForError ());
9195 public override Expression CreateExpressionTree (ResolveContext ec)
9197 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
9198 Expr.CreateExpressionTree (ec));
9200 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
9203 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
9205 if (Arguments.Count != 1){
9206 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
9210 if (Arguments [0] is NamedArgument)
9211 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
9213 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
9214 return new Indirection (p, loc);
9217 protected override Expression DoResolve (ResolveContext ec)
9219 Expr = Expr.Resolve (ec);
9225 // TODO: Create 1 result for Resolve and ResolveLValue ?
9226 var res = CreateAccessExpression (ec);
9230 return res.Resolve (ec);
9233 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
9235 Expr = Expr.Resolve (ec);
9241 var res = CreateAccessExpression (ec);
9245 return res.ResolveLValue (ec, rhs);
9248 public override void Emit (EmitContext ec)
9250 throw new Exception ("Should never be reached");
9253 public static void Error_NamedArgument (NamedArgument na, Report Report)
9255 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
9258 public override string GetSignatureForError ()
9260 return Expr.GetSignatureForError ();
9263 protected override void CloneTo (CloneContext clonectx, Expression t)
9265 ElementAccess target = (ElementAccess) t;
9267 target.Expr = Expr.Clone (clonectx);
9268 if (Arguments != null)
9269 target.Arguments = Arguments.Clone (clonectx);
9272 public override object Accept (StructuralVisitor visitor)
9274 return visitor.Visit (this);
9279 /// Implements array access
9281 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
9283 // Points to our "data" repository
9287 LocalTemporary temp;
9289 bool? has_await_args;
9291 public ArrayAccess (ElementAccess ea_data, Location l)
9297 public void AddressOf (EmitContext ec, AddressOp mode)
9299 var ac = (ArrayContainer) ea.Expr.Type;
9301 LoadInstanceAndArguments (ec, false, false);
9303 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
9304 ec.Emit (OpCodes.Readonly);
9306 ec.EmitArrayAddress (ac);
9309 public override Expression CreateExpressionTree (ResolveContext ec)
9311 return ea.CreateExpressionTree (ec);
9314 public override bool ContainsEmitWithAwait ()
9316 return ea.ContainsEmitWithAwait ();
9319 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9321 return DoResolve (ec);
9324 protected override Expression DoResolve (ResolveContext ec)
9326 // dynamic is used per argument in ConvertExpressionToArrayIndex case
9328 ea.Arguments.Resolve (ec, out dynamic);
9330 var ac = ea.Expr.Type as ArrayContainer;
9331 int rank = ea.Arguments.Count;
9332 if (ac.Rank != rank) {
9333 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
9334 rank.ToString (), ac.Rank.ToString ());
9339 if (type.IsPointer && !ec.IsUnsafe) {
9340 UnsafeError (ec, ea.Location);
9343 foreach (Argument a in ea.Arguments) {
9344 if (a is NamedArgument)
9345 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
9347 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
9350 eclass = ExprClass.Variable;
9355 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
9357 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
9361 // Load the array arguments into the stack.
9363 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
9366 ea.Expr = ea.Expr.EmitToField (ec);
9367 } else if (duplicateArguments) {
9369 ec.Emit (OpCodes.Dup);
9371 var copy = new LocalTemporary (ea.Expr.Type);
9378 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
9379 if (dup_args != null)
9380 ea.Arguments = dup_args;
9383 public void Emit (EmitContext ec, bool leave_copy)
9385 var ac = ea.Expr.Type as ArrayContainer;
9388 ec.EmitLoadFromPtr (type);
9390 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
9391 LoadInstanceAndArguments (ec, false, true);
9394 LoadInstanceAndArguments (ec, false, false);
9395 ec.EmitArrayLoad (ac);
9399 ec.Emit (OpCodes.Dup);
9400 temp = new LocalTemporary (this.type);
9405 public override void Emit (EmitContext ec)
9410 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9412 var ac = (ArrayContainer) ea.Expr.Type;
9413 TypeSpec t = source.Type;
9415 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
9418 // When we are dealing with a struct, get the address of it to avoid value copy
9419 // Same cannot be done for reference type because array covariance and the
9420 // check in ldelema requires to specify the type of array element stored at the index
9422 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
9423 LoadInstanceAndArguments (ec, false, has_await_args.Value);
9425 if (has_await_args.Value) {
9426 if (source.ContainsEmitWithAwait ()) {
9427 source = source.EmitToField (ec);
9432 LoadInstanceAndArguments (ec, isCompound, false);
9437 ec.EmitArrayAddress (ac);
9440 ec.Emit (OpCodes.Dup);
9444 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
9446 if (has_await_args.Value) {
9447 if (source.ContainsEmitWithAwait ())
9448 source = source.EmitToField (ec);
9450 LoadInstanceAndArguments (ec, false, false);
9457 var lt = ea.Expr as LocalTemporary;
9463 ec.Emit (OpCodes.Dup);
9464 temp = new LocalTemporary (this.type);
9469 ec.EmitStoreFromPtr (t);
9471 ec.EmitArrayStore (ac);
9480 public override Expression EmitToField (EmitContext ec)
9483 // Have to be specialized for arrays to get access to
9484 // underlying element. Instead of another result copy we
9485 // need direct access to element
9489 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
9491 ea.Expr = ea.Expr.EmitToField (ec);
9495 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9497 #if NET_4_0 || MONODROID
9498 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9500 throw new NotImplementedException ();
9504 public override SLE.Expression MakeExpression (BuilderContext ctx)
9506 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9509 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
9511 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9512 return Arguments.MakeExpression (ea.Arguments, ctx);
9518 // Indexer access expression
9520 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
9522 IList<MemberSpec> indexers;
9523 Arguments arguments;
9524 TypeSpec queried_type;
9526 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
9527 : base (ea.Location)
9529 this.indexers = indexers;
9530 this.queried_type = queriedType;
9531 this.InstanceExpression = ea.Expr;
9532 this.arguments = ea.Arguments;
9537 protected override Arguments Arguments {
9546 protected override TypeSpec DeclaringType {
9548 return best_candidate.DeclaringType;
9552 public override bool IsInstance {
9558 public override bool IsStatic {
9564 public override string KindName {
9565 get { return "indexer"; }
9568 public override string Name {
9576 public override bool ContainsEmitWithAwait ()
9578 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
9581 public override Expression CreateExpressionTree (ResolveContext ec)
9583 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
9584 InstanceExpression.CreateExpressionTree (ec),
9585 new TypeOfMethod (Getter, loc));
9587 return CreateExpressionFactoryCall (ec, "Call", args);
9590 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9592 LocalTemporary await_source_arg = null;
9595 emitting_compound_assignment = true;
9596 if (source is DynamicExpressionStatement) {
9601 emitting_compound_assignment = false;
9603 if (has_await_arguments) {
9604 await_source_arg = new LocalTemporary (Type);
9605 await_source_arg.Store (ec);
9607 arguments.Add (new Argument (await_source_arg));
9610 temp = await_source_arg;
9613 has_await_arguments = false;
9618 ec.Emit (OpCodes.Dup);
9619 temp = new LocalTemporary (Type);
9625 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9626 source = source.EmitToField (ec);
9628 temp = new LocalTemporary (Type);
9635 arguments.Add (new Argument (source));
9638 var call = new CallEmitter ();
9639 call.InstanceExpression = InstanceExpression;
9640 if (arguments == null)
9641 call.InstanceExpressionOnStack = true;
9643 call.Emit (ec, Setter, arguments, loc);
9648 } else if (leave_copy) {
9652 if (await_source_arg != null) {
9653 await_source_arg.Release (ec);
9657 public override string GetSignatureForError ()
9659 return best_candidate.GetSignatureForError ();
9662 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9665 throw new NotSupportedException ();
9667 var value = new[] { source.MakeExpression (ctx) };
9668 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9669 #if NET_4_0 || MONODROID
9670 return SLE.Expression.Block (
9671 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9674 return args.First ();
9679 public override SLE.Expression MakeExpression (BuilderContext ctx)
9682 return base.MakeExpression (ctx);
9684 var args = Arguments.MakeExpression (arguments, ctx);
9685 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9689 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9691 if (best_candidate != null)
9694 eclass = ExprClass.IndexerAccess;
9697 arguments.Resolve (rc, out dynamic);
9699 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9702 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9703 res.BaseMembersProvider = this;
9704 res.InstanceQualifier = this;
9706 // TODO: Do I need 2 argument sets?
9707 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9708 if (best_candidate != null)
9709 type = res.BestCandidateReturnType;
9710 else if (!res.BestCandidateIsDynamic)
9715 // It has dynamic arguments
9718 Arguments args = new Arguments (arguments.Count + 1);
9720 rc.Report.Error (1972, loc,
9721 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9723 args.Add (new Argument (InstanceExpression));
9725 args.AddRange (arguments);
9727 best_candidate = null;
9728 return new DynamicIndexBinder (args, loc);
9732 // Try to avoid resolving left expression again
9734 if (right_side != null)
9735 ResolveInstanceExpression (rc, right_side);
9740 protected override void CloneTo (CloneContext clonectx, Expression t)
9742 IndexerExpr target = (IndexerExpr) t;
9744 if (arguments != null)
9745 target.arguments = arguments.Clone (clonectx);
9748 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9750 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9753 #region IBaseMembersProvider Members
9755 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9757 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9760 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9762 if (queried_type == member.DeclaringType)
9765 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9766 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9769 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9778 // A base access expression
9780 public class BaseThis : This
9782 public BaseThis (Location loc)
9787 public BaseThis (TypeSpec type, Location loc)
9791 eclass = ExprClass.Variable;
9796 public override string Name {
9804 public override Expression CreateExpressionTree (ResolveContext ec)
9806 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9807 return base.CreateExpressionTree (ec);
9810 public override void Emit (EmitContext ec)
9814 var context_type = ec.CurrentType;
9815 if (context_type.IsStruct) {
9816 ec.Emit (OpCodes.Ldobj, context_type);
9817 ec.Emit (OpCodes.Box, context_type);
9821 protected override void Error_ThisNotAvailable (ResolveContext ec)
9824 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9826 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9830 public override void ResolveBase (ResolveContext ec)
9832 base.ResolveBase (ec);
9833 type = ec.CurrentType.BaseType;
9836 public override object Accept (StructuralVisitor visitor)
9838 return visitor.Visit (this);
9843 /// This class exists solely to pass the Type around and to be a dummy
9844 /// that can be passed to the conversion functions (this is used by
9845 /// foreach implementation to typecast the object return value from
9846 /// get_Current into the proper type. All code has been generated and
9847 /// we only care about the side effect conversions to be performed
9849 /// This is also now used as a placeholder where a no-action expression
9850 /// is needed (the `New' class).
9852 public class EmptyExpression : Expression
9854 sealed class OutAccessExpression : EmptyExpression
9856 public OutAccessExpression (TypeSpec t)
9861 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9863 rc.Report.Error (206, right_side.Location,
9864 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
9870 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
9871 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
9872 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
9873 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
9874 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
9875 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
9876 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
9877 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
9879 public EmptyExpression (TypeSpec t)
9882 eclass = ExprClass.Value;
9883 loc = Location.Null;
9886 public override bool ContainsEmitWithAwait ()
9891 public override Expression CreateExpressionTree (ResolveContext ec)
9893 throw new NotSupportedException ("ET");
9896 protected override Expression DoResolve (ResolveContext ec)
9901 public override void Emit (EmitContext ec)
9903 // nothing, as we only exist to not do anything.
9906 public override void EmitSideEffect (EmitContext ec)
9910 public override object Accept (StructuralVisitor visitor)
9912 return visitor.Visit (this);
9916 sealed class EmptyAwaitExpression : EmptyExpression
9918 public EmptyAwaitExpression (TypeSpec type)
9923 public override bool ContainsEmitWithAwait ()
9930 // Empty statement expression
9932 public sealed class EmptyExpressionStatement : ExpressionStatement
9934 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
9936 private EmptyExpressionStatement ()
9938 loc = Location.Null;
9941 public override bool ContainsEmitWithAwait ()
9946 public override Expression CreateExpressionTree (ResolveContext ec)
9951 public override void EmitStatement (EmitContext ec)
9956 protected override Expression DoResolve (ResolveContext ec)
9958 eclass = ExprClass.Value;
9959 type = ec.BuiltinTypes.Object;
9963 public override void Emit (EmitContext ec)
9968 public override object Accept (StructuralVisitor visitor)
9970 return visitor.Visit (this);
9974 public class ErrorExpression : EmptyExpression
9976 public static readonly ErrorExpression Instance = new ErrorExpression ();
9978 private ErrorExpression ()
9979 : base (InternalType.ErrorType)
9983 public override Expression CreateExpressionTree (ResolveContext ec)
9988 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9993 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
9997 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
10001 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
10005 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
10009 public override object Accept (StructuralVisitor visitor)
10011 return visitor.Visit (this);
10015 public class UserCast : Expression {
10019 public UserCast (MethodSpec method, Expression source, Location l)
10021 if (source == null)
10022 throw new ArgumentNullException ("source");
10024 this.method = method;
10025 this.source = source;
10026 type = method.ReturnType;
10030 public Expression Source {
10036 public override bool ContainsEmitWithAwait ()
10038 return source.ContainsEmitWithAwait ();
10041 public override Expression CreateExpressionTree (ResolveContext ec)
10043 Arguments args = new Arguments (3);
10044 args.Add (new Argument (source.CreateExpressionTree (ec)));
10045 args.Add (new Argument (new TypeOf (type, loc)));
10046 args.Add (new Argument (new TypeOfMethod (method, loc)));
10047 return CreateExpressionFactoryCall (ec, "Convert", args);
10050 protected override Expression DoResolve (ResolveContext ec)
10052 ObsoleteAttribute oa = method.GetAttributeObsolete ();
10054 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
10056 eclass = ExprClass.Value;
10060 public override void Emit (EmitContext ec)
10063 ec.MarkCallEntry (loc);
10064 ec.Emit (OpCodes.Call, method);
10067 public override string GetSignatureForError ()
10069 return TypeManager.CSharpSignature (method);
10072 public override SLE.Expression MakeExpression (BuilderContext ctx)
10075 return base.MakeExpression (ctx);
10077 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
10083 // Holds additional type specifiers like ?, *, []
10085 public class ComposedTypeSpecifier
10087 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
10089 public readonly int Dimension;
10090 public readonly Location Location;
10092 public ComposedTypeSpecifier (int specifier, Location loc)
10094 this.Dimension = specifier;
10095 this.Location = loc;
10099 public bool IsNullable {
10101 return Dimension == -1;
10105 public bool IsPointer {
10107 return Dimension == -2;
10111 public ComposedTypeSpecifier Next { get; set; }
10115 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
10117 return new ComposedTypeSpecifier (dimension, loc);
10120 public static ComposedTypeSpecifier CreateNullable (Location loc)
10122 return new ComposedTypeSpecifier (-1, loc);
10125 public static ComposedTypeSpecifier CreatePointer (Location loc)
10127 return new ComposedTypeSpecifier (-2, loc);
10130 public string GetSignatureForError ()
10135 ArrayContainer.GetPostfixSignature (Dimension);
10137 return Next != null ? s + Next.GetSignatureForError () : s;
10142 // This class is used to "construct" the type during a typecast
10143 // operation. Since the Type.GetType class in .NET can parse
10144 // the type specification, we just use this to construct the type
10145 // one bit at a time.
10147 public class ComposedCast : TypeExpr {
10148 FullNamedExpression left;
10149 ComposedTypeSpecifier spec;
10151 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
10154 throw new ArgumentNullException ("spec");
10158 this.loc = left.Location;
10161 public override TypeSpec ResolveAsType (IMemberContext ec)
10163 type = left.ResolveAsType (ec);
10167 eclass = ExprClass.Type;
10169 var single_spec = spec;
10171 if (single_spec.IsNullable) {
10172 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
10176 single_spec = single_spec.Next;
10177 } else if (single_spec.IsPointer) {
10178 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
10181 if (!ec.IsUnsafe) {
10182 UnsafeError (ec.Module.Compiler.Report, loc);
10186 type = PointerContainer.MakeType (ec.Module, type);
10187 single_spec = single_spec.Next;
10188 } while (single_spec != null && single_spec.IsPointer);
10191 if (single_spec != null && single_spec.Dimension > 0) {
10192 if (type.IsSpecialRuntimeType) {
10193 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
10194 } else if (type.IsStatic) {
10195 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
10196 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
10197 type.GetSignatureForError ());
10199 MakeArray (ec.Module, single_spec);
10206 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
10208 if (spec.Next != null)
10209 MakeArray (module, spec.Next);
10211 type = ArrayContainer.MakeType (module, type, spec.Dimension);
10214 public override string GetSignatureForError ()
10216 return left.GetSignatureForError () + spec.GetSignatureForError ();
10219 public override object Accept (StructuralVisitor visitor)
10221 return visitor.Visit (this);
10225 class FixedBufferPtr : Expression
10227 readonly Expression array;
10229 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
10231 this.type = array_type;
10232 this.array = array;
10236 public override bool ContainsEmitWithAwait ()
10238 throw new NotImplementedException ();
10241 public override Expression CreateExpressionTree (ResolveContext ec)
10243 Error_PointerInsideExpressionTree (ec);
10247 public override void Emit(EmitContext ec)
10252 protected override Expression DoResolve (ResolveContext ec)
10254 type = PointerContainer.MakeType (ec.Module, type);
10255 eclass = ExprClass.Value;
10262 // This class is used to represent the address of an array, used
10263 // only by the Fixed statement, this generates "&a [0]" construct
10264 // for fixed (char *pa = a)
10266 class ArrayPtr : FixedBufferPtr
10268 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
10269 base (array, array_type, l)
10273 public override void Emit (EmitContext ec)
10278 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
10283 // Encapsulates a conversion rules required for array indexes
10285 public class ArrayIndexCast : TypeCast
10287 public ArrayIndexCast (Expression expr, TypeSpec returnType)
10288 : base (expr, returnType)
10290 if (expr.Type == returnType) // int -> int
10291 throw new ArgumentException ("unnecessary array index conversion");
10294 public override Expression CreateExpressionTree (ResolveContext ec)
10296 using (ec.Set (ResolveContext.Options.CheckedScope)) {
10297 return base.CreateExpressionTree (ec);
10301 public override void Emit (EmitContext ec)
10305 switch (child.Type.BuiltinType) {
10306 case BuiltinTypeSpec.Type.UInt:
10307 ec.Emit (OpCodes.Conv_U);
10309 case BuiltinTypeSpec.Type.Long:
10310 ec.Emit (OpCodes.Conv_Ovf_I);
10312 case BuiltinTypeSpec.Type.ULong:
10313 ec.Emit (OpCodes.Conv_Ovf_I_Un);
10316 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
10322 // Implements the `stackalloc' keyword
10324 public class StackAlloc : Expression {
10329 public StackAlloc (Expression type, Expression count, Location l)
10332 this.count = count;
10336 public Expression TypeExpression {
10342 public Expression CountExpression {
10348 public override bool ContainsEmitWithAwait ()
10353 public override Expression CreateExpressionTree (ResolveContext ec)
10355 throw new NotSupportedException ("ET");
10358 protected override Expression DoResolve (ResolveContext ec)
10360 count = count.Resolve (ec);
10364 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
10365 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
10370 Constant c = count as Constant;
10371 if (c != null && c.IsNegative) {
10372 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
10375 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
10376 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
10379 otype = t.ResolveAsType (ec);
10383 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
10386 type = PointerContainer.MakeType (ec.Module, otype);
10387 eclass = ExprClass.Value;
10392 public override void Emit (EmitContext ec)
10394 int size = BuiltinTypeSpec.GetSize (otype);
10399 ec.Emit (OpCodes.Sizeof, otype);
10403 ec.Emit (OpCodes.Mul_Ovf_Un);
10404 ec.Emit (OpCodes.Localloc);
10407 protected override void CloneTo (CloneContext clonectx, Expression t)
10409 StackAlloc target = (StackAlloc) t;
10410 target.count = count.Clone (clonectx);
10411 target.t = t.Clone (clonectx);
10414 public override object Accept (StructuralVisitor visitor)
10416 return visitor.Visit (this);
10421 // An object initializer expression
10423 public class ElementInitializer : Assign
10425 public readonly string Name;
10427 public ElementInitializer (string name, Expression initializer, Location loc)
10428 : base (null, initializer, loc)
10433 protected override void CloneTo (CloneContext clonectx, Expression t)
10435 ElementInitializer target = (ElementInitializer) t;
10436 target.source = source.Clone (clonectx);
10439 public override Expression CreateExpressionTree (ResolveContext ec)
10441 Arguments args = new Arguments (2);
10442 FieldExpr fe = target as FieldExpr;
10444 args.Add (new Argument (fe.CreateTypeOfExpression ()));
10446 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
10449 Expression arg_expr;
10450 var cinit = source as CollectionOrObjectInitializers;
10451 if (cinit == null) {
10453 arg_expr = source.CreateExpressionTree (ec);
10455 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
10456 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
10459 args.Add (new Argument (arg_expr));
10460 return CreateExpressionFactoryCall (ec, mname, args);
10463 protected override Expression DoResolve (ResolveContext ec)
10465 if (source == null)
10466 return EmptyExpressionStatement.Instance;
10468 var t = ec.CurrentInitializerVariable.Type;
10469 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10470 Arguments args = new Arguments (1);
10471 args.Add (new Argument (ec.CurrentInitializerVariable));
10472 target = new DynamicMemberBinder (Name, args, loc);
10475 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10476 if (member == null) {
10477 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10479 if (member != null) {
10480 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
10481 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
10486 if (member == null) {
10487 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
10491 if (!(member is PropertyExpr || member is FieldExpr)) {
10492 ec.Report.Error (1913, loc,
10493 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
10494 member.GetSignatureForError ());
10499 var me = member as MemberExpr;
10501 ec.Report.Error (1914, loc,
10502 "Static field or property `{0}' cannot be assigned in an object initializer",
10503 me.GetSignatureForError ());
10507 me.InstanceExpression = ec.CurrentInitializerVariable;
10510 if (source is CollectionOrObjectInitializers) {
10511 Expression previous = ec.CurrentInitializerVariable;
10512 ec.CurrentInitializerVariable = target;
10513 source = source.Resolve (ec);
10514 ec.CurrentInitializerVariable = previous;
10515 if (source == null)
10518 eclass = source.eclass;
10519 type = source.Type;
10523 return base.DoResolve (ec);
10526 public override void EmitStatement (EmitContext ec)
10528 if (source is CollectionOrObjectInitializers)
10531 base.EmitStatement (ec);
10536 // A collection initializer expression
10538 class CollectionElementInitializer : Invocation
10540 public class ElementInitializerArgument : Argument
10542 public ElementInitializerArgument (Expression e)
10548 sealed class AddMemberAccess : MemberAccess
10550 public AddMemberAccess (Expression expr, Location loc)
10551 : base (expr, "Add", loc)
10555 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10557 if (TypeManager.HasElementType (type))
10560 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10564 public CollectionElementInitializer (Expression argument)
10565 : base (null, new Arguments (1))
10567 base.arguments.Add (new ElementInitializerArgument (argument));
10568 this.loc = argument.Location;
10571 public CollectionElementInitializer (List<Expression> arguments, Location loc)
10572 : base (null, new Arguments (arguments.Count))
10574 foreach (Expression e in arguments)
10575 base.arguments.Add (new ElementInitializerArgument (e));
10580 public CollectionElementInitializer (Location loc)
10581 : base (null, null)
10586 public override Expression CreateExpressionTree (ResolveContext ec)
10588 Arguments args = new Arguments (2);
10589 args.Add (new Argument (mg.CreateExpressionTree (ec)));
10591 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
10592 foreach (Argument a in arguments)
10593 expr_initializers.Add (a.CreateExpressionTree (ec));
10595 args.Add (new Argument (new ArrayCreation (
10596 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
10597 return CreateExpressionFactoryCall (ec, "ElementInit", args);
10600 protected override void CloneTo (CloneContext clonectx, Expression t)
10602 CollectionElementInitializer target = (CollectionElementInitializer) t;
10603 if (arguments != null)
10604 target.arguments = arguments.Clone (clonectx);
10607 protected override Expression DoResolve (ResolveContext ec)
10609 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
10611 return base.DoResolve (ec);
10616 // A block of object or collection initializers
10618 public class CollectionOrObjectInitializers : ExpressionStatement
10620 IList<Expression> initializers;
10621 bool is_collection_initialization;
10623 public CollectionOrObjectInitializers (Location loc)
10624 : this (new Expression[0], loc)
10628 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10630 this.initializers = initializers;
10634 public IList<Expression> Initializers {
10636 return initializers;
10640 public bool IsEmpty {
10642 return initializers.Count == 0;
10646 public bool IsCollectionInitializer {
10648 return is_collection_initialization;
10652 protected override void CloneTo (CloneContext clonectx, Expression target)
10654 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10656 t.initializers = new List<Expression> (initializers.Count);
10657 foreach (var e in initializers)
10658 t.initializers.Add (e.Clone (clonectx));
10661 public override bool ContainsEmitWithAwait ()
10663 foreach (var e in initializers) {
10664 if (e.ContainsEmitWithAwait ())
10671 public override Expression CreateExpressionTree (ResolveContext ec)
10673 return CreateExpressionTree (ec, false);
10676 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10678 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10679 foreach (Expression e in initializers) {
10680 Expression expr = e.CreateExpressionTree (ec);
10682 expr_initializers.Add (expr);
10686 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10688 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10691 protected override Expression DoResolve (ResolveContext ec)
10693 List<string> element_names = null;
10694 for (int i = 0; i < initializers.Count; ++i) {
10695 Expression initializer = initializers [i];
10696 ElementInitializer element_initializer = initializer as ElementInitializer;
10699 if (element_initializer != null) {
10700 element_names = new List<string> (initializers.Count);
10701 element_names.Add (element_initializer.Name);
10702 } else if (initializer is CompletingExpression){
10703 initializer.Resolve (ec);
10704 throw new InternalErrorException ("This line should never be reached");
10706 var t = ec.CurrentInitializerVariable.Type;
10707 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10708 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10709 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10710 "object initializer because type `{1}' does not implement `{2}' interface",
10711 ec.CurrentInitializerVariable.GetSignatureForError (),
10712 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10713 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10716 is_collection_initialization = true;
10719 if (is_collection_initialization != (element_initializer == null)) {
10720 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10721 is_collection_initialization ? "collection initializer" : "object initializer");
10725 if (!is_collection_initialization) {
10726 if (element_names.Contains (element_initializer.Name)) {
10727 ec.Report.Error (1912, element_initializer.Location,
10728 "An object initializer includes more than one member `{0}' initialization",
10729 element_initializer.Name);
10731 element_names.Add (element_initializer.Name);
10736 Expression e = initializer.Resolve (ec);
10737 if (e == EmptyExpressionStatement.Instance)
10738 initializers.RemoveAt (i--);
10740 initializers [i] = e;
10743 type = ec.CurrentInitializerVariable.Type;
10744 if (is_collection_initialization) {
10745 if (TypeManager.HasElementType (type)) {
10746 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10747 type.GetSignatureForError ());
10751 eclass = ExprClass.Variable;
10755 public override void Emit (EmitContext ec)
10757 EmitStatement (ec);
10760 public override void EmitStatement (EmitContext ec)
10762 foreach (ExpressionStatement e in initializers) {
10763 // TODO: need location region
10764 ec.Mark (e.Location);
10765 e.EmitStatement (ec);
10771 // New expression with element/object initializers
10773 public class NewInitialize : New
10776 // This class serves as a proxy for variable initializer target instances.
10777 // A real variable is assigned later when we resolve left side of an
10780 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10782 NewInitialize new_instance;
10784 public InitializerTargetExpression (NewInitialize newInstance)
10786 this.type = newInstance.type;
10787 this.loc = newInstance.loc;
10788 this.eclass = newInstance.eclass;
10789 this.new_instance = newInstance;
10792 public override bool ContainsEmitWithAwait ()
10797 public override Expression CreateExpressionTree (ResolveContext ec)
10799 // Should not be reached
10800 throw new NotSupportedException ("ET");
10803 protected override Expression DoResolve (ResolveContext ec)
10808 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10813 public override void Emit (EmitContext ec)
10815 Expression e = (Expression) new_instance.instance;
10819 public override Expression EmitToField (EmitContext ec)
10821 return (Expression) new_instance.instance;
10824 #region IMemoryLocation Members
10826 public void AddressOf (EmitContext ec, AddressOp mode)
10828 new_instance.instance.AddressOf (ec, mode);
10834 CollectionOrObjectInitializers initializers;
10835 IMemoryLocation instance;
10836 DynamicExpressionStatement dynamic;
10838 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10839 : base (requested_type, arguments, l)
10841 this.initializers = initializers;
10844 public CollectionOrObjectInitializers Initializers {
10846 return initializers;
10850 protected override void CloneTo (CloneContext clonectx, Expression t)
10852 base.CloneTo (clonectx, t);
10854 NewInitialize target = (NewInitialize) t;
10855 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
10858 public override bool ContainsEmitWithAwait ()
10860 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
10863 public override Expression CreateExpressionTree (ResolveContext ec)
10865 Arguments args = new Arguments (2);
10866 args.Add (new Argument (base.CreateExpressionTree (ec)));
10867 if (!initializers.IsEmpty)
10868 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
10870 return CreateExpressionFactoryCall (ec,
10871 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
10875 protected override Expression DoResolve (ResolveContext ec)
10877 Expression e = base.DoResolve (ec);
10881 if (type.IsDelegate) {
10882 ec.Report.Error (1958, Initializers.Location,
10883 "Object and collection initializers cannot be used to instantiate a delegate");
10886 Expression previous = ec.CurrentInitializerVariable;
10887 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
10888 initializers.Resolve (ec);
10889 ec.CurrentInitializerVariable = previous;
10891 dynamic = e as DynamicExpressionStatement;
10892 if (dynamic != null)
10898 public override bool Emit (EmitContext ec, IMemoryLocation target)
10900 bool left_on_stack;
10901 if (dynamic != null) {
10903 left_on_stack = true;
10905 left_on_stack = base.Emit (ec, target);
10908 if (initializers.IsEmpty)
10909 return left_on_stack;
10911 LocalTemporary temp = null;
10913 instance = target as LocalTemporary;
10915 if (instance == null) {
10916 if (!left_on_stack) {
10917 VariableReference vr = target as VariableReference;
10919 // FIXME: This still does not work correctly for pre-set variables
10920 if (vr != null && vr.IsRef)
10921 target.AddressOf (ec, AddressOp.Load);
10923 ((Expression) target).Emit (ec);
10924 left_on_stack = true;
10927 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
10928 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
10930 temp = new LocalTemporary (type);
10935 if (left_on_stack && temp != null)
10938 initializers.Emit (ec);
10940 if (left_on_stack) {
10941 if (temp != null) {
10945 ((Expression) instance).Emit (ec);
10949 return left_on_stack;
10952 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
10954 instance = base.EmitAddressOf (ec, Mode);
10956 if (!initializers.IsEmpty)
10957 initializers.Emit (ec);
10962 public override object Accept (StructuralVisitor visitor)
10964 return visitor.Visit (this);
10968 public class NewAnonymousType : New
10970 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
10972 List<AnonymousTypeParameter> parameters;
10973 readonly TypeContainer parent;
10974 AnonymousTypeClass anonymous_type;
10976 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
10977 : base (null, null, loc)
10979 this.parameters = parameters;
10980 this.parent = parent;
10983 public List<AnonymousTypeParameter> Parameters {
10985 return this.parameters;
10989 protected override void CloneTo (CloneContext clonectx, Expression target)
10991 if (parameters == null)
10994 NewAnonymousType t = (NewAnonymousType) target;
10995 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
10996 foreach (AnonymousTypeParameter atp in parameters)
10997 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
11000 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
11002 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
11006 type = AnonymousTypeClass.Create (parent, parameters, loc);
11010 int errors = ec.Report.Errors;
11011 type.CreateContainer ();
11012 type.DefineContainer ();
11014 if ((ec.Report.Errors - errors) == 0) {
11015 parent.Module.AddAnonymousType (type);
11021 public override Expression CreateExpressionTree (ResolveContext ec)
11023 if (parameters == null)
11024 return base.CreateExpressionTree (ec);
11026 var init = new ArrayInitializer (parameters.Count, loc);
11027 foreach (var m in anonymous_type.Members) {
11028 var p = m as Property;
11030 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
11033 var ctor_args = new ArrayInitializer (arguments.Count, loc);
11034 foreach (Argument a in arguments)
11035 ctor_args.Add (a.CreateExpressionTree (ec));
11037 Arguments args = new Arguments (3);
11038 args.Add (new Argument (new TypeOfMethod (method, loc)));
11039 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
11040 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
11042 return CreateExpressionFactoryCall (ec, "New", args);
11045 protected override Expression DoResolve (ResolveContext ec)
11047 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
11048 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
11052 if (parameters == null) {
11053 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
11054 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
11055 return base.DoResolve (ec);
11058 bool error = false;
11059 arguments = new Arguments (parameters.Count);
11060 var t_args = new TypeSpec [parameters.Count];
11061 for (int i = 0; i < parameters.Count; ++i) {
11062 Expression e = parameters [i].Resolve (ec);
11068 arguments.Add (new Argument (e));
11069 t_args [i] = e.Type;
11075 anonymous_type = CreateAnonymousType (ec, parameters);
11076 if (anonymous_type == null)
11079 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
11080 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
11081 eclass = ExprClass.Value;
11085 public override void EmitStatement (EmitContext ec)
11087 base.EmitStatement (ec);
11090 public override object Accept (StructuralVisitor visitor)
11092 return visitor.Visit (this);
11096 public class AnonymousTypeParameter : ShimExpression
11098 public readonly string Name;
11100 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
11101 : base (initializer)
11107 public AnonymousTypeParameter (Parameter parameter)
11108 : base (new SimpleName (parameter.Name, parameter.Location))
11110 this.Name = parameter.Name;
11111 this.loc = parameter.Location;
11114 public override bool Equals (object o)
11116 AnonymousTypeParameter other = o as AnonymousTypeParameter;
11117 return other != null && Name == other.Name;
11120 public override int GetHashCode ()
11122 return Name.GetHashCode ();
11125 protected override Expression DoResolve (ResolveContext ec)
11127 Expression e = expr.Resolve (ec);
11131 if (e.eclass == ExprClass.MethodGroup) {
11132 Error_InvalidInitializer (ec, e.ExprClassName);
11137 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
11138 Error_InvalidInitializer (ec, type.GetSignatureForError ());
11145 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
11147 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
11148 Name, initializer);