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 protected 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))
1510 // open generic type
1512 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1515 var tps = t as TypeParameterSpec;
1517 return ResolveGenericParameter (ec, d, tps);
1519 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1520 ec.Report.Warning (1981, 3, loc,
1521 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1522 OperatorName, t.GetSignatureForError ());
1525 if (TypeManager.IsGenericParameter (d))
1526 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1528 if (TypeSpec.IsValueType (d)) {
1529 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1530 if (d_is_nullable && !t_is_nullable) {
1531 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1535 return CreateConstantResult (ec, true);
1538 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1539 var c = expr as Constant;
1541 return CreateConstantResult (ec, !c.IsNull);
1544 // Do not optimize for imported type
1546 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1547 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1552 // Turn is check into simple null check for implicitly convertible reference types
1554 return ReducedExpression.Create (
1555 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1559 if (Convert.ExplicitReferenceConversionExists (d, t))
1563 // open generic type
1565 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1570 return CreateConstantResult (ec, false);
1573 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1575 if (t.IsReferenceType) {
1577 return CreateConstantResult (ec, false);
1580 if (expr.Type.IsGenericParameter) {
1581 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1582 return CreateConstantResult (ec, true);
1584 expr = new BoxedCast (expr, d);
1590 public override object Accept (StructuralVisitor visitor)
1592 return visitor.Visit (this);
1597 /// Implementation of the `as' operator.
1599 public class As : Probe {
1600 Expression resolved_type;
1602 public As (Expression expr, Expression probe_type, Location l)
1603 : base (expr, probe_type, l)
1607 protected override string OperatorName {
1608 get { return "as"; }
1611 public override Expression CreateExpressionTree (ResolveContext ec)
1613 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1614 expr.CreateExpressionTree (ec),
1615 new TypeOf (probe_type_expr, loc));
1617 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1620 public override void Emit (EmitContext ec)
1624 ec.Emit (OpCodes.Isinst, type);
1626 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1627 ec.Emit (OpCodes.Unbox_Any, type);
1630 protected override Expression DoResolve (ResolveContext ec)
1632 if (resolved_type == null) {
1633 resolved_type = base.DoResolve (ec);
1635 if (resolved_type == null)
1639 type = probe_type_expr;
1640 eclass = ExprClass.Value;
1641 TypeSpec etype = expr.Type;
1643 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1644 if (TypeManager.IsGenericParameter (type)) {
1645 ec.Report.Error (413, loc,
1646 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1647 probe_type_expr.GetSignatureForError ());
1649 ec.Report.Error (77, loc,
1650 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1651 type.GetSignatureForError ());
1656 if (expr.IsNull && type.IsNullableType) {
1657 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1660 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1661 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1665 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1667 e = EmptyCast.Create (e, type);
1668 return ReducedExpression.Create (e, this).Resolve (ec);
1671 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1672 if (TypeManager.IsGenericParameter (etype))
1673 expr = new BoxedCast (expr, etype);
1678 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1679 expr = new BoxedCast (expr, etype);
1683 if (etype != InternalType.ErrorType) {
1684 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1685 etype.GetSignatureForError (), type.GetSignatureForError ());
1691 public override object Accept (StructuralVisitor visitor)
1693 return visitor.Visit (this);
1698 // This represents a typecast in the source language.
1700 public class Cast : ShimExpression {
1701 Expression target_type;
1703 public Cast (Expression cast_type, Expression expr, Location loc)
1706 this.target_type = cast_type;
1710 public Expression TargetType {
1711 get { return target_type; }
1714 protected override Expression DoResolve (ResolveContext ec)
1716 expr = expr.Resolve (ec);
1720 type = target_type.ResolveAsType (ec);
1724 if (type.IsStatic) {
1725 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
1729 if (type.IsPointer && !ec.IsUnsafe) {
1730 UnsafeError (ec, loc);
1733 eclass = ExprClass.Value;
1735 Constant c = expr as Constant;
1737 c = c.Reduce (ec, type);
1742 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1744 return EmptyCast.Create (res, type);
1749 protected override void CloneTo (CloneContext clonectx, Expression t)
1751 Cast target = (Cast) t;
1753 target.target_type = target_type.Clone (clonectx);
1754 target.expr = expr.Clone (clonectx);
1757 public override object Accept (StructuralVisitor visitor)
1759 return visitor.Visit (this);
1763 public class ImplicitCast : ShimExpression
1767 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1770 this.loc = expr.Location;
1772 this.arrayAccess = arrayAccess;
1775 protected override Expression DoResolve (ResolveContext ec)
1777 expr = expr.Resolve (ec);
1782 expr = ConvertExpressionToArrayIndex (ec, expr);
1784 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1791 // C# 2.0 Default value expression
1793 public class DefaultValueExpression : Expression
1797 public DefaultValueExpression (Expression expr, Location loc)
1803 public Expression Expr {
1809 public override bool IsSideEffectFree {
1815 public override bool ContainsEmitWithAwait ()
1820 public override Expression CreateExpressionTree (ResolveContext ec)
1822 Arguments args = new Arguments (2);
1823 args.Add (new Argument (this));
1824 args.Add (new Argument (new TypeOf (type, loc)));
1825 return CreateExpressionFactoryCall (ec, "Constant", args);
1828 protected override Expression DoResolve (ResolveContext ec)
1830 type = expr.ResolveAsType (ec);
1834 if (type.IsStatic) {
1835 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1839 return new NullLiteral (Location).ConvertImplicitly (type);
1841 if (TypeSpec.IsReferenceType (type))
1842 return new NullConstant (type, loc);
1844 Constant c = New.Constantify (type, expr.Location);
1848 eclass = ExprClass.Variable;
1852 public override void Emit (EmitContext ec)
1854 LocalTemporary temp_storage = new LocalTemporary(type);
1856 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1857 ec.Emit(OpCodes.Initobj, type);
1858 temp_storage.Emit(ec);
1859 temp_storage.Release (ec);
1862 #if (NET_4_0 || MONODROID) && !STATIC
1863 public override SLE.Expression MakeExpression (BuilderContext ctx)
1865 return SLE.Expression.Default (type.GetMetaInfo ());
1869 protected override void CloneTo (CloneContext clonectx, Expression t)
1871 DefaultValueExpression target = (DefaultValueExpression) t;
1873 target.expr = expr.Clone (clonectx);
1876 public override object Accept (StructuralVisitor visitor)
1878 return visitor.Visit (this);
1883 /// Binary operators
1885 public class Binary : Expression, IDynamicBinder
1887 public class PredefinedOperator
1889 protected readonly TypeSpec left;
1890 protected readonly TypeSpec right;
1891 protected readonly TypeSpec left_unwrap;
1892 protected readonly TypeSpec right_unwrap;
1893 public readonly Operator OperatorsMask;
1894 public TypeSpec ReturnType;
1896 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1897 : this (ltype, rtype, op_mask, ltype)
1901 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1902 : this (type, type, op_mask, return_type)
1906 public PredefinedOperator (TypeSpec type, Operator op_mask)
1907 : this (type, type, op_mask, type)
1911 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1913 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1914 throw new InternalErrorException ("Only masked values can be used");
1916 if ((op_mask & Operator.NullableMask) != 0) {
1917 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
1918 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
1920 left_unwrap = ltype;
1921 right_unwrap = rtype;
1926 this.OperatorsMask = op_mask;
1927 this.ReturnType = return_type;
1930 public bool IsLifted {
1932 return (OperatorsMask & Operator.NullableMask) != 0;
1936 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
1940 var left_expr = b.left;
1941 var right_expr = b.right;
1943 b.type = ReturnType;
1946 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
1947 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1948 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1951 if (right_expr.IsNull) {
1952 if ((b.oper & Operator.EqualityMask) != 0) {
1953 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
1954 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
1955 } else if ((b.oper & Operator.BitwiseMask) != 0) {
1956 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
1957 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1959 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1960 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1962 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
1963 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1965 return b.CreateLiftedValueTypeResult (rc, left);
1967 } else if (left_expr.IsNull) {
1968 if ((b.oper & Operator.EqualityMask) != 0) {
1969 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
1970 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
1971 } else if ((b.oper & Operator.BitwiseMask) != 0) {
1972 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
1973 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1975 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1976 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1978 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
1979 return Nullable.LiftedNull.CreateFromExpression (rc, b);
1981 return b.CreateLiftedValueTypeResult (rc, right);
1987 // A user operators does not support multiple user conversions, but decimal type
1988 // is considered to be predefined type therefore we apply predefined operators rules
1989 // and then look for decimal user-operator implementation
1991 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
1992 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
1993 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
1995 return b.ResolveUserOperator (rc, b.left, b.right);
1998 c = right_expr as Constant;
2000 if (c.IsDefaultValue) {
2004 // (expr + 0) to expr
2005 // (expr - 0) to expr
2006 // (bool? | false) to bool?
2008 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2009 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2010 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2011 return ReducedExpression.Create (b.left, b).Resolve (rc);
2015 // Optimizes (value &/&& 0) to 0
2017 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2018 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2019 return ReducedExpression.Create (side_effect, b);
2023 // Optimizes (bool? & true) to bool?
2025 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2026 return ReducedExpression.Create (b.left, b).Resolve (rc);
2030 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2031 return ReducedExpression.Create (b.left, b).Resolve (rc);
2033 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2034 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2038 c = b.left as Constant;
2040 if (c.IsDefaultValue) {
2044 // (0 + expr) to expr
2045 // (false | bool?) to bool?
2047 if (b.oper == Operator.Addition ||
2048 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2049 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2050 return ReducedExpression.Create (b.right, b).Resolve (rc);
2054 // Optimizes (false && expr) to false
2056 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2057 // No rhs side-effects
2058 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2059 return ReducedExpression.Create (c, b);
2063 // Optimizes (0 & value) to 0
2065 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2066 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2067 return ReducedExpression.Create (side_effect, b);
2071 // Optimizes (true & bool?) to bool?
2073 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2074 return ReducedExpression.Create (b.right, b).Resolve (rc);
2078 // Optimizes (true || expr) to true
2080 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2081 // No rhs side-effects
2082 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2083 return ReducedExpression.Create (c, b);
2087 if (b.oper == Operator.Multiply && c.IsOneInteger)
2088 return ReducedExpression.Create (b.right, b).Resolve (rc);
2092 var lifted = new Nullable.LiftedBinaryOperator (b);
2094 TypeSpec ltype, rtype;
2095 if (b.left.Type.IsNullableType) {
2096 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2097 ltype = left_unwrap;
2102 if (b.right.Type.IsNullableType) {
2103 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2104 rtype = right_unwrap;
2109 lifted.Left = b.left.IsNull ?
2111 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2113 lifted.Right = b.right.IsNull ?
2115 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2117 return lifted.Resolve (rc);
2120 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2121 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2126 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2129 // We are dealing with primitive types only
2131 return left == ltype && ltype == rtype;
2134 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2137 if (left == lexpr.Type && right == rexpr.Type)
2140 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2141 Convert.ImplicitConversionExists (ec, rexpr, right);
2144 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2146 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2147 return best_operator;
2149 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2153 if (left != null && best_operator.left != null) {
2154 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2158 // When second argument is same as the first one, the result is same
2160 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2161 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2164 if (result == 0 || result > 2)
2167 return result == 1 ? best_operator : this;
2171 sealed class PredefinedStringOperator : PredefinedOperator
2173 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2174 : base (type, type, op_mask, retType)
2178 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2179 : base (ltype, rtype, op_mask, retType)
2183 public override Expression ConvertResult (ResolveContext ec, Binary b)
2186 // Use original expression for nullable arguments
2188 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2190 b.left = unwrap.Original;
2192 unwrap = b.right as Nullable.Unwrap;
2194 b.right = unwrap.Original;
2196 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2197 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2200 // Start a new concat expression using converted expression
2202 return StringConcat.Create (ec, b.left, b.right, b.loc);
2206 sealed class PredefinedEqualityOperator : PredefinedOperator
2208 MethodSpec equal_method, inequal_method;
2210 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
2211 : base (arg, arg, Operator.EqualityMask, retType)
2215 public override Expression ConvertResult (ResolveContext ec, Binary b)
2217 b.type = ReturnType;
2219 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2220 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2222 Arguments args = new Arguments (2);
2223 args.Add (new Argument (b.left));
2224 args.Add (new Argument (b.right));
2227 if (b.oper == Operator.Equality) {
2228 if (equal_method == null) {
2229 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2230 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2231 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2232 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2234 throw new NotImplementedException (left.GetSignatureForError ());
2237 method = equal_method;
2239 if (inequal_method == null) {
2240 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2241 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2242 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2243 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2245 throw new NotImplementedException (left.GetSignatureForError ());
2248 method = inequal_method;
2251 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2255 class PredefinedPointerOperator : PredefinedOperator
2257 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2258 : base (ltype, rtype, op_mask)
2262 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2263 : base (ltype, rtype, op_mask, retType)
2267 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2268 : base (type, op_mask, return_type)
2272 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2275 if (!lexpr.Type.IsPointer)
2278 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2282 if (right == null) {
2283 if (!rexpr.Type.IsPointer)
2286 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2293 public override Expression ConvertResult (ResolveContext ec, Binary b)
2296 b.left = EmptyCast.Create (b.left, left);
2297 } else if (right != null) {
2298 b.right = EmptyCast.Create (b.right, right);
2301 TypeSpec r_type = ReturnType;
2302 Expression left_arg, right_arg;
2303 if (r_type == null) {
2306 right_arg = b.right;
2307 r_type = b.left.Type;
2311 r_type = b.right.Type;
2315 right_arg = b.right;
2318 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2323 public enum Operator {
2324 Multiply = 0 | ArithmeticMask,
2325 Division = 1 | ArithmeticMask,
2326 Modulus = 2 | ArithmeticMask,
2327 Addition = 3 | ArithmeticMask | AdditionMask,
2328 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2330 LeftShift = 5 | ShiftMask,
2331 RightShift = 6 | ShiftMask,
2333 LessThan = 7 | ComparisonMask | RelationalMask,
2334 GreaterThan = 8 | ComparisonMask | RelationalMask,
2335 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2336 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2337 Equality = 11 | ComparisonMask | EqualityMask,
2338 Inequality = 12 | ComparisonMask | EqualityMask,
2340 BitwiseAnd = 13 | BitwiseMask,
2341 ExclusiveOr = 14 | BitwiseMask,
2342 BitwiseOr = 15 | BitwiseMask,
2344 LogicalAnd = 16 | LogicalMask,
2345 LogicalOr = 17 | LogicalMask,
2350 ValuesOnlyMask = ArithmeticMask - 1,
2351 ArithmeticMask = 1 << 5,
2353 ComparisonMask = 1 << 7,
2354 EqualityMask = 1 << 8,
2355 BitwiseMask = 1 << 9,
2356 LogicalMask = 1 << 10,
2357 AdditionMask = 1 << 11,
2358 SubtractionMask = 1 << 12,
2359 RelationalMask = 1 << 13,
2361 DecomposedMask = 1 << 19,
2362 NullableMask = 1 << 20,
2372 readonly Operator oper;
2373 Expression left, right;
2375 ConvCast.Mode enum_conversion;
2377 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
2378 : this (oper, left, right)
2381 state |= State.Compound;
2384 public Binary (Operator oper, Expression left, Expression right)
2389 this.loc = left.Location;
2394 public bool IsCompound {
2396 return (state & State.Compound) != 0;
2400 public Operator Oper {
2406 public Expression Left {
2412 public Expression Right {
2418 public override Location StartLocation {
2420 return left.StartLocation;
2427 /// Returns a stringified representation of the Operator
2429 string OperName (Operator oper)
2433 case Operator.Multiply:
2436 case Operator.Division:
2439 case Operator.Modulus:
2442 case Operator.Addition:
2445 case Operator.Subtraction:
2448 case Operator.LeftShift:
2451 case Operator.RightShift:
2454 case Operator.LessThan:
2457 case Operator.GreaterThan:
2460 case Operator.LessThanOrEqual:
2463 case Operator.GreaterThanOrEqual:
2466 case Operator.Equality:
2469 case Operator.Inequality:
2472 case Operator.BitwiseAnd:
2475 case Operator.BitwiseOr:
2478 case Operator.ExclusiveOr:
2481 case Operator.LogicalOr:
2484 case Operator.LogicalAnd:
2488 s = oper.ToString ();
2498 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2500 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2503 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2505 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
2509 l = left.Type.GetSignatureForError ();
2510 r = right.Type.GetSignatureForError ();
2512 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2516 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2518 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2522 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2524 string GetOperatorExpressionTypeName ()
2527 case Operator.Addition:
2528 return IsCompound ? "AddAssign" : "Add";
2529 case Operator.BitwiseAnd:
2530 return IsCompound ? "AndAssign" : "And";
2531 case Operator.BitwiseOr:
2532 return IsCompound ? "OrAssign" : "Or";
2533 case Operator.Division:
2534 return IsCompound ? "DivideAssign" : "Divide";
2535 case Operator.ExclusiveOr:
2536 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2537 case Operator.Equality:
2539 case Operator.GreaterThan:
2540 return "GreaterThan";
2541 case Operator.GreaterThanOrEqual:
2542 return "GreaterThanOrEqual";
2543 case Operator.Inequality:
2545 case Operator.LeftShift:
2546 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2547 case Operator.LessThan:
2549 case Operator.LessThanOrEqual:
2550 return "LessThanOrEqual";
2551 case Operator.LogicalAnd:
2553 case Operator.LogicalOr:
2555 case Operator.Modulus:
2556 return IsCompound ? "ModuloAssign" : "Modulo";
2557 case Operator.Multiply:
2558 return IsCompound ? "MultiplyAssign" : "Multiply";
2559 case Operator.RightShift:
2560 return IsCompound ? "RightShiftAssign" : "RightShift";
2561 case Operator.Subtraction:
2562 return IsCompound ? "SubtractAssign" : "Subtract";
2564 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2568 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2571 case Operator.Addition:
2572 return CSharp.Operator.OpType.Addition;
2573 case Operator.BitwiseAnd:
2574 case Operator.LogicalAnd:
2575 return CSharp.Operator.OpType.BitwiseAnd;
2576 case Operator.BitwiseOr:
2577 case Operator.LogicalOr:
2578 return CSharp.Operator.OpType.BitwiseOr;
2579 case Operator.Division:
2580 return CSharp.Operator.OpType.Division;
2581 case Operator.Equality:
2582 return CSharp.Operator.OpType.Equality;
2583 case Operator.ExclusiveOr:
2584 return CSharp.Operator.OpType.ExclusiveOr;
2585 case Operator.GreaterThan:
2586 return CSharp.Operator.OpType.GreaterThan;
2587 case Operator.GreaterThanOrEqual:
2588 return CSharp.Operator.OpType.GreaterThanOrEqual;
2589 case Operator.Inequality:
2590 return CSharp.Operator.OpType.Inequality;
2591 case Operator.LeftShift:
2592 return CSharp.Operator.OpType.LeftShift;
2593 case Operator.LessThan:
2594 return CSharp.Operator.OpType.LessThan;
2595 case Operator.LessThanOrEqual:
2596 return CSharp.Operator.OpType.LessThanOrEqual;
2597 case Operator.Modulus:
2598 return CSharp.Operator.OpType.Modulus;
2599 case Operator.Multiply:
2600 return CSharp.Operator.OpType.Multiply;
2601 case Operator.RightShift:
2602 return CSharp.Operator.OpType.RightShift;
2603 case Operator.Subtraction:
2604 return CSharp.Operator.OpType.Subtraction;
2606 throw new InternalErrorException (op.ToString ());
2610 public override bool ContainsEmitWithAwait ()
2612 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2615 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
2620 case Operator.Multiply:
2621 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2622 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2623 opcode = OpCodes.Mul_Ovf;
2624 else if (!IsFloat (l))
2625 opcode = OpCodes.Mul_Ovf_Un;
2627 opcode = OpCodes.Mul;
2629 opcode = OpCodes.Mul;
2633 case Operator.Division:
2635 opcode = OpCodes.Div_Un;
2637 opcode = OpCodes.Div;
2640 case Operator.Modulus:
2642 opcode = OpCodes.Rem_Un;
2644 opcode = OpCodes.Rem;
2647 case Operator.Addition:
2648 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2649 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2650 opcode = OpCodes.Add_Ovf;
2651 else if (!IsFloat (l))
2652 opcode = OpCodes.Add_Ovf_Un;
2654 opcode = OpCodes.Add;
2656 opcode = OpCodes.Add;
2659 case Operator.Subtraction:
2660 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2661 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2662 opcode = OpCodes.Sub_Ovf;
2663 else if (!IsFloat (l))
2664 opcode = OpCodes.Sub_Ovf_Un;
2666 opcode = OpCodes.Sub;
2668 opcode = OpCodes.Sub;
2671 case Operator.RightShift:
2672 if (!(right is IntConstant)) {
2673 ec.EmitInt (GetShiftMask (l));
2674 ec.Emit (OpCodes.And);
2678 opcode = OpCodes.Shr_Un;
2680 opcode = OpCodes.Shr;
2683 case Operator.LeftShift:
2684 if (!(right is IntConstant)) {
2685 ec.EmitInt (GetShiftMask (l));
2686 ec.Emit (OpCodes.And);
2689 opcode = OpCodes.Shl;
2692 case Operator.Equality:
2693 opcode = OpCodes.Ceq;
2696 case Operator.Inequality:
2697 ec.Emit (OpCodes.Ceq);
2700 opcode = OpCodes.Ceq;
2703 case Operator.LessThan:
2705 opcode = OpCodes.Clt_Un;
2707 opcode = OpCodes.Clt;
2710 case Operator.GreaterThan:
2712 opcode = OpCodes.Cgt_Un;
2714 opcode = OpCodes.Cgt;
2717 case Operator.LessThanOrEqual:
2718 if (IsUnsigned (l) || IsFloat (l))
2719 ec.Emit (OpCodes.Cgt_Un);
2721 ec.Emit (OpCodes.Cgt);
2724 opcode = OpCodes.Ceq;
2727 case Operator.GreaterThanOrEqual:
2728 if (IsUnsigned (l) || IsFloat (l))
2729 ec.Emit (OpCodes.Clt_Un);
2731 ec.Emit (OpCodes.Clt);
2735 opcode = OpCodes.Ceq;
2738 case Operator.BitwiseOr:
2739 opcode = OpCodes.Or;
2742 case Operator.BitwiseAnd:
2743 opcode = OpCodes.And;
2746 case Operator.ExclusiveOr:
2747 opcode = OpCodes.Xor;
2751 throw new InternalErrorException (oper.ToString ());
2757 static int GetShiftMask (TypeSpec type)
2759 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
2762 static bool IsUnsigned (TypeSpec t)
2764 switch (t.BuiltinType) {
2765 case BuiltinTypeSpec.Type.Char:
2766 case BuiltinTypeSpec.Type.UInt:
2767 case BuiltinTypeSpec.Type.ULong:
2768 case BuiltinTypeSpec.Type.UShort:
2769 case BuiltinTypeSpec.Type.Byte:
2776 static bool IsFloat (TypeSpec t)
2778 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2781 public Expression ResolveOperator (ResolveContext rc)
2783 eclass = ExprClass.Value;
2785 TypeSpec l = left.Type;
2786 TypeSpec r = right.Type;
2788 bool primitives_only = false;
2791 // Handles predefined primitive types
2793 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
2794 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
2795 if ((oper & Operator.ShiftMask) == 0) {
2796 if (!DoBinaryOperatorPromotion (rc))
2799 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
2803 if (l.IsPointer || r.IsPointer)
2804 return ResolveOperatorPointer (rc, l, r);
2807 expr = ResolveUserOperator (rc, left, right);
2812 bool lenum = l.IsEnum;
2813 bool renum = r.IsEnum;
2814 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2818 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2819 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
2824 if ((oper & Operator.BitwiseMask) != 0) {
2825 expr = EmptyCast.Create (expr, type);
2826 AddEnumResultCast (type);
2828 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
2829 expr = OptimizeAndOperation (expr);
2833 left = ConvertEnumOperandToUnderlyingType (rc, left);
2834 right = ConvertEnumOperandToUnderlyingType (rc, right);
2837 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
2838 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2842 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
2845 // We cannot break here there is also Enum + String possible match
2846 // which is not ambiguous with predefined enum operators
2849 left = ConvertEnumOperandToUnderlyingType (rc, left);
2850 right = ConvertEnumOperandToUnderlyingType (rc, right);
2854 } else if (l.IsDelegate || r.IsDelegate) {
2858 expr = ResolveOperatorDelegate (rc, l, r);
2860 // TODO: Can this be ambiguous
2868 // Equality operators are more complicated
2870 if ((oper & Operator.EqualityMask) != 0) {
2871 return ResolveEquality (rc, l, r, primitives_only);
2874 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
2878 if (primitives_only)
2882 // Lifted operators have lower priority
2884 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
2887 static bool IsEnumOrNullableEnum (TypeSpec type)
2889 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
2893 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2894 // if 'left' is not an enumeration constant, create one from the type of 'right'
2895 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
2898 case Operator.BitwiseOr:
2899 case Operator.BitwiseAnd:
2900 case Operator.ExclusiveOr:
2901 case Operator.Equality:
2902 case Operator.Inequality:
2903 case Operator.LessThan:
2904 case Operator.LessThanOrEqual:
2905 case Operator.GreaterThan:
2906 case Operator.GreaterThanOrEqual:
2907 if (left.Type.IsEnum)
2910 if (left.IsZeroInteger)
2911 return left.Reduce (ec, right.Type);
2915 case Operator.Addition:
2916 case Operator.Subtraction:
2919 case Operator.Multiply:
2920 case Operator.Division:
2921 case Operator.Modulus:
2922 case Operator.LeftShift:
2923 case Operator.RightShift:
2924 if (right.Type.IsEnum || left.Type.IsEnum)
2933 // The `|' operator used on types which were extended is dangerous
2935 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2937 OpcodeCast lcast = left as OpcodeCast;
2938 if (lcast != null) {
2939 if (IsUnsigned (lcast.UnderlyingType))
2943 OpcodeCast rcast = right as OpcodeCast;
2944 if (rcast != null) {
2945 if (IsUnsigned (rcast.UnderlyingType))
2949 if (lcast == null && rcast == null)
2952 // FIXME: consider constants
2954 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
2955 ec.Report.Warning (675, 3, loc,
2956 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2957 ltype.GetSignatureForError ());
2960 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
2962 return new PredefinedOperator[] {
2964 // Pointer arithmetic:
2966 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2967 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2968 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2969 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2971 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
2972 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
2973 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
2974 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
2977 // T* operator + (int y, T* x);
2978 // T* operator + (uint y, T *x);
2979 // T* operator + (long y, T *x);
2980 // T* operator + (ulong y, T *x);
2982 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
2983 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
2984 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
2985 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
2988 // long operator - (T* x, T *y)
2990 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
2994 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
2996 TypeSpec bool_type = types.Bool;
2999 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3000 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3001 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3002 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3003 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3004 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3005 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3007 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3008 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3009 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3010 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3011 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3012 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3013 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3015 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3016 // Remaining string operators are in lifted tables
3018 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3020 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3021 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3022 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3026 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3028 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3029 if (nullable == null)
3030 return new PredefinedOperator [0];
3032 var types = module.Compiler.BuiltinTypes;
3033 var bool_type = types.Bool;
3035 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3036 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3037 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3038 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3039 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3040 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3041 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3042 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3045 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3046 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3047 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3048 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3049 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3050 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3051 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3053 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3054 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3055 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3056 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3057 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3058 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3059 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3061 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3063 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3064 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3065 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3068 // Not strictly lifted but need to be in second group otherwise expressions like
3069 // int + null would resolve to +(object, string) instead of +(int?, int?)
3071 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3072 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3077 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3079 TypeSpec bool_type = types.Bool;
3082 new PredefinedEqualityOperator (types.String, bool_type),
3083 new PredefinedEqualityOperator (types.Delegate, bool_type),
3084 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3085 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3086 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3087 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3088 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3089 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3090 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3091 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3095 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3097 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3099 if (nullable == null)
3100 return new PredefinedOperator [0];
3102 var types = module.Compiler.BuiltinTypes;
3103 var bool_type = types.Bool;
3104 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3105 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3106 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3107 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3108 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3109 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3110 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3111 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3114 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3115 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3116 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3117 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3118 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3119 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3120 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3121 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3126 // 7.2.6.2 Binary numeric promotions
3128 bool DoBinaryOperatorPromotion (ResolveContext rc)
3130 TypeSpec ltype = left.Type;
3131 if (ltype.IsNullableType) {
3132 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
3136 // This is numeric promotion code only
3138 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
3141 TypeSpec rtype = right.Type;
3142 if (rtype.IsNullableType) {
3143 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
3146 var lb = ltype.BuiltinType;
3147 var rb = rtype.BuiltinType;
3151 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
3152 type = rc.BuiltinTypes.Decimal;
3153 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
3154 type = rc.BuiltinTypes.Double;
3155 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
3156 type = rc.BuiltinTypes.Float;
3157 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
3158 type = rc.BuiltinTypes.ULong;
3160 if (IsSignedType (lb)) {
3161 expr = ConvertSignedConstant (left, type);
3165 } else if (IsSignedType (rb)) {
3166 expr = ConvertSignedConstant (right, type);
3172 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
3173 type = rc.BuiltinTypes.Long;
3174 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
3175 type = rc.BuiltinTypes.UInt;
3177 if (IsSignedType (lb)) {
3178 expr = ConvertSignedConstant (left, type);
3180 type = rc.BuiltinTypes.Long;
3181 } else if (IsSignedType (rb)) {
3182 expr = ConvertSignedConstant (right, type);
3184 type = rc.BuiltinTypes.Long;
3187 type = rc.BuiltinTypes.Int;
3190 if (ltype != type) {
3191 expr = PromoteExpression (rc, left, type);
3198 if (rtype != type) {
3199 expr = PromoteExpression (rc, right, type);
3209 static bool IsSignedType (BuiltinTypeSpec.Type type)
3212 case BuiltinTypeSpec.Type.Int:
3213 case BuiltinTypeSpec.Type.Short:
3214 case BuiltinTypeSpec.Type.SByte:
3215 case BuiltinTypeSpec.Type.Long:
3222 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
3224 var c = expr as Constant;
3228 return c.ConvertImplicitly (type);
3231 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
3233 if (expr.Type.IsNullableType) {
3234 return Convert.ImplicitConversionStandard (rc, expr,
3235 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
3238 var c = expr as Constant;
3240 return c.ConvertImplicitly (type);
3242 return Convert.ImplicitNumericConversion (expr, type);
3245 protected override Expression DoResolve (ResolveContext ec)
3250 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
3251 left = ((ParenthesizedExpression) left).Expr;
3252 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
3256 if (left.eclass == ExprClass.Type) {
3257 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
3261 left = left.Resolve (ec);
3266 right = right.Resolve (ec);
3270 Constant lc = left as Constant;
3271 Constant rc = right as Constant;
3273 // The conversion rules are ignored in enum context but why
3274 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
3275 lc = EnumLiftUp (ec, lc, rc);
3277 rc = EnumLiftUp (ec, rc, lc);
3280 if (rc != null && lc != null) {
3281 int prev_e = ec.Report.Errors;
3282 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
3283 if (e != null || ec.Report.Errors != prev_e)
3287 // Comparison warnings
3288 if ((oper & Operator.ComparisonMask) != 0) {
3289 if (left.Equals (right)) {
3290 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
3292 CheckOutOfRangeComparison (ec, lc, right.Type);
3293 CheckOutOfRangeComparison (ec, rc, left.Type);
3296 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3297 return DoResolveDynamic (ec);
3299 return DoResolveCore (ec, left, right);
3302 Expression DoResolveDynamic (ResolveContext rc)
3305 var rt = right.Type;
3306 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
3307 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
3308 Error_OperatorCannotBeApplied (rc, left, right);
3315 // Special handling for logical boolean operators which require rhs not to be
3316 // evaluated based on lhs value
3318 if ((oper & Operator.LogicalMask) != 0) {
3319 Expression cond_left, cond_right, expr;
3321 args = new Arguments (2);
3323 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3324 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
3326 var cond_args = new Arguments (1);
3327 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
3330 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
3331 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
3333 left = temp.CreateReferenceExpression (rc, loc);
3334 if (oper == Operator.LogicalAnd) {
3335 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
3338 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
3342 args.Add (new Argument (left));
3343 args.Add (new Argument (right));
3344 cond_right = new DynamicExpressionStatement (this, args, loc);
3346 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
3348 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
3349 args.Add (new Argument (right));
3350 right = new DynamicExpressionStatement (this, args, loc);
3353 // bool && dynamic => (temp = left) ? temp && right : temp;
3354 // bool || dynamic => (temp = left) ? temp : temp || right;
3356 if (oper == Operator.LogicalAnd) {
3358 cond_right = temp.CreateReferenceExpression (rc, loc);
3360 cond_left = temp.CreateReferenceExpression (rc, loc);
3364 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
3367 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
3370 args = new Arguments (2);
3371 args.Add (new Argument (left));
3372 args.Add (new Argument (right));
3373 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
3376 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3378 Expression expr = ResolveOperator (ec);
3380 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3382 if (left == null || right == null)
3383 throw new InternalErrorException ("Invalid conversion");
3385 if (oper == Operator.BitwiseOr)
3386 CheckBitwiseOrOnSignExtended (ec);
3391 public override SLE.Expression MakeExpression (BuilderContext ctx)
3393 return MakeExpression (ctx, left, right);
3396 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
3398 var le = left.MakeExpression (ctx);
3399 var re = right.MakeExpression (ctx);
3400 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3403 case Operator.Addition:
3404 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3405 case Operator.BitwiseAnd:
3406 return SLE.Expression.And (le, re);
3407 case Operator.BitwiseOr:
3408 return SLE.Expression.Or (le, re);
3409 case Operator.Division:
3410 return SLE.Expression.Divide (le, re);
3411 case Operator.Equality:
3412 return SLE.Expression.Equal (le, re);
3413 case Operator.ExclusiveOr:
3414 return SLE.Expression.ExclusiveOr (le, re);
3415 case Operator.GreaterThan:
3416 return SLE.Expression.GreaterThan (le, re);
3417 case Operator.GreaterThanOrEqual:
3418 return SLE.Expression.GreaterThanOrEqual (le, re);
3419 case Operator.Inequality:
3420 return SLE.Expression.NotEqual (le, re);
3421 case Operator.LeftShift:
3422 return SLE.Expression.LeftShift (le, re);
3423 case Operator.LessThan:
3424 return SLE.Expression.LessThan (le, re);
3425 case Operator.LessThanOrEqual:
3426 return SLE.Expression.LessThanOrEqual (le, re);
3427 case Operator.LogicalAnd:
3428 return SLE.Expression.AndAlso (le, re);
3429 case Operator.LogicalOr:
3430 return SLE.Expression.OrElse (le, re);
3431 case Operator.Modulus:
3432 return SLE.Expression.Modulo (le, re);
3433 case Operator.Multiply:
3434 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3435 case Operator.RightShift:
3436 return SLE.Expression.RightShift (le, re);
3437 case Operator.Subtraction:
3438 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3440 throw new NotImplementedException (oper.ToString ());
3445 // D operator + (D x, D y)
3446 // D operator - (D x, D y)
3448 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3450 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3452 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3453 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3458 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3459 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3469 MethodSpec method = null;
3470 Arguments args = new Arguments (2);
3471 args.Add (new Argument (left));
3472 args.Add (new Argument (right));
3474 if (oper == Operator.Addition) {
3475 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3476 } else if (oper == Operator.Subtraction) {
3477 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3481 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3483 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
3484 return new ClassCast (expr, l);
3488 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
3490 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3493 // bool operator == (E x, E y);
3494 // bool operator != (E x, E y);
3495 // bool operator < (E x, E y);
3496 // bool operator > (E x, E y);
3497 // bool operator <= (E x, E y);
3498 // bool operator >= (E x, E y);
3500 // E operator & (E x, E y);
3501 // E operator | (E x, E y);
3502 // E operator ^ (E x, E y);
3505 if ((oper & Operator.ComparisonMask) != 0) {
3506 type = rc.BuiltinTypes.Bool;
3512 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3518 if (ltype == rtype) {
3522 var lifted = new Nullable.LiftedBinaryOperator (this);
3524 lifted.Right = right;
3525 return lifted.Resolve (rc);
3528 if (renum && !ltype.IsNullableType) {
3529 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
3534 } else if (lenum && !rtype.IsNullableType) {
3535 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
3543 // Now try lifted version of predefined operator
3545 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
3546 if (nullable_type != null) {
3547 if (renum && !ltype.IsNullableType) {
3548 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
3550 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3553 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3556 if ((oper & Operator.BitwiseMask) != 0)
3560 if ((oper & Operator.BitwiseMask) != 0)
3561 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3563 return CreateLiftedValueTypeResult (rc, rtype);
3567 var lifted = new Nullable.LiftedBinaryOperator (this);
3569 lifted.Right = right;
3570 return lifted.Resolve (rc);
3572 } else if (lenum && !rtype.IsNullableType) {
3573 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
3575 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3578 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3581 if ((oper & Operator.BitwiseMask) != 0)
3585 if ((oper & Operator.BitwiseMask) != 0)
3586 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3588 return CreateLiftedValueTypeResult (rc, ltype);
3592 var lifted = new Nullable.LiftedBinaryOperator (this);
3594 lifted.Right = expr;
3595 return lifted.Resolve (rc);
3597 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
3599 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3600 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
3602 if ((oper & Operator.RelationalMask) != 0)
3603 return CreateLiftedValueTypeResult (rc, rtype);
3605 if ((oper & Operator.BitwiseMask) != 0)
3606 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3608 // Equality operators are valid between E? and null
3611 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
3617 var lifted = new Nullable.LiftedBinaryOperator (this);
3619 lifted.Right = right;
3620 return lifted.Resolve (rc);
3622 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
3624 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3625 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
3627 if ((oper & Operator.RelationalMask) != 0)
3628 return CreateLiftedValueTypeResult (rc, ltype);
3630 if ((oper & Operator.BitwiseMask) != 0)
3631 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3633 // Equality operators are valid between E? and null
3636 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
3642 var lifted = new Nullable.LiftedBinaryOperator (this);
3644 lifted.Right = expr;
3645 return lifted.Resolve (rc);
3653 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr)
3655 TypeSpec underlying_type;
3656 if (expr.Type.IsNullableType) {
3657 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
3659 underlying_type = EnumSpec.GetUnderlyingType (nt);
3661 underlying_type = nt;
3662 } else if (expr.Type.IsEnum) {
3663 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
3665 underlying_type = expr.Type;
3668 switch (underlying_type.BuiltinType) {
3669 case BuiltinTypeSpec.Type.SByte:
3670 case BuiltinTypeSpec.Type.Byte:
3671 case BuiltinTypeSpec.Type.Short:
3672 case BuiltinTypeSpec.Type.UShort:
3673 underlying_type = rc.BuiltinTypes.Int;
3677 if (expr.Type.IsNullableType)
3678 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
3680 if (expr.Type == underlying_type)
3683 return EmptyCast.Create (expr, underlying_type);
3686 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3689 // U operator - (E e, E f)
3690 // E operator - (E e, U x) // Internal decomposition operator
3691 // E operator - (U x, E e) // Internal decomposition operator
3693 // E operator + (E e, U x)
3694 // E operator + (U x, E e)
3703 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3709 if (!enum_type.IsNullableType) {
3710 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
3712 if (oper == Operator.Subtraction)
3713 expr = ConvertEnumSubtractionResult (rc, expr);
3715 expr = ConvertEnumAdditionalResult (expr, enum_type);
3717 AddEnumResultCast (expr.Type);
3722 enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
3725 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
3727 if (oper == Operator.Subtraction)
3728 expr = ConvertEnumSubtractionResult (rc, expr);
3730 expr = ConvertEnumAdditionalResult (expr, enum_type);
3732 AddEnumResultCast (expr.Type);
3738 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
3740 return EmptyCast.Create (expr, enumType);
3743 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
3746 // Enumeration subtraction has different result type based on
3749 TypeSpec result_type;
3750 if (left.Type == right.Type) {
3751 var c = right as EnumConstant;
3752 if (c != null && c.IsZeroInteger) {
3754 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
3755 // E which is not what expressions E - 1 or 0 - E return
3757 result_type = left.Type;
3759 result_type = left.Type.IsNullableType ?
3760 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
3761 EnumSpec.GetUnderlyingType (left.Type);
3764 if (IsEnumOrNullableEnum (left.Type)) {
3765 result_type = left.Type;
3767 result_type = right.Type;
3770 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
3771 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
3774 return EmptyCast.Create (expr, result_type);
3777 void AddEnumResultCast (TypeSpec type)
3779 if (type.IsNullableType)
3780 type = Nullable.NullableInfo.GetUnderlyingType (type);
3783 type = EnumSpec.GetUnderlyingType (type);
3785 switch (type.BuiltinType) {
3786 case BuiltinTypeSpec.Type.SByte:
3787 enum_conversion = ConvCast.Mode.I4_I1;
3789 case BuiltinTypeSpec.Type.Byte:
3790 enum_conversion = ConvCast.Mode.I4_U1;
3792 case BuiltinTypeSpec.Type.Short:
3793 enum_conversion = ConvCast.Mode.I4_I2;
3795 case BuiltinTypeSpec.Type.UShort:
3796 enum_conversion = ConvCast.Mode.I4_U2;
3802 // Equality operators rules
3804 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
3807 type = ec.BuiltinTypes.Bool;
3808 bool no_arg_conv = false;
3810 if (!primitives_only) {
3813 // a, Both operands are reference-type values or the value null
3814 // b, One operand is a value of type T where T is a type-parameter and
3815 // the other operand is the value null. Furthermore T does not have the
3816 // value type constraint
3818 // LAMESPEC: Very confusing details in the specification, basically any
3819 // reference like type-parameter is allowed
3821 var tparam_l = l as TypeParameterSpec;
3822 var tparam_r = r as TypeParameterSpec;
3823 if (tparam_l != null) {
3824 if (right is NullLiteral) {
3825 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3828 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3832 if (!tparam_l.IsReferenceType)
3835 l = tparam_l.GetEffectiveBase ();
3836 left = new BoxedCast (left, l);
3837 } else if (left is NullLiteral && tparam_r == null) {
3838 if (TypeSpec.IsReferenceType (r))
3841 if (r.Kind == MemberKind.InternalCompilerType)
3845 if (tparam_r != null) {
3846 if (left is NullLiteral) {
3847 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3850 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3854 if (!tparam_r.IsReferenceType)
3857 r = tparam_r.GetEffectiveBase ();
3858 right = new BoxedCast (right, r);
3859 } else if (right is NullLiteral) {
3860 if (TypeSpec.IsReferenceType (l))
3863 if (l.Kind == MemberKind.InternalCompilerType)
3868 // LAMESPEC: method groups can be compared when they convert to other side delegate
3871 if (right.eclass == ExprClass.MethodGroup) {
3872 result = Convert.ImplicitConversion (ec, right, l, loc);
3878 } else if (r.IsDelegate && l != r) {
3881 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3882 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3889 no_arg_conv = l == r && !l.IsStruct;
3894 // bool operator != (string a, string b)
3895 // bool operator == (string a, string b)
3897 // bool operator != (Delegate a, Delegate b)
3898 // bool operator == (Delegate a, Delegate b)
3900 // bool operator != (bool a, bool b)
3901 // bool operator == (bool a, bool b)
3903 // LAMESPEC: Reference equality comparison can apply to value/reference types when
3904 // they implement an implicit conversion to any of types above. This does
3905 // not apply when both operands are of same reference type
3907 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3908 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
3913 // Now try lifted version of predefined operators
3915 if (no_arg_conv && !l.IsNullableType) {
3917 // Optimizes cases which won't match
3920 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
3926 // The == and != operators permit one operand to be a value of a nullable
3927 // type and the other to be the null literal, even if no predefined or user-defined
3928 // operator (in unlifted or lifted form) exists for the operation.
3930 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
3931 var lifted = new Nullable.LiftedBinaryOperator (this);
3933 lifted.Right = right;
3934 return lifted.Resolve (ec);
3939 // bool operator != (object a, object b)
3940 // bool operator == (object a, object b)
3942 // An explicit reference conversion exists from the
3943 // type of either operand to the type of the other operand.
3946 // Optimize common path
3948 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3951 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3952 !Convert.ExplicitReferenceConversionExists (r, l))
3955 // Reject allowed explicit conversions like int->object
3956 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
3959 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3960 ec.Report.Warning (253, 2, loc,
3961 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3962 l.GetSignatureForError ());
3964 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3965 ec.Report.Warning (252, 2, loc,
3966 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3967 r.GetSignatureForError ());
3973 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3976 // bool operator == (void* x, void* y);
3977 // bool operator != (void* x, void* y);
3978 // bool operator < (void* x, void* y);
3979 // bool operator > (void* x, void* y);
3980 // bool operator <= (void* x, void* y);
3981 // bool operator >= (void* x, void* y);
3983 if ((oper & Operator.ComparisonMask) != 0) {
3986 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3993 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3999 type = ec.BuiltinTypes.Bool;
4003 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4007 // Build-in operators method overloading
4009 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4011 PredefinedOperator best_operator = null;
4012 TypeSpec l = left.Type;
4013 TypeSpec r = right.Type;
4014 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4016 foreach (PredefinedOperator po in operators) {
4017 if ((po.OperatorsMask & oper_mask) == 0)
4020 if (primitives_only) {
4021 if (!po.IsPrimitiveApplicable (l, r))
4024 if (!po.IsApplicable (ec, left, right))
4028 if (best_operator == null) {
4030 if (primitives_only)
4036 best_operator = po.ResolveBetterOperator (ec, best_operator);
4038 if (best_operator == null) {
4039 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4040 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4047 if (best_operator == null)
4050 return best_operator.ConvertResult (ec, this);
4054 // Optimize & constant expressions with 0 value
4056 Expression OptimizeAndOperation (Expression expr)
4058 Constant rc = right as Constant;
4059 Constant lc = left as Constant;
4060 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4062 // The result is a constant with side-effect
4064 Constant side_effect = rc == null ?
4065 new SideEffectConstant (lc, right, loc) :
4066 new SideEffectConstant (rc, left, loc);
4068 return ReducedExpression.Create (side_effect, expr);
4075 // Value types can be compared with the null literal because of the lifting
4076 // language rules. However the result is always true or false.
4078 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4080 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4081 type = rc.BuiltinTypes.Bool;
4085 // FIXME: Handle side effect constants
4086 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4088 if ((Oper & Operator.EqualityMask) != 0) {
4089 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4090 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4092 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4093 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4100 // Performs user-operator overloading
4102 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4104 Expression oper_expr;
4106 var op = ConvertBinaryToUserOperator (oper);
4108 if (l.IsNullableType)
4109 l = Nullable.NullableInfo.GetUnderlyingType (l);
4111 if (r.IsNullableType)
4112 r = Nullable.NullableInfo.GetUnderlyingType (r);
4114 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
4115 IList<MemberSpec> right_operators = null;
4118 right_operators = MemberCache.GetUserOperator (r, op, false);
4119 if (right_operators == null && left_operators == null)
4121 } else if (left_operators == null) {
4125 Arguments args = new Arguments (2);
4126 Argument larg = new Argument (left);
4128 Argument rarg = new Argument (right);
4132 // User-defined operator implementations always take precedence
4133 // over predefined operator implementations
4135 if (left_operators != null && right_operators != null) {
4136 left_operators = CombineUserOperators (left_operators, right_operators);
4137 } else if (right_operators != null) {
4138 left_operators = right_operators;
4141 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
4142 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
4144 var res = new OverloadResolver (left_operators, restr, loc);
4146 var oper_method = res.ResolveOperator (rc, ref args);
4147 if (oper_method == null) {
4149 // Logical && and || cannot be lifted
4151 if ((oper & Operator.LogicalMask) != 0)
4155 // Apply lifted user operators only for liftable types. Implicit conversion
4156 // to nullable types is not allowed
4158 if (!IsLiftedOperatorApplicable ())
4161 // TODO: Cache the result in module container
4162 var lifted_methods = CreateLiftedOperators (rc, left_operators);
4163 if (lifted_methods == null)
4166 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
4168 oper_method = res.ResolveOperator (rc, ref args);
4169 if (oper_method == null)
4172 MethodSpec best_original = null;
4173 foreach (MethodSpec ms in left_operators) {
4174 if (ms.MemberDefinition == oper_method.MemberDefinition) {
4180 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4182 // Expression trees use lifted notation in this case
4184 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
4185 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
4188 var ptypes = best_original.Parameters.Types;
4190 if (left.IsNull || right.IsNull) {
4192 // The lifted operator produces the value false if one or both operands are null for
4193 // relational operators.
4195 if ((oper & Operator.ComparisonMask) != 0) {
4197 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
4198 // because return type is actually bool
4200 // For some reason CSC does not report this warning for equality operators
4202 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
4205 // The lifted operator produces a null value if one or both operands are null
4207 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
4208 type = oper_method.ReturnType;
4209 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4213 type = oper_method.ReturnType;
4214 var lifted = new Nullable.LiftedBinaryOperator (this);
4215 lifted.UserOperator = best_original;
4217 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
4218 lifted.UnwrapLeft = new Nullable.Unwrap (left);
4221 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
4222 lifted.UnwrapRight = new Nullable.Unwrap (right);
4225 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
4226 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
4228 return lifted.Resolve (rc);
4231 if ((oper & Operator.LogicalMask) != 0) {
4232 // TODO: CreateExpressionTree is allocated every time
4233 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
4234 oper == Operator.LogicalAnd, loc).Resolve (rc);
4236 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
4239 this.left = larg.Expr;
4240 this.right = rarg.Expr;
4245 bool IsLiftedOperatorApplicable ()
4247 if (left.Type.IsNullableType) {
4248 if ((oper & Operator.EqualityMask) != 0)
4249 return !right.IsNull;
4254 if (right.Type.IsNullableType) {
4255 if ((oper & Operator.EqualityMask) != 0)
4256 return !left.IsNull;
4261 if (TypeSpec.IsValueType (left.Type))
4262 return right.IsNull;
4264 if (TypeSpec.IsValueType (right.Type))
4270 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
4272 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4273 if (nullable_type == null)
4277 // Lifted operators permit predefined and user-defined operators that operate
4278 // on non-nullable value types to also be used with nullable forms of those types.
4279 // Lifted operators are constructed from predefined and user-defined operators
4280 // that meet certain requirements
4282 List<MemberSpec> lifted = null;
4283 foreach (MethodSpec oper in operators) {
4285 if ((Oper & Operator.ComparisonMask) != 0) {
4287 // Result type must be of type bool for lifted comparison operators
4289 rt = oper.ReturnType;
4290 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
4293 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
4299 var ptypes = oper.Parameters.Types;
4300 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
4304 // LAMESPEC: I am not sure why but for equality operators to be lifted
4305 // both types have to match
4307 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
4311 lifted = new List<MemberSpec> ();
4314 // The lifted form is constructed by adding a single ? modifier to each operand and
4315 // result type except for comparison operators where return type is bool
4318 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
4320 var parameters = ParametersCompiled.CreateFullyResolved (
4321 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
4322 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
4324 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
4325 rt, parameters, oper.Modifiers);
4327 lifted.Add (lifted_op);
4334 // Merge two sets of user operators into one, they are mostly distinguish
4335 // except when they share base type and it contains an operator
4337 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
4339 var combined = new List<MemberSpec> (left.Count + right.Count);
4340 combined.AddRange (left);
4341 foreach (var r in right) {
4343 foreach (var l in left) {
4344 if (l.DeclaringType == r.DeclaringType) {
4357 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
4359 if (c is IntegralConstant || c is CharConstant) {
4361 c.ConvertExplicitly (true, type);
4362 } catch (OverflowException) {
4363 ec.Report.Warning (652, 2, loc,
4364 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
4365 type.GetSignatureForError ());
4371 /// EmitBranchable is called from Statement.EmitBoolExpression in the
4372 /// context of a conditional bool expression. This function will return
4373 /// false if it is was possible to use EmitBranchable, or true if it was.
4375 /// The expression's code is generated, and we will generate a branch to `target'
4376 /// if the resulting expression value is equal to isTrue
4378 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
4380 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4381 left = left.EmitToField (ec);
4383 if ((oper & Operator.LogicalMask) == 0) {
4384 right = right.EmitToField (ec);
4389 // This is more complicated than it looks, but its just to avoid
4390 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
4391 // but on top of that we want for == and != to use a special path
4392 // if we are comparing against null
4394 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
4395 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
4398 // put the constant on the rhs, for simplicity
4400 if (left is Constant) {
4401 Expression swap = right;
4407 // brtrue/brfalse works with native int only
4409 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
4410 left.EmitBranchable (ec, target, my_on_true);
4413 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
4414 // right is a boolean, and it's not 'false' => it is 'true'
4415 left.EmitBranchable (ec, target, !my_on_true);
4419 } else if (oper == Operator.LogicalAnd) {
4422 Label tests_end = ec.DefineLabel ();
4424 left.EmitBranchable (ec, tests_end, false);
4425 right.EmitBranchable (ec, target, true);
4426 ec.MarkLabel (tests_end);
4429 // This optimizes code like this
4430 // if (true && i > 4)
4432 if (!(left is Constant))
4433 left.EmitBranchable (ec, target, false);
4435 if (!(right is Constant))
4436 right.EmitBranchable (ec, target, false);
4441 } else if (oper == Operator.LogicalOr){
4443 left.EmitBranchable (ec, target, true);
4444 right.EmitBranchable (ec, target, true);
4447 Label tests_end = ec.DefineLabel ();
4448 left.EmitBranchable (ec, tests_end, true);
4449 right.EmitBranchable (ec, target, false);
4450 ec.MarkLabel (tests_end);
4455 } else if ((oper & Operator.ComparisonMask) == 0) {
4456 base.EmitBranchable (ec, target, on_true);
4463 TypeSpec t = left.Type;
4464 bool is_float = IsFloat (t);
4465 bool is_unsigned = is_float || IsUnsigned (t);
4468 case Operator.Equality:
4470 ec.Emit (OpCodes.Beq, target);
4472 ec.Emit (OpCodes.Bne_Un, target);
4475 case Operator.Inequality:
4477 ec.Emit (OpCodes.Bne_Un, target);
4479 ec.Emit (OpCodes.Beq, target);
4482 case Operator.LessThan:
4484 if (is_unsigned && !is_float)
4485 ec.Emit (OpCodes.Blt_Un, target);
4487 ec.Emit (OpCodes.Blt, target);
4490 ec.Emit (OpCodes.Bge_Un, target);
4492 ec.Emit (OpCodes.Bge, target);
4495 case Operator.GreaterThan:
4497 if (is_unsigned && !is_float)
4498 ec.Emit (OpCodes.Bgt_Un, target);
4500 ec.Emit (OpCodes.Bgt, target);
4503 ec.Emit (OpCodes.Ble_Un, target);
4505 ec.Emit (OpCodes.Ble, target);
4508 case Operator.LessThanOrEqual:
4510 if (is_unsigned && !is_float)
4511 ec.Emit (OpCodes.Ble_Un, target);
4513 ec.Emit (OpCodes.Ble, target);
4516 ec.Emit (OpCodes.Bgt_Un, target);
4518 ec.Emit (OpCodes.Bgt, target);
4522 case Operator.GreaterThanOrEqual:
4524 if (is_unsigned && !is_float)
4525 ec.Emit (OpCodes.Bge_Un, target);
4527 ec.Emit (OpCodes.Bge, target);
4530 ec.Emit (OpCodes.Blt_Un, target);
4532 ec.Emit (OpCodes.Blt, target);
4535 throw new InternalErrorException (oper.ToString ());
4539 public override void Emit (EmitContext ec)
4541 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4542 left = left.EmitToField (ec);
4544 if ((oper & Operator.LogicalMask) == 0) {
4545 right = right.EmitToField (ec);
4550 // Handle short-circuit operators differently
4553 if ((oper & Operator.LogicalMask) != 0) {
4554 Label load_result = ec.DefineLabel ();
4555 Label end = ec.DefineLabel ();
4557 bool is_or = oper == Operator.LogicalOr;
4558 left.EmitBranchable (ec, load_result, is_or);
4560 ec.Emit (OpCodes.Br_S, end);
4562 ec.MarkLabel (load_result);
4563 ec.EmitInt (is_or ? 1 : 0);
4569 // Optimize zero-based operations which cannot be optimized at expression level
4571 if (oper == Operator.Subtraction) {
4572 var lc = left as IntegralConstant;
4573 if (lc != null && lc.IsDefaultValue) {
4575 ec.Emit (OpCodes.Neg);
4580 EmitOperator (ec, left, right);
4583 public void EmitOperator (EmitContext ec, Expression left, Expression right)
4588 EmitOperatorOpcode (ec, oper, left.Type, right);
4591 // Emit result enumerable conversion this way because it's quite complicated get it
4592 // to resolved tree because expression tree cannot see it.
4594 if (enum_conversion != 0)
4595 ConvCast.Emit (ec, enum_conversion);
4598 public override void EmitSideEffect (EmitContext ec)
4600 if ((oper & Operator.LogicalMask) != 0 ||
4601 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
4602 base.EmitSideEffect (ec);
4604 left.EmitSideEffect (ec);
4605 right.EmitSideEffect (ec);
4609 public override Expression EmitToField (EmitContext ec)
4611 if ((oper & Operator.LogicalMask) == 0) {
4612 var await_expr = left as Await;
4613 if (await_expr != null && right.IsSideEffectFree) {
4614 await_expr.Statement.EmitPrologue (ec);
4615 left = await_expr.Statement.GetResultExpression (ec);
4619 await_expr = right as Await;
4620 if (await_expr != null && left.IsSideEffectFree) {
4621 await_expr.Statement.EmitPrologue (ec);
4622 right = await_expr.Statement.GetResultExpression (ec);
4627 return base.EmitToField (ec);
4630 protected override void CloneTo (CloneContext clonectx, Expression t)
4632 Binary target = (Binary) t;
4634 target.left = left.Clone (clonectx);
4635 target.right = right.Clone (clonectx);
4638 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
4640 Arguments binder_args = new Arguments (4);
4642 MemberAccess sle = new MemberAccess (new MemberAccess (
4643 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
4645 CSharpBinderFlags flags = 0;
4646 if (ec.HasSet (ResolveContext.Options.CheckedScope))
4647 flags = CSharpBinderFlags.CheckedContext;
4649 if ((oper & Operator.LogicalMask) != 0)
4650 flags |= CSharpBinderFlags.BinaryOperationLogical;
4652 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
4653 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
4654 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
4655 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
4657 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
4660 public override Expression CreateExpressionTree (ResolveContext ec)
4662 return CreateExpressionTree (ec, null);
4665 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
4668 bool lift_arg = false;
4671 case Operator.Addition:
4672 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4673 method_name = "AddChecked";
4675 method_name = "Add";
4677 case Operator.BitwiseAnd:
4678 method_name = "And";
4680 case Operator.BitwiseOr:
4683 case Operator.Division:
4684 method_name = "Divide";
4686 case Operator.Equality:
4687 method_name = "Equal";
4690 case Operator.ExclusiveOr:
4691 method_name = "ExclusiveOr";
4693 case Operator.GreaterThan:
4694 method_name = "GreaterThan";
4697 case Operator.GreaterThanOrEqual:
4698 method_name = "GreaterThanOrEqual";
4701 case Operator.Inequality:
4702 method_name = "NotEqual";
4705 case Operator.LeftShift:
4706 method_name = "LeftShift";
4708 case Operator.LessThan:
4709 method_name = "LessThan";
4712 case Operator.LessThanOrEqual:
4713 method_name = "LessThanOrEqual";
4716 case Operator.LogicalAnd:
4717 method_name = "AndAlso";
4719 case Operator.LogicalOr:
4720 method_name = "OrElse";
4722 case Operator.Modulus:
4723 method_name = "Modulo";
4725 case Operator.Multiply:
4726 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4727 method_name = "MultiplyChecked";
4729 method_name = "Multiply";
4731 case Operator.RightShift:
4732 method_name = "RightShift";
4734 case Operator.Subtraction:
4735 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4736 method_name = "SubtractChecked";
4738 method_name = "Subtract";
4742 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4745 Arguments args = new Arguments (2);
4746 args.Add (new Argument (left.CreateExpressionTree (ec)));
4747 args.Add (new Argument (right.CreateExpressionTree (ec)));
4748 if (method != null) {
4750 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4752 args.Add (new Argument (method));
4755 return CreateExpressionFactoryCall (ec, method_name, args);
4758 public override object Accept (StructuralVisitor visitor)
4760 return visitor.Visit (this);
4766 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4767 // b, c, d... may be strings or objects.
4769 public class StringConcat : Expression
4771 Arguments arguments;
4773 StringConcat (Location loc)
4776 arguments = new Arguments (2);
4779 public override bool ContainsEmitWithAwait ()
4781 return arguments.ContainsEmitWithAwait ();
4784 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4786 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4787 throw new ArgumentException ();
4789 var s = new StringConcat (loc);
4790 s.type = rc.BuiltinTypes.String;
4791 s.eclass = ExprClass.Value;
4793 s.Append (rc, left);
4794 s.Append (rc, right);
4798 public override Expression CreateExpressionTree (ResolveContext ec)
4800 Argument arg = arguments [0];
4801 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4805 // Creates nested calls tree from an array of arguments used for IL emit
4807 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4809 Arguments concat_args = new Arguments (2);
4810 Arguments add_args = new Arguments (3);
4812 concat_args.Add (left);
4813 add_args.Add (new Argument (left_etree));
4815 concat_args.Add (arguments [pos]);
4816 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4818 var methods = GetConcatMethodCandidates ();
4819 if (methods == null)
4822 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4823 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4827 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4829 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4830 if (++pos == arguments.Count)
4833 left = new Argument (new EmptyExpression (method.ReturnType));
4834 return CreateExpressionAddCall (ec, left, expr, pos);
4837 protected override Expression DoResolve (ResolveContext ec)
4842 void Append (ResolveContext rc, Expression operand)
4847 StringConstant sc = operand as StringConstant;
4849 if (arguments.Count != 0) {
4850 Argument last_argument = arguments [arguments.Count - 1];
4851 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4852 if (last_expr_constant != null) {
4853 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4859 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4861 StringConcat concat_oper = operand as StringConcat;
4862 if (concat_oper != null) {
4863 arguments.AddRange (concat_oper.arguments);
4868 arguments.Add (new Argument (operand));
4871 IList<MemberSpec> GetConcatMethodCandidates ()
4873 return MemberCache.FindMembers (type, "Concat", true);
4876 public override void Emit (EmitContext ec)
4878 // Optimize by removing any extra null arguments, they are no-op
4879 for (int i = 0; i < arguments.Count; ++i) {
4880 if (arguments[i].Expr is NullConstant)
4881 arguments.RemoveAt (i--);
4884 var members = GetConcatMethodCandidates ();
4885 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4886 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4887 if (method != null) {
4888 var call = new CallEmitter ();
4889 call.EmitPredefined (ec, method, arguments);
4893 public override SLE.Expression MakeExpression (BuilderContext ctx)
4895 if (arguments.Count != 2)
4896 throw new NotImplementedException ("arguments.Count != 2");
4898 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4899 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4904 // User-defined conditional logical operator
4906 public class ConditionalLogicalOperator : UserOperatorCall
4908 readonly bool is_and;
4909 Expression oper_expr;
4911 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4912 : base (oper, arguments, expr_tree, loc)
4914 this.is_and = is_and;
4915 eclass = ExprClass.Unresolved;
4918 protected override Expression DoResolve (ResolveContext ec)
4920 AParametersCollection pd = oper.Parameters;
4921 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4922 ec.Report.Error (217, loc,
4923 "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",
4924 oper.GetSignatureForError ());
4928 Expression left_dup = new EmptyExpression (type);
4929 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4930 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4931 if (op_true == null || op_false == null) {
4932 ec.Report.Error (218, loc,
4933 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4934 type.GetSignatureForError (), oper.GetSignatureForError ());
4938 oper_expr = is_and ? op_false : op_true;
4939 eclass = ExprClass.Value;
4943 public override void Emit (EmitContext ec)
4945 Label end_target = ec.DefineLabel ();
4948 // Emit and duplicate left argument
4950 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
4951 if (right_contains_await) {
4952 arguments[0] = arguments[0].EmitToField (ec, false);
4953 arguments[0].Expr.Emit (ec);
4955 arguments[0].Expr.Emit (ec);
4956 ec.Emit (OpCodes.Dup);
4957 arguments.RemoveAt (0);
4960 oper_expr.EmitBranchable (ec, end_target, true);
4964 if (right_contains_await) {
4966 // Special handling when right expression contains await and left argument
4967 // could not be left on stack before logical branch
4969 Label skip_left_load = ec.DefineLabel ();
4970 ec.Emit (OpCodes.Br_S, skip_left_load);
4971 ec.MarkLabel (end_target);
4972 arguments[0].Expr.Emit (ec);
4973 ec.MarkLabel (skip_left_load);
4975 ec.MarkLabel (end_target);
4980 public class PointerArithmetic : Expression {
4981 Expression left, right;
4982 readonly Binary.Operator op;
4985 // We assume that `l' is always a pointer
4987 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4996 public override bool ContainsEmitWithAwait ()
4998 throw new NotImplementedException ();
5001 public override Expression CreateExpressionTree (ResolveContext ec)
5003 Error_PointerInsideExpressionTree (ec);
5007 protected override Expression DoResolve (ResolveContext ec)
5009 eclass = ExprClass.Variable;
5011 var pc = left.Type as PointerContainer;
5012 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5013 Error_VoidPointerOperation (ec);
5020 public override void Emit (EmitContext ec)
5022 TypeSpec op_type = left.Type;
5024 // It must be either array or fixed buffer
5026 if (TypeManager.HasElementType (op_type)) {
5027 element = TypeManager.GetElementType (op_type);
5029 FieldExpr fe = left as FieldExpr;
5031 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5036 int size = BuiltinTypeSpec.GetSize(element);
5037 TypeSpec rtype = right.Type;
5039 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5041 // handle (pointer - pointer)
5045 ec.Emit (OpCodes.Sub);
5049 ec.Emit (OpCodes.Sizeof, element);
5052 ec.Emit (OpCodes.Div);
5054 ec.Emit (OpCodes.Conv_I8);
5057 // handle + and - on (pointer op int)
5059 Constant left_const = left as Constant;
5060 if (left_const != null) {
5062 // Optimize ((T*)null) pointer operations
5064 if (left_const.IsDefaultValue) {
5065 left = EmptyExpression.Null;
5073 var right_const = right as Constant;
5074 if (right_const != null) {
5076 // Optimize 0-based arithmetic
5078 if (right_const.IsDefaultValue)
5082 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5084 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5086 // TODO: Should be the checks resolve context sensitive?
5087 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5088 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5094 switch (rtype.BuiltinType) {
5095 case BuiltinTypeSpec.Type.SByte:
5096 case BuiltinTypeSpec.Type.Byte:
5097 case BuiltinTypeSpec.Type.Short:
5098 case BuiltinTypeSpec.Type.UShort:
5099 ec.Emit (OpCodes.Conv_I);
5101 case BuiltinTypeSpec.Type.UInt:
5102 ec.Emit (OpCodes.Conv_U);
5106 if (right_const == null && size != 1){
5108 ec.Emit (OpCodes.Sizeof, element);
5111 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5112 ec.Emit (OpCodes.Conv_I8);
5114 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
5117 if (left_const == null) {
5118 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
5119 ec.Emit (OpCodes.Conv_I);
5120 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5121 ec.Emit (OpCodes.Conv_U);
5123 Binary.EmitOperatorOpcode (ec, op, op_type, right);
5130 // A boolean-expression is an expression that yields a result
5133 public class BooleanExpression : ShimExpression
5135 public BooleanExpression (Expression expr)
5138 this.loc = expr.Location;
5141 public override Expression CreateExpressionTree (ResolveContext ec)
5143 // TODO: We should emit IsTrue (v4) instead of direct user operator
5144 // call but that would break csc compatibility
5145 return base.CreateExpressionTree (ec);
5148 protected override Expression DoResolve (ResolveContext ec)
5150 // A boolean-expression is required to be of a type
5151 // that can be implicitly converted to bool or of
5152 // a type that implements operator true
5154 expr = expr.Resolve (ec);
5158 Assign ass = expr as Assign;
5159 if (ass != null && ass.Source is Constant) {
5160 ec.Report.Warning (665, 3, loc,
5161 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
5164 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
5167 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5168 Arguments args = new Arguments (1);
5169 args.Add (new Argument (expr));
5170 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
5173 type = ec.BuiltinTypes.Bool;
5174 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
5175 if (converted != null)
5179 // If no implicit conversion to bool exists, try using `operator true'
5181 converted = GetOperatorTrue (ec, expr, loc);
5182 if (converted == null) {
5183 expr.Error_ValueCannotBeConverted (ec, type, false);
5190 public override object Accept (StructuralVisitor visitor)
5192 return visitor.Visit (this);
5196 public class BooleanExpressionFalse : Unary
5198 public BooleanExpressionFalse (Expression expr)
5199 : base (Operator.LogicalNot, expr, expr.Location)
5203 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
5205 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
5210 /// Implements the ternary conditional operator (?:)
5212 public class Conditional : Expression {
5213 Expression expr, true_expr, false_expr;
5215 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
5218 this.true_expr = true_expr;
5219 this.false_expr = false_expr;
5225 public Expression Expr {
5231 public Expression TrueExpr {
5237 public Expression FalseExpr {
5245 public override bool ContainsEmitWithAwait ()
5247 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
5250 public override Expression CreateExpressionTree (ResolveContext ec)
5252 Arguments args = new Arguments (3);
5253 args.Add (new Argument (expr.CreateExpressionTree (ec)));
5254 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
5255 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
5256 return CreateExpressionFactoryCall (ec, "Condition", args);
5259 protected override Expression DoResolve (ResolveContext ec)
5261 expr = expr.Resolve (ec);
5264 // Unreachable code needs different resolve path. For instance for await
5265 // expression to not generate unreachable resumable statement
5267 Constant c = expr as Constant;
5268 if (c != null && ec.CurrentBranching != null) {
5269 bool unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
5271 if (c.IsDefaultValue) {
5272 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
5273 true_expr = true_expr.Resolve (ec);
5274 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
5276 false_expr = false_expr.Resolve (ec);
5278 true_expr = true_expr.Resolve (ec);
5280 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = true;
5281 false_expr = false_expr.Resolve (ec);
5282 ec.CurrentBranching.CurrentUsageVector.IsUnreachable = unreachable;
5285 true_expr = true_expr.Resolve (ec);
5286 false_expr = false_expr.Resolve (ec);
5289 if (true_expr == null || false_expr == null || expr == null)
5292 eclass = ExprClass.Value;
5293 TypeSpec true_type = true_expr.Type;
5294 TypeSpec false_type = false_expr.Type;
5298 // First, if an implicit conversion exists from true_expr
5299 // to false_expr, then the result type is of type false_expr.Type
5301 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
5302 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
5303 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5305 // Check if both can convert implicitly to each other's type
5309 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5310 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
5312 // LAMESPEC: There seems to be hardcoded promotition to int type when
5313 // both sides are numeric constants and one side is int constant and
5314 // other side is numeric constant convertible to int.
5316 // var res = condition ? (short)1 : 1;
5318 // Type of res is int even if according to the spec the conversion is
5319 // ambiguous because 1 literal can be converted to short.
5321 if (conv_false_expr != null) {
5322 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
5324 conv_false_expr = null;
5325 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
5326 conv_false_expr = null;
5330 if (conv_false_expr != null) {
5331 ec.Report.Error (172, true_expr.Location,
5332 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
5333 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5338 if (true_expr.Type != type)
5339 true_expr = EmptyCast.Create (true_expr, type);
5340 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
5343 ec.Report.Error (173, true_expr.Location,
5344 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
5345 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5351 bool is_false = c.IsDefaultValue;
5354 // Don't issue the warning for constant expressions
5356 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
5357 // CSC: Missing warning
5358 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
5361 return ReducedExpression.Create (
5362 is_false ? false_expr : true_expr, this,
5363 false_expr is Constant && true_expr is Constant).Resolve (ec);
5369 public override void Emit (EmitContext ec)
5371 Label false_target = ec.DefineLabel ();
5372 Label end_target = ec.DefineLabel ();
5374 expr.EmitBranchable (ec, false_target, false);
5375 true_expr.Emit (ec);
5378 // Verifier doesn't support interface merging. When there are two types on
5379 // the stack without common type hint and the common type is an interface.
5380 // Use temporary local to give verifier hint on what type to unify the stack
5382 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
5383 var temp = ec.GetTemporaryLocal (type);
5384 ec.Emit (OpCodes.Stloc, temp);
5385 ec.Emit (OpCodes.Ldloc, temp);
5386 ec.FreeTemporaryLocal (temp, type);
5389 ec.Emit (OpCodes.Br, end_target);
5390 ec.MarkLabel (false_target);
5391 false_expr.Emit (ec);
5392 ec.MarkLabel (end_target);
5395 protected override void CloneTo (CloneContext clonectx, Expression t)
5397 Conditional target = (Conditional) t;
5399 target.expr = expr.Clone (clonectx);
5400 target.true_expr = true_expr.Clone (clonectx);
5401 target.false_expr = false_expr.Clone (clonectx);
5405 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
5407 LocalTemporary temp;
5410 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
5411 public abstract void SetHasAddressTaken ();
5412 public abstract void VerifyDefiniteAssignment (ResolveContext rc);
5414 public abstract bool IsLockedByStatement { get; set; }
5416 public abstract bool IsFixed { get; }
5417 public abstract bool IsRef { get; }
5418 public abstract string Name { get; }
5421 // Variable IL data, it has to be protected to encapsulate hoisted variables
5423 protected abstract ILocalVariable Variable { get; }
5426 // Variable flow-analysis data
5428 public abstract VariableInfo VariableInfo { get; }
5431 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5433 HoistedVariable hv = GetHoistedVariable (ec);
5435 hv.AddressOf (ec, mode);
5439 Variable.EmitAddressOf (ec);
5442 public override bool ContainsEmitWithAwait ()
5447 public override Expression CreateExpressionTree (ResolveContext ec)
5449 HoistedVariable hv = GetHoistedVariable (ec);
5451 return hv.CreateExpressionTree ();
5453 Arguments arg = new Arguments (1);
5454 arg.Add (new Argument (this));
5455 return CreateExpressionFactoryCall (ec, "Constant", arg);
5458 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
5460 if (IsLockedByStatement) {
5461 rc.Report.Warning (728, 2, loc,
5462 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
5469 public override void Emit (EmitContext ec)
5474 public override void EmitSideEffect (EmitContext ec)
5480 // This method is used by parameters that are references, that are
5481 // being passed as references: we only want to pass the pointer (that
5482 // is already stored in the parameter, not the address of the pointer,
5483 // and not the value of the variable).
5485 public void EmitLoad (EmitContext ec)
5490 public void Emit (EmitContext ec, bool leave_copy)
5492 HoistedVariable hv = GetHoistedVariable (ec);
5494 hv.Emit (ec, leave_copy);
5502 // If we are a reference, we loaded on the stack a pointer
5503 // Now lets load the real value
5505 ec.EmitLoadFromPtr (type);
5509 ec.Emit (OpCodes.Dup);
5512 temp = new LocalTemporary (Type);
5518 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
5519 bool prepare_for_load)
5521 HoistedVariable hv = GetHoistedVariable (ec);
5523 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
5527 New n_source = source as New;
5528 if (n_source != null) {
5529 if (!n_source.Emit (ec, this)) {
5533 ec.EmitLoadFromPtr (type);
5545 ec.Emit (OpCodes.Dup);
5547 temp = new LocalTemporary (Type);
5553 ec.EmitStoreFromPtr (type);
5555 Variable.EmitAssign (ec);
5563 public override Expression EmitToField (EmitContext ec)
5565 HoistedVariable hv = GetHoistedVariable (ec);
5567 return hv.EmitToField (ec);
5570 return base.EmitToField (ec);
5573 public HoistedVariable GetHoistedVariable (ResolveContext rc)
5575 return GetHoistedVariable (rc.CurrentAnonymousMethod);
5578 public HoistedVariable GetHoistedVariable (EmitContext ec)
5580 return GetHoistedVariable (ec.CurrentAnonymousMethod);
5583 public override string GetSignatureForError ()
5588 public bool IsHoisted {
5589 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
5594 // Resolved reference to a local variable
5596 public class LocalVariableReference : VariableReference
5598 public LocalVariable local_info;
5600 public LocalVariableReference (LocalVariable li, Location l)
5602 this.local_info = li;
5606 public override VariableInfo VariableInfo {
5607 get { return local_info.VariableInfo; }
5610 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5612 return local_info.HoistedVariant;
5618 // A local variable is always fixed
5620 public override bool IsFixed {
5626 public override bool IsLockedByStatement {
5628 return local_info.IsLocked;
5631 local_info.IsLocked = value;
5635 public override bool IsRef {
5636 get { return false; }
5639 public override string Name {
5640 get { return local_info.Name; }
5645 public override void VerifyDefiniteAssignment (ResolveContext rc)
5647 VariableInfo variable_info = VariableInfo;
5648 if (variable_info == null)
5651 if (variable_info.IsAssigned (rc))
5654 rc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
5655 variable_info.SetAssigned (rc);
5658 public override void SetHasAddressTaken ()
5660 local_info.SetHasAddressTaken ();
5663 void DoResolveBase (ResolveContext ec)
5666 // If we are referencing a variable from the external block
5667 // flag it for capturing
5669 if (ec.MustCaptureVariable (local_info)) {
5670 if (local_info.AddressTaken) {
5671 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5672 } else if (local_info.IsFixed) {
5673 ec.Report.Error (1764, loc,
5674 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
5675 GetSignatureForError ());
5678 if (ec.IsVariableCapturingRequired) {
5679 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
5680 storey.CaptureLocalVariable (ec, local_info);
5684 eclass = ExprClass.Variable;
5685 type = local_info.Type;
5688 protected override Expression DoResolve (ResolveContext ec)
5690 local_info.SetIsUsed ();
5692 VerifyDefiniteAssignment (ec);
5698 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5701 // Don't be too pedantic when variable is used as out param or for some broken code
5702 // which uses property/indexer access to run some initialization
5704 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5705 local_info.SetIsUsed ();
5707 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5710 if (rhs == EmptyExpression.OutAccess) {
5711 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5712 } else if (rhs == EmptyExpression.LValueMemberAccess) {
5713 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
5714 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5715 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5716 } else if (rhs == EmptyExpression.UnaryAddress) {
5717 code = 459; msg = "Cannot take the address of {1} `{0}'";
5719 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5721 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5722 } else if (VariableInfo != null) {
5723 VariableInfo.SetAssigned (ec);
5726 if (eclass == ExprClass.Unresolved)
5729 return base.DoResolveLValue (ec, rhs);
5732 public override int GetHashCode ()
5734 return local_info.GetHashCode ();
5737 public override bool Equals (object obj)
5739 LocalVariableReference lvr = obj as LocalVariableReference;
5743 return local_info == lvr.local_info;
5746 protected override ILocalVariable Variable {
5747 get { return local_info; }
5750 public override string ToString ()
5752 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5755 protected override void CloneTo (CloneContext clonectx, Expression t)
5762 /// This represents a reference to a parameter in the intermediate
5765 public class ParameterReference : VariableReference
5767 protected ParametersBlock.ParameterInfo pi;
5769 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5777 public override bool IsLockedByStatement {
5782 pi.IsLocked = value;
5786 public override bool IsRef {
5787 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5790 bool HasOutModifier {
5791 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5794 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5796 return pi.Parameter.HoistedVariant;
5800 // A ref or out parameter is classified as a moveable variable, even
5801 // if the argument given for the parameter is a fixed variable
5803 public override bool IsFixed {
5804 get { return !IsRef; }
5807 public override string Name {
5808 get { return Parameter.Name; }
5811 public Parameter Parameter {
5812 get { return pi.Parameter; }
5815 public override VariableInfo VariableInfo {
5816 get { return pi.VariableInfo; }
5819 protected override ILocalVariable Variable {
5820 get { return Parameter; }
5825 public override void AddressOf (EmitContext ec, AddressOp mode)
5828 // ParameterReferences might already be a reference
5835 base.AddressOf (ec, mode);
5838 public override void SetHasAddressTaken ()
5840 Parameter.HasAddressTaken = true;
5843 void SetAssigned (ResolveContext ec)
5845 if (Parameter.HoistedVariant != null)
5846 Parameter.HoistedVariant.IsAssigned = true;
5848 if (HasOutModifier && ec.DoFlowAnalysis)
5849 ec.CurrentBranching.SetAssigned (VariableInfo);
5852 bool DoResolveBase (ResolveContext ec)
5854 if (eclass != ExprClass.Unresolved)
5857 type = pi.ParameterType;
5858 eclass = ExprClass.Variable;
5861 // If we are referencing a parameter from the external block
5862 // flag it for capturing
5864 if (ec.MustCaptureVariable (pi)) {
5865 if (Parameter.HasAddressTaken)
5866 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5869 ec.Report.Error (1628, loc,
5870 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5871 Name, ec.CurrentAnonymousMethod.ContainerType);
5874 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5875 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
5876 storey.CaptureParameter (ec, pi, this);
5883 public override int GetHashCode ()
5885 return Name.GetHashCode ();
5888 public override bool Equals (object obj)
5890 ParameterReference pr = obj as ParameterReference;
5894 return Name == pr.Name;
5897 protected override void CloneTo (CloneContext clonectx, Expression target)
5903 public override Expression CreateExpressionTree (ResolveContext ec)
5905 HoistedVariable hv = GetHoistedVariable (ec);
5907 return hv.CreateExpressionTree ();
5909 return Parameter.ExpressionTreeVariableReference ();
5912 protected override Expression DoResolve (ResolveContext ec)
5914 if (!DoResolveBase (ec))
5917 VerifyDefiniteAssignment (ec);
5921 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5923 if (!DoResolveBase (ec))
5927 return base.DoResolveLValue (ec, right_side);
5930 public override void VerifyDefiniteAssignment (ResolveContext rc)
5932 VariableInfo variable_info = VariableInfo;
5933 if (variable_info == null)
5936 if (variable_info.IsAssigned (rc))
5939 rc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
5940 variable_info.SetAssigned (rc);
5945 /// Invocation of methods or delegates.
5947 public class Invocation : ExpressionStatement
5949 protected Arguments arguments;
5950 protected Expression expr;
5951 protected MethodGroupExpr mg;
5953 public Invocation (Expression expr, Arguments arguments)
5956 this.arguments = arguments;
5958 loc = expr.Location;
5963 public Arguments Arguments {
5969 public Expression Exp {
5975 public MethodGroupExpr MethodGroup {
5981 public override Location StartLocation {
5983 return expr.StartLocation;
5989 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
5991 if (MethodGroup == null)
5994 var candidate = MethodGroup.BestCandidate;
5995 if (candidate == null || !(candidate.IsStatic || Exp is This))
5998 var args_count = arguments == null ? 0 : arguments.Count;
5999 if (args_count != body.Parameters.Count)
6002 var lambda_parameters = body.Block.Parameters.FixedParameters;
6003 for (int i = 0; i < args_count; ++i) {
6004 var pr = arguments[i].Expr as ParameterReference;
6008 if (lambda_parameters[i] != pr.Parameter)
6011 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6015 var emg = MethodGroup as ExtensionMethodGroupExpr;
6017 return MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6023 protected override void CloneTo (CloneContext clonectx, Expression t)
6025 Invocation target = (Invocation) t;
6027 if (arguments != null)
6028 target.arguments = arguments.Clone (clonectx);
6030 target.expr = expr.Clone (clonectx);
6033 public override bool ContainsEmitWithAwait ()
6035 if (arguments != null && arguments.ContainsEmitWithAwait ())
6038 return mg.ContainsEmitWithAwait ();
6041 public override Expression CreateExpressionTree (ResolveContext ec)
6043 Expression instance = mg.IsInstance ?
6044 mg.InstanceExpression.CreateExpressionTree (ec) :
6045 new NullLiteral (loc);
6047 var args = Arguments.CreateForExpressionTree (ec, arguments,
6049 mg.CreateExpressionTree (ec));
6051 return CreateExpressionFactoryCall (ec, "Call", args);
6054 protected override Expression DoResolve (ResolveContext ec)
6056 Expression member_expr;
6057 var atn = expr as ATypeNameExpression;
6059 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
6060 if (member_expr != null)
6061 member_expr = member_expr.Resolve (ec);
6063 member_expr = expr.Resolve (ec);
6066 if (member_expr == null)
6070 // Next, evaluate all the expressions in the argument list
6072 bool dynamic_arg = false;
6073 if (arguments != null)
6074 arguments.Resolve (ec, out dynamic_arg);
6076 TypeSpec expr_type = member_expr.Type;
6077 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6078 return DoResolveDynamic (ec, member_expr);
6080 mg = member_expr as MethodGroupExpr;
6081 Expression invoke = null;
6084 if (expr_type != null && expr_type.IsDelegate) {
6085 invoke = new DelegateInvocation (member_expr, arguments, loc);
6086 invoke = invoke.Resolve (ec);
6087 if (invoke == null || !dynamic_arg)
6090 if (member_expr is RuntimeValueExpression) {
6091 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
6092 member_expr.Type.GetSignatureForError ());
6096 MemberExpr me = member_expr as MemberExpr;
6098 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
6102 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
6103 member_expr.GetSignatureForError ());
6108 if (invoke == null) {
6109 mg = DoResolveOverload (ec);
6115 return DoResolveDynamic (ec, member_expr);
6117 var method = mg.BestCandidate;
6118 type = mg.BestCandidateReturnType;
6120 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
6122 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
6124 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
6128 IsSpecialMethodInvocation (ec, method, loc);
6130 eclass = ExprClass.Value;
6134 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
6137 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
6139 args = dmb.Arguments;
6140 if (arguments != null)
6141 args.AddRange (arguments);
6142 } else if (mg == null) {
6143 if (arguments == null)
6144 args = new Arguments (1);
6148 args.Insert (0, new Argument (memberExpr));
6152 ec.Report.Error (1971, loc,
6153 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
6158 if (arguments == null)
6159 args = new Arguments (1);
6163 MemberAccess ma = expr as MemberAccess;
6165 var left_type = ma.LeftExpression as TypeExpr;
6166 if (left_type != null) {
6167 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6170 // Any value type has to be pass as by-ref to get back the same
6171 // instance on which the member was called
6173 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
6174 Argument.AType.Ref : Argument.AType.None;
6175 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
6177 } else { // is SimpleName
6179 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6181 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
6186 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
6189 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
6191 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
6194 public override string GetSignatureForError ()
6196 return mg.GetSignatureForError ();
6200 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
6201 // or the type dynamic, then the member is invocable
6203 public static bool IsMemberInvocable (MemberSpec member)
6205 switch (member.Kind) {
6206 case MemberKind.Event:
6208 case MemberKind.Field:
6209 case MemberKind.Property:
6210 var m = member as IInterfaceMemberSpec;
6211 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
6217 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
6219 if (!method.IsReservedMethod)
6222 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
6225 ec.Report.SymbolRelatedToPreviousError (method);
6226 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
6227 method.GetSignatureForError ());
6232 public override void Emit (EmitContext ec)
6234 mg.EmitCall (ec, arguments);
6237 public override void EmitStatement (EmitContext ec)
6242 // Pop the return value if there is one
6244 if (type.Kind != MemberKind.Void)
6245 ec.Emit (OpCodes.Pop);
6248 public override SLE.Expression MakeExpression (BuilderContext ctx)
6250 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
6253 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
6256 throw new NotSupportedException ();
6258 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
6259 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
6263 public override object Accept (StructuralVisitor visitor)
6265 return visitor.Visit (this);
6270 // Implements simple new expression
6272 public class New : ExpressionStatement, IMemoryLocation
6274 protected Arguments arguments;
6277 // During bootstrap, it contains the RequestedType,
6278 // but if `type' is not null, it *might* contain a NewDelegate
6279 // (because of field multi-initialization)
6281 protected Expression RequestedType;
6283 protected MethodSpec method;
6285 public New (Expression requested_type, Arguments arguments, Location l)
6287 RequestedType = requested_type;
6288 this.arguments = arguments;
6293 public Arguments Arguments {
6300 // Returns true for resolved `new S()'
6302 public bool IsDefaultStruct {
6304 return arguments == null && type.IsStruct && GetType () == typeof (New);
6308 public Expression TypeExpression {
6310 return RequestedType;
6317 /// Converts complex core type syntax like 'new int ()' to simple constant
6319 public static Constant Constantify (TypeSpec t, Location loc)
6321 switch (t.BuiltinType) {
6322 case BuiltinTypeSpec.Type.Int:
6323 return new IntConstant (t, 0, loc);
6324 case BuiltinTypeSpec.Type.UInt:
6325 return new UIntConstant (t, 0, loc);
6326 case BuiltinTypeSpec.Type.Long:
6327 return new LongConstant (t, 0, loc);
6328 case BuiltinTypeSpec.Type.ULong:
6329 return new ULongConstant (t, 0, loc);
6330 case BuiltinTypeSpec.Type.Float:
6331 return new FloatConstant (t, 0, loc);
6332 case BuiltinTypeSpec.Type.Double:
6333 return new DoubleConstant (t, 0, loc);
6334 case BuiltinTypeSpec.Type.Short:
6335 return new ShortConstant (t, 0, loc);
6336 case BuiltinTypeSpec.Type.UShort:
6337 return new UShortConstant (t, 0, loc);
6338 case BuiltinTypeSpec.Type.SByte:
6339 return new SByteConstant (t, 0, loc);
6340 case BuiltinTypeSpec.Type.Byte:
6341 return new ByteConstant (t, 0, loc);
6342 case BuiltinTypeSpec.Type.Char:
6343 return new CharConstant (t, '\0', loc);
6344 case BuiltinTypeSpec.Type.Bool:
6345 return new BoolConstant (t, false, loc);
6346 case BuiltinTypeSpec.Type.Decimal:
6347 return new DecimalConstant (t, 0, loc);
6351 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
6353 if (t.IsNullableType)
6354 return Nullable.LiftedNull.Create (t, loc);
6359 public override bool ContainsEmitWithAwait ()
6361 return arguments != null && arguments.ContainsEmitWithAwait ();
6365 // Checks whether the type is an interface that has the
6366 // [ComImport, CoClass] attributes and must be treated
6369 public Expression CheckComImport (ResolveContext ec)
6371 if (!type.IsInterface)
6375 // Turn the call into:
6376 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
6378 var real_class = type.MemberDefinition.GetAttributeCoClass ();
6379 if (real_class == null)
6382 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
6383 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
6384 return cast.Resolve (ec);
6387 public override Expression CreateExpressionTree (ResolveContext ec)
6390 if (method == null) {
6391 args = new Arguments (1);
6392 args.Add (new Argument (new TypeOf (type, loc)));
6394 args = Arguments.CreateForExpressionTree (ec,
6395 arguments, new TypeOfMethod (method, loc));
6398 return CreateExpressionFactoryCall (ec, "New", args);
6401 protected override Expression DoResolve (ResolveContext ec)
6403 type = RequestedType.ResolveAsType (ec);
6407 eclass = ExprClass.Value;
6409 if (type.IsPointer) {
6410 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
6411 type.GetSignatureForError ());
6415 if (arguments == null) {
6416 Constant c = Constantify (type, RequestedType.Location);
6418 return ReducedExpression.Create (c, this);
6421 if (type.IsDelegate) {
6422 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
6425 var tparam = type as TypeParameterSpec;
6426 if (tparam != null) {
6428 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
6429 // where type parameter constraint is inflated to struct
6431 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
6432 ec.Report.Error (304, loc,
6433 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
6434 type.GetSignatureForError ());
6437 if ((arguments != null) && (arguments.Count != 0)) {
6438 ec.Report.Error (417, loc,
6439 "`{0}': cannot provide arguments when creating an instance of a variable type",
6440 type.GetSignatureForError ());
6446 if (type.IsStatic) {
6447 ec.Report.SymbolRelatedToPreviousError (type);
6448 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
6452 if (type.IsInterface || type.IsAbstract){
6453 if (!TypeManager.IsGenericType (type)) {
6454 RequestedType = CheckComImport (ec);
6455 if (RequestedType != null)
6456 return RequestedType;
6459 ec.Report.SymbolRelatedToPreviousError (type);
6460 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
6465 // Any struct always defines parameterless constructor
6467 if (type.IsStruct && arguments == null)
6471 if (arguments != null) {
6472 arguments.Resolve (ec, out dynamic);
6477 method = ConstructorLookup (ec, type, ref arguments, loc);
6480 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6481 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
6487 bool DoEmitTypeParameter (EmitContext ec)
6489 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
6493 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
6494 var tparam = (TypeParameterSpec) type;
6496 if (tparam.IsReferenceType) {
6497 ec.Emit (OpCodes.Call, ctor_factory);
6501 // Allow DoEmit() to be called multiple times.
6502 // We need to create a new LocalTemporary each time since
6503 // you can't share LocalBuilders among ILGeneators.
6504 LocalTemporary temp = new LocalTemporary (type);
6506 Label label_activator = ec.DefineLabel ();
6507 Label label_end = ec.DefineLabel ();
6509 temp.AddressOf (ec, AddressOp.Store);
6510 ec.Emit (OpCodes.Initobj, type);
6513 ec.Emit (OpCodes.Box, type);
6514 ec.Emit (OpCodes.Brfalse, label_activator);
6516 temp.AddressOf (ec, AddressOp.Store);
6517 ec.Emit (OpCodes.Initobj, type);
6520 ec.Emit (OpCodes.Br_S, label_end);
6522 ec.MarkLabel (label_activator);
6524 ec.Emit (OpCodes.Call, ctor_factory);
6525 ec.MarkLabel (label_end);
6530 // This Emit can be invoked in two contexts:
6531 // * As a mechanism that will leave a value on the stack (new object)
6532 // * As one that wont (init struct)
6534 // If we are dealing with a ValueType, we have a few
6535 // situations to deal with:
6537 // * The target is a ValueType, and we have been provided
6538 // the instance (this is easy, we are being assigned).
6540 // * The target of New is being passed as an argument,
6541 // to a boxing operation or a function that takes a
6544 // In this case, we need to create a temporary variable
6545 // that is the argument of New.
6547 // Returns whether a value is left on the stack
6549 // *** Implementation note ***
6551 // To benefit from this optimization, each assignable expression
6552 // has to manually cast to New and call this Emit.
6554 // TODO: It's worth to implement it for arrays and fields
6556 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
6558 bool is_value_type = TypeSpec.IsValueType (type);
6559 VariableReference vr = target as VariableReference;
6561 if (target != null && is_value_type && (vr != null || method == null)) {
6562 target.AddressOf (ec, AddressOp.Store);
6563 } else if (vr != null && vr.IsRef) {
6567 if (arguments != null) {
6568 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
6569 arguments = arguments.Emit (ec, false, true);
6571 arguments.Emit (ec);
6574 if (is_value_type) {
6575 if (method == null) {
6576 ec.Emit (OpCodes.Initobj, type);
6581 ec.MarkCallEntry (loc);
6582 ec.Emit (OpCodes.Call, method);
6587 if (type is TypeParameterSpec)
6588 return DoEmitTypeParameter (ec);
6590 ec.MarkCallEntry (loc);
6591 ec.Emit (OpCodes.Newobj, method);
6595 public override void Emit (EmitContext ec)
6597 LocalTemporary v = null;
6598 if (method == null && TypeSpec.IsValueType (type)) {
6599 // TODO: Use temporary variable from pool
6600 v = new LocalTemporary (type);
6607 public override void EmitStatement (EmitContext ec)
6609 LocalTemporary v = null;
6610 if (method == null && TypeSpec.IsValueType (type)) {
6611 // TODO: Use temporary variable from pool
6612 v = new LocalTemporary (type);
6616 ec.Emit (OpCodes.Pop);
6619 public void AddressOf (EmitContext ec, AddressOp mode)
6621 EmitAddressOf (ec, mode);
6624 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
6626 LocalTemporary value_target = new LocalTemporary (type);
6628 if (type is TypeParameterSpec) {
6629 DoEmitTypeParameter (ec);
6630 value_target.Store (ec);
6631 value_target.AddressOf (ec, mode);
6632 return value_target;
6635 value_target.AddressOf (ec, AddressOp.Store);
6637 if (method == null) {
6638 ec.Emit (OpCodes.Initobj, type);
6640 if (arguments != null)
6641 arguments.Emit (ec);
6643 ec.Emit (OpCodes.Call, method);
6646 value_target.AddressOf (ec, mode);
6647 return value_target;
6650 protected override void CloneTo (CloneContext clonectx, Expression t)
6652 New target = (New) t;
6654 target.RequestedType = RequestedType.Clone (clonectx);
6655 if (arguments != null){
6656 target.arguments = arguments.Clone (clonectx);
6660 public override SLE.Expression MakeExpression (BuilderContext ctx)
6663 return base.MakeExpression (ctx);
6665 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
6669 public override object Accept (StructuralVisitor visitor)
6671 return visitor.Visit (this);
6676 // Array initializer expression, the expression is allowed in
6677 // variable or field initialization only which makes it tricky as
6678 // the type has to be infered based on the context either from field
6679 // type or variable type (think of multiple declarators)
6681 public class ArrayInitializer : Expression
6683 List<Expression> elements;
6684 BlockVariable variable;
6686 public ArrayInitializer (List<Expression> init, Location loc)
6692 public ArrayInitializer (int count, Location loc)
6693 : this (new List<Expression> (count), loc)
6697 public ArrayInitializer (Location loc)
6705 get { return elements.Count; }
6708 public List<Expression> Elements {
6714 public Expression this [int index] {
6716 return elements [index];
6720 public BlockVariable VariableDeclaration {
6731 public void Add (Expression expr)
6733 elements.Add (expr);
6736 public override bool ContainsEmitWithAwait ()
6738 throw new NotSupportedException ();
6741 public override Expression CreateExpressionTree (ResolveContext ec)
6743 throw new NotSupportedException ("ET");
6746 protected override void CloneTo (CloneContext clonectx, Expression t)
6748 var target = (ArrayInitializer) t;
6750 target.elements = new List<Expression> (elements.Count);
6751 foreach (var element in elements)
6752 target.elements.Add (element.Clone (clonectx));
6755 protected override Expression DoResolve (ResolveContext rc)
6757 var current_field = rc.CurrentMemberDefinition as FieldBase;
6758 TypeExpression type;
6759 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6760 type = new TypeExpression (current_field.MemberType, current_field.Location);
6761 } else if (variable != null) {
6762 if (variable.TypeExpression is VarExpr) {
6763 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6764 return EmptyExpression.Null;
6767 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6769 throw new NotImplementedException ("Unexpected array initializer context");
6772 return new ArrayCreation (type, this).Resolve (rc);
6775 public override void Emit (EmitContext ec)
6777 throw new InternalErrorException ("Missing Resolve call");
6780 public override object Accept (StructuralVisitor visitor)
6782 return visitor.Visit (this);
6787 /// 14.5.10.2: Represents an array creation expression.
6791 /// There are two possible scenarios here: one is an array creation
6792 /// expression that specifies the dimensions and optionally the
6793 /// initialization data and the other which does not need dimensions
6794 /// specified but where initialization data is mandatory.
6796 public class ArrayCreation : Expression
6798 FullNamedExpression requested_base_type;
6799 ArrayInitializer initializers;
6802 // The list of Argument types.
6803 // This is used to construct the `newarray' or constructor signature
6805 protected List<Expression> arguments;
6807 protected TypeSpec array_element_type;
6809 protected int dimensions;
6810 protected readonly ComposedTypeSpecifier rank;
6811 Expression first_emit;
6812 LocalTemporary first_emit_temp;
6814 protected List<Expression> array_data;
6816 Dictionary<int, int> bounds;
6819 // The number of constants in array initializers
6820 int const_initializers_count;
6821 bool only_constant_initializers;
6823 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6824 : this (requested_base_type, rank, initializers, l)
6826 arguments = new List<Expression> (exprs);
6827 num_arguments = arguments.Count;
6831 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6833 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6835 this.requested_base_type = requested_base_type;
6837 this.initializers = initializers;
6841 num_arguments = rank.Dimension;
6845 // For compiler generated single dimensional arrays only
6847 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6848 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6853 // For expressions like int[] foo = { 1, 2, 3 };
6855 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6856 : this (requested_base_type, null, initializers, initializers.Location)
6860 public ComposedTypeSpecifier Rank {
6866 public FullNamedExpression TypeExpression {
6868 return this.requested_base_type;
6872 public ArrayInitializer Initializers {
6874 return this.initializers;
6878 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6880 if (initializers != null && bounds == null) {
6882 // We use this to store all the data values in the order in which we
6883 // will need to store them in the byte blob later
6885 array_data = new List<Expression> (probe.Count);
6886 bounds = new Dictionary<int, int> ();
6889 if (specified_dims) {
6890 Expression a = arguments [idx];
6895 a = ConvertExpressionToArrayIndex (ec, a);
6901 if (initializers != null) {
6902 Constant c = a as Constant;
6903 if (c == null && a is ArrayIndexCast)
6904 c = ((ArrayIndexCast) a).Child as Constant;
6907 ec.Report.Error (150, a.Location, "A constant value is expected");
6913 value = System.Convert.ToInt32 (c.GetValue ());
6915 ec.Report.Error (150, a.Location, "A constant value is expected");
6919 // TODO: probe.Count does not fit ulong in
6920 if (value != probe.Count) {
6921 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6925 bounds[idx] = value;
6929 if (initializers == null)
6932 for (int i = 0; i < probe.Count; ++i) {
6934 if (o is ArrayInitializer) {
6935 var sub_probe = o as ArrayInitializer;
6936 if (idx + 1 >= dimensions){
6937 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6941 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
6942 if (!bounds.ContainsKey(idx + 1))
6943 bounds[idx + 1] = sub_probe.Count;
6945 if (bounds[idx + 1] != sub_probe.Count) {
6946 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
6950 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6953 } else if (child_bounds > 1) {
6954 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6956 Expression element = ResolveArrayElement (ec, o);
6957 if (element == null)
6960 // Initializers with the default values can be ignored
6961 Constant c = element as Constant;
6963 if (!c.IsDefaultInitializer (array_element_type)) {
6964 ++const_initializers_count;
6967 only_constant_initializers = false;
6970 array_data.Add (element);
6977 public override bool ContainsEmitWithAwait ()
6979 foreach (var arg in arguments) {
6980 if (arg.ContainsEmitWithAwait ())
6984 return InitializersContainAwait ();
6987 public override Expression CreateExpressionTree (ResolveContext ec)
6991 if (array_data == null) {
6992 args = new Arguments (arguments.Count + 1);
6993 args.Add (new Argument (new TypeOf (array_element_type, loc)));
6994 foreach (Expression a in arguments)
6995 args.Add (new Argument (a.CreateExpressionTree (ec)));
6997 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7000 if (dimensions > 1) {
7001 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7005 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7006 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7007 if (array_data != null) {
7008 for (int i = 0; i < array_data.Count; ++i) {
7009 Expression e = array_data [i];
7010 args.Add (new Argument (e.CreateExpressionTree (ec)));
7014 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7017 void UpdateIndices (ResolveContext rc)
7020 for (var probe = initializers; probe != null;) {
7021 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7023 bounds[i++] = probe.Count;
7025 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7026 probe = (ArrayInitializer) probe[0];
7027 } else if (dimensions > i) {
7035 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7037 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
7040 bool InitializersContainAwait ()
7042 if (array_data == null)
7045 foreach (var expr in array_data) {
7046 if (expr.ContainsEmitWithAwait ())
7053 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
7055 element = element.Resolve (ec);
7056 if (element == null)
7059 if (element is CompoundAssign.TargetExpression) {
7060 if (first_emit != null)
7061 throw new InternalErrorException ("Can only handle one mutator at a time");
7062 first_emit = element;
7063 element = first_emit_temp = new LocalTemporary (element.Type);
7066 return Convert.ImplicitConversionRequired (
7067 ec, element, array_element_type, loc);
7070 protected bool ResolveInitializers (ResolveContext ec)
7073 only_constant_initializers = true;
7076 if (arguments != null) {
7078 for (int i = 0; i < arguments.Count; ++i) {
7079 res &= CheckIndices (ec, initializers, i, true, dimensions);
7080 if (initializers != null)
7087 arguments = new List<Expression> ();
7089 if (!CheckIndices (ec, initializers, 0, false, dimensions))
7098 // Resolved the type of the array
7100 bool ResolveArrayType (ResolveContext ec)
7105 FullNamedExpression array_type_expr;
7106 if (num_arguments > 0) {
7107 array_type_expr = new ComposedCast (requested_base_type, rank);
7109 array_type_expr = requested_base_type;
7112 type = array_type_expr.ResolveAsType (ec);
7113 if (array_type_expr == null)
7116 var ac = type as ArrayContainer;
7118 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
7122 array_element_type = ac.Element;
7123 dimensions = ac.Rank;
7128 protected override Expression DoResolve (ResolveContext ec)
7133 if (!ResolveArrayType (ec))
7137 // validate the initializers and fill in any missing bits
7139 if (!ResolveInitializers (ec))
7142 eclass = ExprClass.Value;
7146 byte [] MakeByteBlob ()
7151 int count = array_data.Count;
7153 TypeSpec element_type = array_element_type;
7154 if (element_type.IsEnum)
7155 element_type = EnumSpec.GetUnderlyingType (element_type);
7157 factor = BuiltinTypeSpec.GetSize (element_type);
7159 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
7161 data = new byte [(count * factor + 3) & ~3];
7164 for (int i = 0; i < count; ++i) {
7165 var c = array_data[i] as Constant;
7171 object v = c.GetValue ();
7173 switch (element_type.BuiltinType) {
7174 case BuiltinTypeSpec.Type.Long:
7175 long lval = (long) v;
7177 for (int j = 0; j < factor; ++j) {
7178 data[idx + j] = (byte) (lval & 0xFF);
7182 case BuiltinTypeSpec.Type.ULong:
7183 ulong ulval = (ulong) v;
7185 for (int j = 0; j < factor; ++j) {
7186 data[idx + j] = (byte) (ulval & 0xFF);
7187 ulval = (ulval >> 8);
7190 case BuiltinTypeSpec.Type.Float:
7191 var fval = SingleConverter.SingleToInt32Bits((float) v);
7193 data[idx] = (byte) (fval & 0xff);
7194 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
7195 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
7196 data[idx + 3] = (byte) (fval >> 24);
7198 case BuiltinTypeSpec.Type.Double:
7199 element = BitConverter.GetBytes ((double) v);
7201 for (int j = 0; j < factor; ++j)
7202 data[idx + j] = element[j];
7204 // FIXME: Handle the ARM float format.
7205 if (!BitConverter.IsLittleEndian)
7206 System.Array.Reverse (data, idx, 8);
7208 case BuiltinTypeSpec.Type.Char:
7209 int chval = (int) ((char) v);
7211 data[idx] = (byte) (chval & 0xff);
7212 data[idx + 1] = (byte) (chval >> 8);
7214 case BuiltinTypeSpec.Type.Short:
7215 int sval = (int) ((short) v);
7217 data[idx] = (byte) (sval & 0xff);
7218 data[idx + 1] = (byte) (sval >> 8);
7220 case BuiltinTypeSpec.Type.UShort:
7221 int usval = (int) ((ushort) v);
7223 data[idx] = (byte) (usval & 0xff);
7224 data[idx + 1] = (byte) (usval >> 8);
7226 case BuiltinTypeSpec.Type.Int:
7229 data[idx] = (byte) (val & 0xff);
7230 data[idx + 1] = (byte) ((val >> 8) & 0xff);
7231 data[idx + 2] = (byte) ((val >> 16) & 0xff);
7232 data[idx + 3] = (byte) (val >> 24);
7234 case BuiltinTypeSpec.Type.UInt:
7235 uint uval = (uint) v;
7237 data[idx] = (byte) (uval & 0xff);
7238 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
7239 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
7240 data[idx + 3] = (byte) (uval >> 24);
7242 case BuiltinTypeSpec.Type.SByte:
7243 data[idx] = (byte) (sbyte) v;
7245 case BuiltinTypeSpec.Type.Byte:
7246 data[idx] = (byte) v;
7248 case BuiltinTypeSpec.Type.Bool:
7249 data[idx] = (byte) ((bool) v ? 1 : 0);
7251 case BuiltinTypeSpec.Type.Decimal:
7252 int[] bits = Decimal.GetBits ((decimal) v);
7255 // FIXME: For some reason, this doesn't work on the MS runtime.
7256 int[] nbits = new int[4];
7262 for (int j = 0; j < 4; j++) {
7263 data[p++] = (byte) (nbits[j] & 0xff);
7264 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
7265 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
7266 data[p++] = (byte) (nbits[j] >> 24);
7270 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
7279 #if NET_4_0 || MONODROID
7280 public override SLE.Expression MakeExpression (BuilderContext ctx)
7283 return base.MakeExpression (ctx);
7285 var initializers = new SLE.Expression [array_data.Count];
7286 for (var i = 0; i < initializers.Length; i++) {
7287 if (array_data [i] == null)
7288 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
7290 initializers [i] = array_data [i].MakeExpression (ctx);
7293 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
7299 // Emits the initializers for the array
7301 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
7303 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
7308 // First, the static data
7310 byte [] data = MakeByteBlob ();
7311 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
7313 if (stackArray == null) {
7314 ec.Emit (OpCodes.Dup);
7316 stackArray.Emit (ec);
7319 ec.Emit (OpCodes.Ldtoken, fb);
7320 ec.Emit (OpCodes.Call, m);
7325 // Emits pieces of the array that can not be computed at compile
7326 // time (variables and string locations).
7328 // This always expect the top value on the stack to be the array
7330 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, FieldExpr stackArray)
7332 int dims = bounds.Count;
7333 var current_pos = new int [dims];
7335 for (int i = 0; i < array_data.Count; i++){
7337 Expression e = array_data [i];
7338 var c = e as Constant;
7340 // Constant can be initialized via StaticInitializer
7341 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
7345 if (stackArray != null) {
7346 if (e.ContainsEmitWithAwait ()) {
7347 e = e.EmitToField (ec);
7350 stackArray.Emit (ec);
7352 ec.Emit (OpCodes.Dup);
7355 for (int idx = 0; idx < dims; idx++)
7356 ec.EmitInt (current_pos [idx]);
7359 // If we are dealing with a struct, get the
7360 // address of it, so we can store it.
7362 if (dims == 1 && etype.IsStruct) {
7363 switch (etype.BuiltinType) {
7364 case BuiltinTypeSpec.Type.Byte:
7365 case BuiltinTypeSpec.Type.SByte:
7366 case BuiltinTypeSpec.Type.Bool:
7367 case BuiltinTypeSpec.Type.Short:
7368 case BuiltinTypeSpec.Type.UShort:
7369 case BuiltinTypeSpec.Type.Char:
7370 case BuiltinTypeSpec.Type.Int:
7371 case BuiltinTypeSpec.Type.UInt:
7372 case BuiltinTypeSpec.Type.Long:
7373 case BuiltinTypeSpec.Type.ULong:
7374 case BuiltinTypeSpec.Type.Float:
7375 case BuiltinTypeSpec.Type.Double:
7378 ec.Emit (OpCodes.Ldelema, etype);
7385 ec.EmitArrayStore ((ArrayContainer) type);
7391 for (int j = dims - 1; j >= 0; j--){
7393 if (current_pos [j] < bounds [j])
7395 current_pos [j] = 0;
7400 public override void Emit (EmitContext ec)
7402 EmitToFieldSource (ec);
7405 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
7407 if (first_emit != null) {
7408 first_emit.Emit (ec);
7409 first_emit_temp.Store (ec);
7412 FieldExpr await_stack_field;
7413 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
7414 await_stack_field = ec.GetTemporaryField (type);
7417 await_stack_field = null;
7420 EmitExpressionsList (ec, arguments);
7422 ec.EmitArrayNew ((ArrayContainer) type);
7424 if (initializers == null)
7425 return await_stack_field;
7427 if (await_stack_field != null)
7428 await_stack_field.EmitAssignFromStack (ec);
7432 // Emit static initializer for arrays which contain more than 2 items and
7433 // the static initializer will initialize at least 25% of array values or there
7434 // is more than 10 items to be initialized
7436 // NOTE: const_initializers_count does not contain default constant values.
7438 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
7439 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
7440 EmitStaticInitializers (ec, await_stack_field);
7442 if (!only_constant_initializers)
7443 EmitDynamicInitializers (ec, false, await_stack_field);
7447 EmitDynamicInitializers (ec, true, await_stack_field);
7450 if (first_emit_temp != null)
7451 first_emit_temp.Release (ec);
7453 return await_stack_field;
7456 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7458 // no multi dimensional or jagged arrays
7459 if (arguments.Count != 1 || array_element_type.IsArray) {
7460 base.EncodeAttributeValue (rc, enc, targetType);
7464 // No array covariance, except for array -> object
7465 if (type != targetType) {
7466 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
7467 base.EncodeAttributeValue (rc, enc, targetType);
7471 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
7472 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7477 // Single dimensional array of 0 size
7478 if (array_data == null) {
7479 IntConstant ic = arguments[0] as IntConstant;
7480 if (ic == null || !ic.IsDefaultValue) {
7481 base.EncodeAttributeValue (rc, enc, targetType);
7489 enc.Encode (array_data.Count);
7490 foreach (var element in array_data) {
7491 element.EncodeAttributeValue (rc, enc, array_element_type);
7495 protected override void CloneTo (CloneContext clonectx, Expression t)
7497 ArrayCreation target = (ArrayCreation) t;
7499 if (requested_base_type != null)
7500 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
7502 if (arguments != null){
7503 target.arguments = new List<Expression> (arguments.Count);
7504 foreach (Expression e in arguments)
7505 target.arguments.Add (e.Clone (clonectx));
7508 if (initializers != null)
7509 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
7512 public override object Accept (StructuralVisitor visitor)
7514 return visitor.Visit (this);
7519 // Represents an implicitly typed array epxression
7521 class ImplicitlyTypedArrayCreation : ArrayCreation
7523 TypeInferenceContext best_type_inference;
7525 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7526 : base (null, rank, initializers, loc)
7530 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
7531 : base (null, initializers, loc)
7535 protected override Expression DoResolve (ResolveContext ec)
7540 dimensions = rank.Dimension;
7542 best_type_inference = new TypeInferenceContext ();
7544 if (!ResolveInitializers (ec))
7547 best_type_inference.FixAllTypes (ec);
7548 array_element_type = best_type_inference.InferredTypeArguments[0];
7549 best_type_inference = null;
7551 if (array_element_type == null ||
7552 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
7553 arguments.Count != rank.Dimension) {
7554 ec.Report.Error (826, loc,
7555 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
7560 // At this point we found common base type for all initializer elements
7561 // but we have to be sure that all static initializer elements are of
7564 UnifyInitializerElement (ec);
7566 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
7567 eclass = ExprClass.Value;
7572 // Converts static initializer only
7574 void UnifyInitializerElement (ResolveContext ec)
7576 for (int i = 0; i < array_data.Count; ++i) {
7577 Expression e = array_data[i];
7579 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
7583 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
7585 element = element.Resolve (ec);
7586 if (element != null)
7587 best_type_inference.AddCommonTypeBound (element.Type);
7593 sealed class CompilerGeneratedThis : This
7595 public CompilerGeneratedThis (TypeSpec type, Location loc)
7599 eclass = ExprClass.Variable;
7602 protected override Expression DoResolve (ResolveContext ec)
7607 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7614 /// Represents the `this' construct
7617 public class This : VariableReference
7619 sealed class ThisVariable : ILocalVariable
7621 public static readonly ILocalVariable Instance = new ThisVariable ();
7623 public void Emit (EmitContext ec)
7628 public void EmitAssign (EmitContext ec)
7630 throw new InvalidOperationException ();
7633 public void EmitAddressOf (EmitContext ec)
7639 VariableInfo variable_info;
7641 public This (Location loc)
7648 public override string Name {
7649 get { return "this"; }
7652 public override bool IsLockedByStatement {
7660 public override bool IsRef {
7661 get { return type.IsStruct; }
7664 public override bool IsSideEffectFree {
7670 protected override ILocalVariable Variable {
7671 get { return ThisVariable.Instance; }
7674 public override VariableInfo VariableInfo {
7675 get { return variable_info; }
7678 public override bool IsFixed {
7679 get { return false; }
7684 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
7687 // It's null for all cases when we don't need to check `this'
7688 // definitive assignment
7690 if (variable_info == null)
7693 if (rc.OmitStructFlowAnalysis)
7696 if (!variable_info.IsAssigned (rc)) {
7697 rc.Report.Error (188, loc,
7698 "The `this' object cannot be used before all of its fields are assigned to");
7702 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7704 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7705 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7706 } else if (ec.CurrentAnonymousMethod != null) {
7707 ec.Report.Error (1673, loc,
7708 "Anonymous methods inside structs cannot access instance members of `this'. " +
7709 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7711 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7715 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7720 AnonymousMethodStorey storey = ae.Storey;
7721 return storey != null ? storey.HoistedThis : null;
7724 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7726 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7729 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7732 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7738 public virtual void ResolveBase (ResolveContext ec)
7740 eclass = ExprClass.Variable;
7741 type = ec.CurrentType;
7743 if (!IsThisAvailable (ec, false)) {
7744 Error_ThisNotAvailable (ec);
7748 var block = ec.CurrentBlock;
7749 if (block != null) {
7750 var top = block.ParametersBlock.TopBlock;
7751 if (top.ThisVariable != null)
7752 variable_info = top.ThisVariable.VariableInfo;
7754 AnonymousExpression am = ec.CurrentAnonymousMethod;
7755 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7757 // Hoisted this is almost like hoisted variable but not exactly. When
7758 // there is no variable hoisted we can simply emit an instance method
7759 // without lifting this into a storey. Unfotunatelly this complicates
7760 // things in other cases because we don't know where this will be hoisted
7761 // until top-level block is fully resolved
7763 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7764 am.SetHasThisAccess ();
7769 protected override Expression DoResolve (ResolveContext ec)
7773 CheckStructThisDefiniteAssignment (ec);
7778 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7780 if (eclass == ExprClass.Unresolved)
7783 if (variable_info != null)
7784 variable_info.SetAssigned (ec);
7787 if (right_side == EmptyExpression.UnaryAddress)
7788 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7789 else if (right_side == EmptyExpression.OutAccess)
7790 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7792 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7798 public override int GetHashCode()
7800 throw new NotImplementedException ();
7803 public override bool Equals (object obj)
7805 This t = obj as This;
7812 protected override void CloneTo (CloneContext clonectx, Expression t)
7817 public override void SetHasAddressTaken ()
7822 public override void VerifyDefiniteAssignment (ResolveContext rc)
7826 public override object Accept (StructuralVisitor visitor)
7828 return visitor.Visit (this);
7833 /// Represents the `__arglist' construct
7835 public class ArglistAccess : Expression
7837 public ArglistAccess (Location loc)
7842 protected override void CloneTo (CloneContext clonectx, Expression target)
7847 public override bool ContainsEmitWithAwait ()
7852 public override Expression CreateExpressionTree (ResolveContext ec)
7854 throw new NotSupportedException ("ET");
7857 protected override Expression DoResolve (ResolveContext ec)
7859 eclass = ExprClass.Variable;
7860 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
7862 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7863 ec.Report.Error (190, loc,
7864 "The __arglist construct is valid only within a variable argument method");
7870 public override void Emit (EmitContext ec)
7872 ec.Emit (OpCodes.Arglist);
7875 public override object Accept (StructuralVisitor visitor)
7877 return visitor.Visit (this);
7882 /// Represents the `__arglist (....)' construct
7884 public class Arglist : Expression
7886 Arguments arguments;
7888 public Arglist (Location loc)
7893 public Arglist (Arguments args, Location l)
7899 public Arguments Arguments {
7905 public MetaType[] ArgumentTypes {
7907 if (arguments == null)
7908 return MetaType.EmptyTypes;
7910 var retval = new MetaType[arguments.Count];
7911 for (int i = 0; i < retval.Length; i++)
7912 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
7918 public override bool ContainsEmitWithAwait ()
7920 throw new NotImplementedException ();
7923 public override Expression CreateExpressionTree (ResolveContext ec)
7925 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7929 protected override Expression DoResolve (ResolveContext ec)
7931 eclass = ExprClass.Variable;
7932 type = InternalType.Arglist;
7933 if (arguments != null) {
7934 bool dynamic; // Can be ignored as there is always only 1 overload
7935 arguments.Resolve (ec, out dynamic);
7941 public override void Emit (EmitContext ec)
7943 if (arguments != null)
7944 arguments.Emit (ec);
7947 protected override void CloneTo (CloneContext clonectx, Expression t)
7949 Arglist target = (Arglist) t;
7951 if (arguments != null)
7952 target.arguments = arguments.Clone (clonectx);
7955 public override object Accept (StructuralVisitor visitor)
7957 return visitor.Visit (this);
7961 public class RefValueExpr : ShimExpression, IAssignMethod
7963 FullNamedExpression texpr;
7965 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7972 public FullNamedExpression TypeExpression {
7978 public override bool ContainsEmitWithAwait ()
7983 protected override Expression DoResolve (ResolveContext rc)
7985 expr = expr.Resolve (rc);
7986 type = texpr.ResolveAsType (rc);
7987 if (expr == null || type == null)
7990 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7991 eclass = ExprClass.Value;
7995 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7997 return DoResolve (rc);
8000 public override void Emit (EmitContext ec)
8003 ec.Emit (OpCodes.Refanyval, type);
8004 ec.EmitLoadFromPtr (type);
8007 public void Emit (EmitContext ec, bool leave_copy)
8009 throw new NotImplementedException ();
8012 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8015 ec.Emit (OpCodes.Refanyval, type);
8018 LocalTemporary temporary = null;
8020 ec.Emit (OpCodes.Dup);
8021 temporary = new LocalTemporary (source.Type);
8022 temporary.Store (ec);
8025 ec.EmitStoreFromPtr (type);
8027 if (temporary != null) {
8028 temporary.Emit (ec);
8029 temporary.Release (ec);
8033 public override object Accept (StructuralVisitor visitor)
8035 return visitor.Visit (this);
8039 public class RefTypeExpr : ShimExpression
8041 public RefTypeExpr (Expression expr, Location loc)
8047 protected override Expression DoResolve (ResolveContext rc)
8049 expr = expr.Resolve (rc);
8053 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8057 type = rc.BuiltinTypes.Type;
8058 eclass = ExprClass.Value;
8062 public override void Emit (EmitContext ec)
8065 ec.Emit (OpCodes.Refanytype);
8066 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8068 ec.Emit (OpCodes.Call, m);
8071 public override object Accept (StructuralVisitor visitor)
8073 return visitor.Visit (this);
8077 public class MakeRefExpr : ShimExpression
8079 public MakeRefExpr (Expression expr, Location loc)
8085 public override bool ContainsEmitWithAwait ()
8087 throw new NotImplementedException ();
8090 protected override Expression DoResolve (ResolveContext rc)
8092 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8093 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8094 eclass = ExprClass.Value;
8098 public override void Emit (EmitContext ec)
8100 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8101 ec.Emit (OpCodes.Mkrefany, expr.Type);
8104 public override object Accept (StructuralVisitor visitor)
8106 return visitor.Visit (this);
8111 /// Implements the typeof operator
8113 public class TypeOf : Expression {
8114 FullNamedExpression QueriedType;
8117 public TypeOf (FullNamedExpression queried_type, Location l)
8119 QueriedType = queried_type;
8124 // Use this constructor for any compiler generated typeof expression
8126 public TypeOf (TypeSpec type, Location loc)
8128 this.typearg = type;
8134 public override bool IsSideEffectFree {
8140 public TypeSpec TypeArgument {
8146 public FullNamedExpression TypeExpression {
8155 protected override void CloneTo (CloneContext clonectx, Expression t)
8157 TypeOf target = (TypeOf) t;
8158 if (QueriedType != null)
8159 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
8162 public override bool ContainsEmitWithAwait ()
8167 public override Expression CreateExpressionTree (ResolveContext ec)
8169 Arguments args = new Arguments (2);
8170 args.Add (new Argument (this));
8171 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8172 return CreateExpressionFactoryCall (ec, "Constant", args);
8175 protected override Expression DoResolve (ResolveContext ec)
8177 if (eclass != ExprClass.Unresolved)
8180 if (typearg == null) {
8182 // Pointer types are allowed without explicit unsafe, they are just tokens
8184 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
8185 typearg = QueriedType.ResolveAsType (ec);
8188 if (typearg == null)
8191 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8192 ec.Report.Error (1962, QueriedType.Location,
8193 "The typeof operator cannot be used on the dynamic type");
8197 type = ec.BuiltinTypes.Type;
8199 // Even though what is returned is a type object, it's treated as a value by the compiler.
8200 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
8201 eclass = ExprClass.Value;
8205 static bool ContainsDynamicType (TypeSpec type)
8207 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
8210 var element_container = type as ElementTypeSpec;
8211 if (element_container != null)
8212 return ContainsDynamicType (element_container.Element);
8214 foreach (var t in type.TypeArguments) {
8215 if (ContainsDynamicType (t)) {
8223 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
8225 // Target type is not System.Type therefore must be object
8226 // and we need to use different encoding sequence
8227 if (targetType != type)
8230 if (typearg is InflatedTypeSpec) {
8233 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
8234 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
8235 typearg.GetSignatureForError ());
8239 gt = gt.DeclaringType;
8240 } while (gt != null);
8243 if (ContainsDynamicType (typearg)) {
8244 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8248 enc.EncodeTypeName (typearg);
8251 public override void Emit (EmitContext ec)
8253 ec.Emit (OpCodes.Ldtoken, typearg);
8254 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8256 ec.Emit (OpCodes.Call, m);
8259 public override object Accept (StructuralVisitor visitor)
8261 return visitor.Visit (this);
8265 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
8267 public TypeOfMethod (MethodSpec method, Location loc)
8268 : base (method, loc)
8272 protected override Expression DoResolve (ResolveContext ec)
8274 if (member.IsConstructor) {
8275 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
8277 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
8283 return base.DoResolve (ec);
8286 public override void Emit (EmitContext ec)
8288 ec.Emit (OpCodes.Ldtoken, member);
8291 ec.Emit (OpCodes.Castclass, type);
8294 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8296 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
8299 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8301 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
8305 abstract class TypeOfMember<T> : Expression where T : MemberSpec
8307 protected readonly T member;
8309 protected TypeOfMember (T member, Location loc)
8311 this.member = member;
8315 public override bool IsSideEffectFree {
8321 public override bool ContainsEmitWithAwait ()
8326 public override Expression CreateExpressionTree (ResolveContext ec)
8328 Arguments args = new Arguments (2);
8329 args.Add (new Argument (this));
8330 args.Add (new Argument (new TypeOf (type, loc)));
8331 return CreateExpressionFactoryCall (ec, "Constant", args);
8334 protected override Expression DoResolve (ResolveContext ec)
8336 eclass = ExprClass.Value;
8340 public override void Emit (EmitContext ec)
8342 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
8343 PredefinedMember<MethodSpec> p;
8345 p = GetTypeFromHandleGeneric (ec);
8346 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
8348 p = GetTypeFromHandle (ec);
8351 var mi = p.Resolve (loc);
8353 ec.Emit (OpCodes.Call, mi);
8356 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
8357 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
8360 sealed class TypeOfField : TypeOfMember<FieldSpec>
8362 public TypeOfField (FieldSpec field, Location loc)
8367 protected override Expression DoResolve (ResolveContext ec)
8369 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
8373 return base.DoResolve (ec);
8376 public override void Emit (EmitContext ec)
8378 ec.Emit (OpCodes.Ldtoken, member);
8382 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8384 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
8387 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8389 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
8394 /// Implements the sizeof expression
8396 public class SizeOf : Expression {
8397 readonly Expression texpr;
8398 TypeSpec type_queried;
8400 public SizeOf (Expression queried_type, Location l)
8402 this.texpr = queried_type;
8406 public override bool IsSideEffectFree {
8412 public Expression TypeExpression {
8418 public override bool ContainsEmitWithAwait ()
8423 public override Expression CreateExpressionTree (ResolveContext ec)
8425 Error_PointerInsideExpressionTree (ec);
8429 protected override Expression DoResolve (ResolveContext ec)
8431 type_queried = texpr.ResolveAsType (ec);
8432 if (type_queried == null)
8435 if (type_queried.IsEnum)
8436 type_queried = EnumSpec.GetUnderlyingType (type_queried);
8438 int size_of = BuiltinTypeSpec.GetSize (type_queried);
8440 return new IntConstant (ec.BuiltinTypes, size_of, loc);
8443 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
8448 ec.Report.Error (233, loc,
8449 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
8450 type_queried.GetSignatureForError ());
8453 type = ec.BuiltinTypes.Int;
8454 eclass = ExprClass.Value;
8458 public override void Emit (EmitContext ec)
8460 ec.Emit (OpCodes.Sizeof, type_queried);
8463 protected override void CloneTo (CloneContext clonectx, Expression t)
8467 public override object Accept (StructuralVisitor visitor)
8469 return visitor.Visit (this);
8474 /// Implements the qualified-alias-member (::) expression.
8476 public class QualifiedAliasMember : MemberAccess
8478 readonly string alias;
8479 public static readonly string GlobalAlias = "global";
8481 public QualifiedAliasMember (string alias, string identifier, Location l)
8482 : base (null, identifier, l)
8487 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
8488 : base (null, identifier, targs, l)
8493 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
8494 : base (null, identifier, arity, l)
8499 public string Alias {
8505 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
8507 if (alias == GlobalAlias) {
8508 expr = ec.Module.GlobalRootNamespace;
8509 return base.ResolveAsTypeOrNamespace (ec);
8512 int errors = ec.Module.Compiler.Report.Errors;
8513 expr = ec.LookupNamespaceAlias (alias);
8515 if (errors == ec.Module.Compiler.Report.Errors)
8516 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
8520 return base.ResolveAsTypeOrNamespace (ec);
8523 protected override Expression DoResolve (ResolveContext ec)
8525 return ResolveAsTypeOrNamespace (ec);
8528 public override string GetSignatureForError ()
8531 if (targs != null) {
8532 name = Name + "<" + targs.GetSignatureForError () + ">";
8535 return alias + "::" + name;
8538 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8540 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
8541 rc.Module.Compiler.Report.Error (687, loc,
8542 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
8543 GetSignatureForError ());
8548 return DoResolve (rc);
8551 protected override void CloneTo (CloneContext clonectx, Expression t)
8556 public override object Accept (StructuralVisitor visitor)
8558 return visitor.Visit (this);
8563 /// Implements the member access expression
8565 public class MemberAccess : ATypeNameExpression
8567 protected Expression expr;
8569 public MemberAccess (Expression expr, string id)
8570 : base (id, expr.Location)
8575 public MemberAccess (Expression expr, string identifier, Location loc)
8576 : base (identifier, loc)
8581 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
8582 : base (identifier, args, loc)
8587 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
8588 : base (identifier, arity, loc)
8593 public Expression LeftExpression {
8599 public override Location StartLocation {
8601 return expr == null ? loc : expr.StartLocation;
8605 protected override Expression DoResolve (ResolveContext rc)
8607 var e = DoResolveName (rc, null);
8609 if (!rc.OmitStructFlowAnalysis) {
8610 var fe = e as FieldExpr;
8612 fe.VerifyAssignedStructField (rc, null);
8619 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
8621 var e = DoResolveName (rc, rhs);
8623 if (!rc.OmitStructFlowAnalysis) {
8624 var fe = e as FieldExpr;
8625 if (fe != null && fe.InstanceExpression is FieldExpr) {
8626 fe = (FieldExpr) fe.InstanceExpression;
8627 fe.VerifyAssignedStructField (rc, rhs);
8634 Expression DoResolveName (ResolveContext rc, Expression right_side)
8636 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
8640 if (right_side != null) {
8641 if (e is TypeExpr) {
8642 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8646 e = e.ResolveLValue (rc, right_side);
8648 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
8654 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8656 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8657 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8659 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8662 public static bool IsValidDotExpression (TypeSpec type)
8664 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8665 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8667 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8670 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8672 var sn = expr as SimpleName;
8673 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8676 // Resolve the expression with flow analysis turned off, we'll do the definite
8677 // assignment checks later. This is because we don't know yet what the expression
8678 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
8679 // definite assignment check on the actual field and not on the whole struct.
8681 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
8683 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8686 // Resolve expression which does have type set as we need expression type
8687 // with disable flow analysis as we don't know whether left side expression
8688 // is used as variable or type
8690 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8691 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
8692 expr = expr.Resolve (rc);
8694 } else if (expr is TypeParameterExpr) {
8695 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8699 expr = expr.Resolve (rc, flags);
8706 Namespace ns = expr as Namespace;
8708 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8710 if (retval == null) {
8711 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8715 if (HasTypeArguments)
8716 return new GenericTypeExpr (retval.Type, targs, loc);
8722 TypeSpec expr_type = expr.Type;
8723 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8724 me = expr as MemberExpr;
8726 me.ResolveInstanceExpression (rc, null);
8729 // Run defined assigned checks on expressions resolved with
8730 // disabled flow-analysis
8733 var vr = expr as VariableReference;
8735 vr.VerifyDefiniteAssignment (rc);
8738 Arguments args = new Arguments (1);
8739 args.Add (new Argument (expr));
8740 return new DynamicMemberBinder (Name, args, loc);
8743 if (!IsValidDotExpression (expr_type)) {
8744 Error_OperatorCannotBeApplied (rc, expr_type);
8748 var lookup_arity = Arity;
8749 bool errorMode = false;
8750 Expression member_lookup;
8752 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8753 if (member_lookup == null) {
8755 // Try to look for extension method when member lookup failed
8757 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8758 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8759 if (methods != null) {
8760 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8761 if (HasTypeArguments) {
8762 if (!targs.Resolve (rc))
8765 emg.SetTypeArguments (rc, targs);
8769 // Run defined assigned checks on expressions resolved with
8770 // disabled flow-analysis
8772 if (sn != null && !errorMode) {
8773 var vr = expr as VariableReference;
8775 vr.VerifyDefiniteAssignment (rc);
8778 // TODO: it should really skip the checks bellow
8779 return emg.Resolve (rc);
8785 if (member_lookup == null) {
8786 var dep = expr_type.GetMissingDependencies ();
8788 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8789 } else if (expr is TypeExpr) {
8790 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8792 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8798 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8799 // Leave it to overload resolution to report correct error
8800 } else if (!(member_lookup is TypeExpr)) {
8801 // TODO: rc.SymbolRelatedToPreviousError
8802 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8807 if (member_lookup != null)
8811 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8815 TypeExpr texpr = member_lookup as TypeExpr;
8816 if (texpr != null) {
8817 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8818 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8819 Name, texpr.GetSignatureForError ());
8822 if (!texpr.Type.IsAccessible (rc)) {
8823 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8824 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8828 if (HasTypeArguments) {
8829 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8832 return member_lookup;
8835 me = member_lookup as MemberExpr;
8837 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8841 me = me.ResolveMemberAccess (rc, expr, sn);
8844 if (!targs.Resolve (rc))
8847 me.SetTypeArguments (rc, targs);
8851 // Run defined assigned checks on expressions resolved with
8852 // disabled flow-analysis
8854 if (sn != null && !(me is FieldExpr && TypeSpec.IsValueType (expr_type))) {
8855 var vr = expr as VariableReference;
8857 vr.VerifyDefiniteAssignment (rc);
8863 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8865 FullNamedExpression fexpr = expr as FullNamedExpression;
8866 if (fexpr == null) {
8867 expr.ResolveAsType (rc);
8871 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8873 if (expr_resolved == null)
8876 Namespace ns = expr_resolved as Namespace;
8878 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8880 if (retval == null) {
8881 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
8882 } else if (HasTypeArguments) {
8883 retval = new GenericTypeExpr (retval.Type, targs, loc);
8884 if (retval.ResolveAsType (rc) == null)
8891 var tnew_expr = expr_resolved.ResolveAsType (rc);
8892 if (tnew_expr == null)
8895 TypeSpec expr_type = tnew_expr;
8896 if (TypeManager.IsGenericParameter (expr_type)) {
8897 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8898 tnew_expr.GetSignatureForError ());
8902 var qam = this as QualifiedAliasMember;
8904 rc.Module.Compiler.Report.Error (431, loc,
8905 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8910 TypeSpec nested = null;
8911 while (expr_type != null) {
8912 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8913 if (nested == null) {
8914 if (expr_type == tnew_expr) {
8915 Error_IdentifierNotFound (rc, expr_type, Name);
8919 expr_type = tnew_expr;
8920 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8921 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
8925 if (nested.IsAccessible (rc))
8929 // Keep looking after inaccessible candidate but only if
8930 // we are not in same context as the definition itself
8932 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
8935 expr_type = expr_type.BaseType;
8940 if (HasTypeArguments) {
8941 texpr = new GenericTypeExpr (nested, targs, loc);
8943 texpr = new GenericOpenTypeExpr (nested, loc);
8946 texpr = new TypeExpression (nested, loc);
8949 if (texpr.ResolveAsType (rc) == null)
8955 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
8957 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
8959 if (nested != null) {
8960 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
8964 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
8965 if (any_other_member != null) {
8966 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
8970 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
8971 Name, expr_type.GetSignatureForError ());
8974 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
8976 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
8979 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
8981 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8982 ec.Report.SymbolRelatedToPreviousError (type);
8984 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
8986 // a using directive or an assembly reference
8988 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
8990 missing = "an assembly reference";
8993 ec.Report.Error (1061, loc,
8994 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
8995 type.GetSignatureForError (), name, missing);
8999 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9002 public override string GetSignatureForError ()
9004 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9007 protected override void CloneTo (CloneContext clonectx, Expression t)
9009 MemberAccess target = (MemberAccess) t;
9011 target.expr = expr.Clone (clonectx);
9014 public override object Accept (StructuralVisitor visitor)
9016 return visitor.Visit (this);
9021 /// Implements checked expressions
9023 public class CheckedExpr : Expression {
9025 public Expression Expr;
9027 public CheckedExpr (Expression e, Location l)
9033 public override bool ContainsEmitWithAwait ()
9035 return Expr.ContainsEmitWithAwait ();
9038 public override Expression CreateExpressionTree (ResolveContext ec)
9040 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9041 return Expr.CreateExpressionTree (ec);
9044 protected override Expression DoResolve (ResolveContext ec)
9046 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9047 Expr = Expr.Resolve (ec);
9052 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9055 eclass = Expr.eclass;
9060 public override void Emit (EmitContext ec)
9062 using (ec.With (EmitContext.Options.CheckedScope, true))
9066 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9068 using (ec.With (EmitContext.Options.CheckedScope, true))
9069 Expr.EmitBranchable (ec, target, on_true);
9072 public override SLE.Expression MakeExpression (BuilderContext ctx)
9074 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9075 return Expr.MakeExpression (ctx);
9079 protected override void CloneTo (CloneContext clonectx, Expression t)
9081 CheckedExpr target = (CheckedExpr) t;
9083 target.Expr = Expr.Clone (clonectx);
9086 public override object Accept (StructuralVisitor visitor)
9088 return visitor.Visit (this);
9093 /// Implements the unchecked expression
9095 public class UnCheckedExpr : Expression {
9097 public Expression Expr;
9099 public UnCheckedExpr (Expression e, Location l)
9105 public override bool ContainsEmitWithAwait ()
9107 return Expr.ContainsEmitWithAwait ();
9110 public override Expression CreateExpressionTree (ResolveContext ec)
9112 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9113 return Expr.CreateExpressionTree (ec);
9116 protected override Expression DoResolve (ResolveContext ec)
9118 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9119 Expr = Expr.Resolve (ec);
9124 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9127 eclass = Expr.eclass;
9132 public override void Emit (EmitContext ec)
9134 using (ec.With (EmitContext.Options.CheckedScope, false))
9138 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9140 using (ec.With (EmitContext.Options.CheckedScope, false))
9141 Expr.EmitBranchable (ec, target, on_true);
9144 protected override void CloneTo (CloneContext clonectx, Expression t)
9146 UnCheckedExpr target = (UnCheckedExpr) t;
9148 target.Expr = Expr.Clone (clonectx);
9151 public override object Accept (StructuralVisitor visitor)
9153 return visitor.Visit (this);
9158 /// An Element Access expression.
9160 /// During semantic analysis these are transformed into
9161 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
9163 public class ElementAccess : Expression
9165 public Arguments Arguments;
9166 public Expression Expr;
9168 public ElementAccess (Expression e, Arguments args, Location loc)
9172 this.Arguments = args;
9175 public override Location StartLocation {
9177 return Expr.StartLocation;
9181 public override bool ContainsEmitWithAwait ()
9183 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
9187 // We perform some simple tests, and then to "split" the emit and store
9188 // code we create an instance of a different class, and return that.
9190 Expression CreateAccessExpression (ResolveContext ec)
9193 return (new ArrayAccess (this, loc));
9196 return MakePointerAccess (ec, type);
9198 FieldExpr fe = Expr as FieldExpr;
9200 var ff = fe.Spec as FixedFieldSpec;
9202 return MakePointerAccess (ec, ff.ElementType);
9206 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
9207 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9208 return new IndexerExpr (indexers, type, this);
9211 if (type != InternalType.ErrorType) {
9212 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
9213 type.GetSignatureForError ());
9219 public override Expression CreateExpressionTree (ResolveContext ec)
9221 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
9222 Expr.CreateExpressionTree (ec));
9224 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
9227 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
9229 if (Arguments.Count != 1){
9230 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
9234 if (Arguments [0] is NamedArgument)
9235 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
9237 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
9238 return new Indirection (p, loc);
9241 protected override Expression DoResolve (ResolveContext ec)
9243 Expr = Expr.Resolve (ec);
9249 // TODO: Create 1 result for Resolve and ResolveLValue ?
9250 var res = CreateAccessExpression (ec);
9254 return res.Resolve (ec);
9257 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
9259 Expr = Expr.Resolve (ec);
9265 var res = CreateAccessExpression (ec);
9269 return res.ResolveLValue (ec, rhs);
9272 public override void Emit (EmitContext ec)
9274 throw new Exception ("Should never be reached");
9277 public static void Error_NamedArgument (NamedArgument na, Report Report)
9279 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
9282 public override string GetSignatureForError ()
9284 return Expr.GetSignatureForError ();
9287 protected override void CloneTo (CloneContext clonectx, Expression t)
9289 ElementAccess target = (ElementAccess) t;
9291 target.Expr = Expr.Clone (clonectx);
9292 if (Arguments != null)
9293 target.Arguments = Arguments.Clone (clonectx);
9296 public override object Accept (StructuralVisitor visitor)
9298 return visitor.Visit (this);
9303 /// Implements array access
9305 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
9307 // Points to our "data" repository
9311 LocalTemporary temp;
9313 bool? has_await_args;
9315 public ArrayAccess (ElementAccess ea_data, Location l)
9321 public void AddressOf (EmitContext ec, AddressOp mode)
9323 var ac = (ArrayContainer) ea.Expr.Type;
9325 LoadInstanceAndArguments (ec, false, false);
9327 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
9328 ec.Emit (OpCodes.Readonly);
9330 ec.EmitArrayAddress (ac);
9333 public override Expression CreateExpressionTree (ResolveContext ec)
9335 return ea.CreateExpressionTree (ec);
9338 public override bool ContainsEmitWithAwait ()
9340 return ea.ContainsEmitWithAwait ();
9343 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9345 return DoResolve (ec);
9348 protected override Expression DoResolve (ResolveContext ec)
9350 // dynamic is used per argument in ConvertExpressionToArrayIndex case
9352 ea.Arguments.Resolve (ec, out dynamic);
9354 var ac = ea.Expr.Type as ArrayContainer;
9355 int rank = ea.Arguments.Count;
9356 if (ac.Rank != rank) {
9357 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
9358 rank.ToString (), ac.Rank.ToString ());
9363 if (type.IsPointer && !ec.IsUnsafe) {
9364 UnsafeError (ec, ea.Location);
9367 foreach (Argument a in ea.Arguments) {
9368 if (a is NamedArgument)
9369 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
9371 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
9374 eclass = ExprClass.Variable;
9379 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
9381 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
9385 // Load the array arguments into the stack.
9387 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
9390 ea.Expr = ea.Expr.EmitToField (ec);
9391 } else if (duplicateArguments) {
9393 ec.Emit (OpCodes.Dup);
9395 var copy = new LocalTemporary (ea.Expr.Type);
9402 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
9403 if (dup_args != null)
9404 ea.Arguments = dup_args;
9407 public void Emit (EmitContext ec, bool leave_copy)
9409 var ac = ea.Expr.Type as ArrayContainer;
9412 ec.EmitLoadFromPtr (type);
9414 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
9415 LoadInstanceAndArguments (ec, false, true);
9418 LoadInstanceAndArguments (ec, false, false);
9419 ec.EmitArrayLoad (ac);
9423 ec.Emit (OpCodes.Dup);
9424 temp = new LocalTemporary (this.type);
9429 public override void Emit (EmitContext ec)
9434 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9436 var ac = (ArrayContainer) ea.Expr.Type;
9437 TypeSpec t = source.Type;
9439 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
9442 // When we are dealing with a struct, get the address of it to avoid value copy
9443 // Same cannot be done for reference type because array covariance and the
9444 // check in ldelema requires to specify the type of array element stored at the index
9446 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
9447 LoadInstanceAndArguments (ec, false, has_await_args.Value);
9449 if (has_await_args.Value) {
9450 if (source.ContainsEmitWithAwait ()) {
9451 source = source.EmitToField (ec);
9456 LoadInstanceAndArguments (ec, isCompound, false);
9461 ec.EmitArrayAddress (ac);
9464 ec.Emit (OpCodes.Dup);
9468 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
9470 if (has_await_args.Value) {
9471 if (source.ContainsEmitWithAwait ())
9472 source = source.EmitToField (ec);
9474 LoadInstanceAndArguments (ec, false, false);
9481 var lt = ea.Expr as LocalTemporary;
9487 ec.Emit (OpCodes.Dup);
9488 temp = new LocalTemporary (this.type);
9493 ec.EmitStoreFromPtr (t);
9495 ec.EmitArrayStore (ac);
9504 public override Expression EmitToField (EmitContext ec)
9507 // Have to be specialized for arrays to get access to
9508 // underlying element. Instead of another result copy we
9509 // need direct access to element
9513 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
9515 ea.Expr = ea.Expr.EmitToField (ec);
9519 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9521 #if NET_4_0 || MONODROID
9522 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9524 throw new NotImplementedException ();
9528 public override SLE.Expression MakeExpression (BuilderContext ctx)
9530 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9533 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
9535 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9536 return Arguments.MakeExpression (ea.Arguments, ctx);
9542 // Indexer access expression
9544 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
9546 IList<MemberSpec> indexers;
9547 Arguments arguments;
9548 TypeSpec queried_type;
9550 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
9551 : base (ea.Location)
9553 this.indexers = indexers;
9554 this.queried_type = queriedType;
9555 this.InstanceExpression = ea.Expr;
9556 this.arguments = ea.Arguments;
9561 protected override Arguments Arguments {
9570 protected override TypeSpec DeclaringType {
9572 return best_candidate.DeclaringType;
9576 public override bool IsInstance {
9582 public override bool IsStatic {
9588 public override string KindName {
9589 get { return "indexer"; }
9592 public override string Name {
9600 public override bool ContainsEmitWithAwait ()
9602 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
9605 public override Expression CreateExpressionTree (ResolveContext ec)
9607 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
9608 InstanceExpression.CreateExpressionTree (ec),
9609 new TypeOfMethod (Getter, loc));
9611 return CreateExpressionFactoryCall (ec, "Call", args);
9614 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9616 LocalTemporary await_source_arg = null;
9619 emitting_compound_assignment = true;
9620 if (source is DynamicExpressionStatement) {
9625 emitting_compound_assignment = false;
9627 if (has_await_arguments) {
9628 await_source_arg = new LocalTemporary (Type);
9629 await_source_arg.Store (ec);
9631 arguments.Add (new Argument (await_source_arg));
9634 temp = await_source_arg;
9637 has_await_arguments = false;
9642 ec.Emit (OpCodes.Dup);
9643 temp = new LocalTemporary (Type);
9649 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9650 source = source.EmitToField (ec);
9652 temp = new LocalTemporary (Type);
9659 arguments.Add (new Argument (source));
9662 var call = new CallEmitter ();
9663 call.InstanceExpression = InstanceExpression;
9664 if (arguments == null)
9665 call.InstanceExpressionOnStack = true;
9667 call.Emit (ec, Setter, arguments, loc);
9672 } else if (leave_copy) {
9676 if (await_source_arg != null) {
9677 await_source_arg.Release (ec);
9681 public override string GetSignatureForError ()
9683 return best_candidate.GetSignatureForError ();
9686 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9689 throw new NotSupportedException ();
9691 var value = new[] { source.MakeExpression (ctx) };
9692 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9693 #if NET_4_0 || MONODROID
9694 return SLE.Expression.Block (
9695 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9698 return args.First ();
9703 public override SLE.Expression MakeExpression (BuilderContext ctx)
9706 return base.MakeExpression (ctx);
9708 var args = Arguments.MakeExpression (arguments, ctx);
9709 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9713 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9715 if (best_candidate != null)
9718 eclass = ExprClass.IndexerAccess;
9721 arguments.Resolve (rc, out dynamic);
9723 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9726 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9727 res.BaseMembersProvider = this;
9728 res.InstanceQualifier = this;
9730 // TODO: Do I need 2 argument sets?
9731 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9732 if (best_candidate != null)
9733 type = res.BestCandidateReturnType;
9734 else if (!res.BestCandidateIsDynamic)
9739 // It has dynamic arguments
9742 Arguments args = new Arguments (arguments.Count + 1);
9744 rc.Report.Error (1972, loc,
9745 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9747 args.Add (new Argument (InstanceExpression));
9749 args.AddRange (arguments);
9751 best_candidate = null;
9752 return new DynamicIndexBinder (args, loc);
9756 // Try to avoid resolving left expression again
9758 if (right_side != null)
9759 ResolveInstanceExpression (rc, right_side);
9764 protected override void CloneTo (CloneContext clonectx, Expression t)
9766 IndexerExpr target = (IndexerExpr) t;
9768 if (arguments != null)
9769 target.arguments = arguments.Clone (clonectx);
9772 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9774 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9777 #region IBaseMembersProvider Members
9779 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9781 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9784 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9786 if (queried_type == member.DeclaringType)
9789 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9790 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9793 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9802 // A base access expression
9804 public class BaseThis : This
9806 public BaseThis (Location loc)
9811 public BaseThis (TypeSpec type, Location loc)
9815 eclass = ExprClass.Variable;
9820 public override string Name {
9828 public override Expression CreateExpressionTree (ResolveContext ec)
9830 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9831 return base.CreateExpressionTree (ec);
9834 public override void Emit (EmitContext ec)
9838 var context_type = ec.CurrentType;
9839 if (context_type.IsStruct) {
9840 ec.Emit (OpCodes.Ldobj, context_type);
9841 ec.Emit (OpCodes.Box, context_type);
9845 protected override void Error_ThisNotAvailable (ResolveContext ec)
9848 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9850 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9854 public override void ResolveBase (ResolveContext ec)
9856 base.ResolveBase (ec);
9857 type = ec.CurrentType.BaseType;
9860 public override object Accept (StructuralVisitor visitor)
9862 return visitor.Visit (this);
9867 /// This class exists solely to pass the Type around and to be a dummy
9868 /// that can be passed to the conversion functions (this is used by
9869 /// foreach implementation to typecast the object return value from
9870 /// get_Current into the proper type. All code has been generated and
9871 /// we only care about the side effect conversions to be performed
9873 /// This is also now used as a placeholder where a no-action expression
9874 /// is needed (the `New' class).
9876 public class EmptyExpression : Expression
9878 sealed class OutAccessExpression : EmptyExpression
9880 public OutAccessExpression (TypeSpec t)
9885 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9887 rc.Report.Error (206, right_side.Location,
9888 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
9894 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
9895 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
9896 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
9897 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
9898 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
9899 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
9900 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
9901 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
9903 public EmptyExpression (TypeSpec t)
9906 eclass = ExprClass.Value;
9907 loc = Location.Null;
9910 public override bool ContainsEmitWithAwait ()
9915 public override Expression CreateExpressionTree (ResolveContext ec)
9917 throw new NotSupportedException ("ET");
9920 protected override Expression DoResolve (ResolveContext ec)
9925 public override void Emit (EmitContext ec)
9927 // nothing, as we only exist to not do anything.
9930 public override void EmitSideEffect (EmitContext ec)
9934 public override object Accept (StructuralVisitor visitor)
9936 return visitor.Visit (this);
9940 sealed class EmptyAwaitExpression : EmptyExpression
9942 public EmptyAwaitExpression (TypeSpec type)
9947 public override bool ContainsEmitWithAwait ()
9954 // Empty statement expression
9956 public sealed class EmptyExpressionStatement : ExpressionStatement
9958 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
9960 private EmptyExpressionStatement ()
9962 loc = Location.Null;
9965 public override bool ContainsEmitWithAwait ()
9970 public override Expression CreateExpressionTree (ResolveContext ec)
9975 public override void EmitStatement (EmitContext ec)
9980 protected override Expression DoResolve (ResolveContext ec)
9982 eclass = ExprClass.Value;
9983 type = ec.BuiltinTypes.Object;
9987 public override void Emit (EmitContext ec)
9992 public override object Accept (StructuralVisitor visitor)
9994 return visitor.Visit (this);
9998 public class ErrorExpression : EmptyExpression
10000 public static readonly ErrorExpression Instance = new ErrorExpression ();
10002 private ErrorExpression ()
10003 : base (InternalType.ErrorType)
10007 public override Expression CreateExpressionTree (ResolveContext ec)
10012 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10017 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
10021 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
10025 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
10029 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
10033 public override object Accept (StructuralVisitor visitor)
10035 return visitor.Visit (this);
10039 public class UserCast : Expression {
10043 public UserCast (MethodSpec method, Expression source, Location l)
10045 if (source == null)
10046 throw new ArgumentNullException ("source");
10048 this.method = method;
10049 this.source = source;
10050 type = method.ReturnType;
10054 public Expression Source {
10060 public override bool ContainsEmitWithAwait ()
10062 return source.ContainsEmitWithAwait ();
10065 public override Expression CreateExpressionTree (ResolveContext ec)
10067 Arguments args = new Arguments (3);
10068 args.Add (new Argument (source.CreateExpressionTree (ec)));
10069 args.Add (new Argument (new TypeOf (type, loc)));
10070 args.Add (new Argument (new TypeOfMethod (method, loc)));
10071 return CreateExpressionFactoryCall (ec, "Convert", args);
10074 protected override Expression DoResolve (ResolveContext ec)
10076 ObsoleteAttribute oa = method.GetAttributeObsolete ();
10078 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
10080 eclass = ExprClass.Value;
10084 public override void Emit (EmitContext ec)
10087 ec.MarkCallEntry (loc);
10088 ec.Emit (OpCodes.Call, method);
10091 public override string GetSignatureForError ()
10093 return TypeManager.CSharpSignature (method);
10096 public override SLE.Expression MakeExpression (BuilderContext ctx)
10099 return base.MakeExpression (ctx);
10101 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
10107 // Holds additional type specifiers like ?, *, []
10109 public class ComposedTypeSpecifier
10111 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
10113 public readonly int Dimension;
10114 public readonly Location Location;
10116 public ComposedTypeSpecifier (int specifier, Location loc)
10118 this.Dimension = specifier;
10119 this.Location = loc;
10123 public bool IsNullable {
10125 return Dimension == -1;
10129 public bool IsPointer {
10131 return Dimension == -2;
10135 public ComposedTypeSpecifier Next { get; set; }
10139 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
10141 return new ComposedTypeSpecifier (dimension, loc);
10144 public static ComposedTypeSpecifier CreateNullable (Location loc)
10146 return new ComposedTypeSpecifier (-1, loc);
10149 public static ComposedTypeSpecifier CreatePointer (Location loc)
10151 return new ComposedTypeSpecifier (-2, loc);
10154 public string GetSignatureForError ()
10159 ArrayContainer.GetPostfixSignature (Dimension);
10161 return Next != null ? s + Next.GetSignatureForError () : s;
10166 // This class is used to "construct" the type during a typecast
10167 // operation. Since the Type.GetType class in .NET can parse
10168 // the type specification, we just use this to construct the type
10169 // one bit at a time.
10171 public class ComposedCast : TypeExpr {
10172 FullNamedExpression left;
10173 ComposedTypeSpecifier spec;
10175 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
10178 throw new ArgumentNullException ("spec");
10182 this.loc = left.Location;
10185 public override TypeSpec ResolveAsType (IMemberContext ec)
10187 type = left.ResolveAsType (ec);
10191 eclass = ExprClass.Type;
10193 var single_spec = spec;
10195 if (single_spec.IsNullable) {
10196 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
10200 single_spec = single_spec.Next;
10201 } else if (single_spec.IsPointer) {
10202 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
10205 if (!ec.IsUnsafe) {
10206 UnsafeError (ec.Module.Compiler.Report, loc);
10210 type = PointerContainer.MakeType (ec.Module, type);
10211 single_spec = single_spec.Next;
10212 } while (single_spec != null && single_spec.IsPointer);
10215 if (single_spec != null && single_spec.Dimension > 0) {
10216 if (type.IsSpecialRuntimeType) {
10217 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
10218 } else if (type.IsStatic) {
10219 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
10220 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
10221 type.GetSignatureForError ());
10223 MakeArray (ec.Module, single_spec);
10230 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
10232 if (spec.Next != null)
10233 MakeArray (module, spec.Next);
10235 type = ArrayContainer.MakeType (module, type, spec.Dimension);
10238 public override string GetSignatureForError ()
10240 return left.GetSignatureForError () + spec.GetSignatureForError ();
10243 public override object Accept (StructuralVisitor visitor)
10245 return visitor.Visit (this);
10249 class FixedBufferPtr : Expression
10251 readonly Expression array;
10253 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
10255 this.type = array_type;
10256 this.array = array;
10260 public override bool ContainsEmitWithAwait ()
10262 throw new NotImplementedException ();
10265 public override Expression CreateExpressionTree (ResolveContext ec)
10267 Error_PointerInsideExpressionTree (ec);
10271 public override void Emit(EmitContext ec)
10276 protected override Expression DoResolve (ResolveContext ec)
10278 type = PointerContainer.MakeType (ec.Module, type);
10279 eclass = ExprClass.Value;
10286 // This class is used to represent the address of an array, used
10287 // only by the Fixed statement, this generates "&a [0]" construct
10288 // for fixed (char *pa = a)
10290 class ArrayPtr : FixedBufferPtr
10292 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
10293 base (array, array_type, l)
10297 public override void Emit (EmitContext ec)
10302 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
10307 // Encapsulates a conversion rules required for array indexes
10309 public class ArrayIndexCast : TypeCast
10311 public ArrayIndexCast (Expression expr, TypeSpec returnType)
10312 : base (expr, returnType)
10314 if (expr.Type == returnType) // int -> int
10315 throw new ArgumentException ("unnecessary array index conversion");
10318 public override Expression CreateExpressionTree (ResolveContext ec)
10320 using (ec.Set (ResolveContext.Options.CheckedScope)) {
10321 return base.CreateExpressionTree (ec);
10325 public override void Emit (EmitContext ec)
10329 switch (child.Type.BuiltinType) {
10330 case BuiltinTypeSpec.Type.UInt:
10331 ec.Emit (OpCodes.Conv_U);
10333 case BuiltinTypeSpec.Type.Long:
10334 ec.Emit (OpCodes.Conv_Ovf_I);
10336 case BuiltinTypeSpec.Type.ULong:
10337 ec.Emit (OpCodes.Conv_Ovf_I_Un);
10340 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
10346 // Implements the `stackalloc' keyword
10348 public class StackAlloc : Expression {
10353 public StackAlloc (Expression type, Expression count, Location l)
10356 this.count = count;
10360 public Expression TypeExpression {
10366 public Expression CountExpression {
10372 public override bool ContainsEmitWithAwait ()
10377 public override Expression CreateExpressionTree (ResolveContext ec)
10379 throw new NotSupportedException ("ET");
10382 protected override Expression DoResolve (ResolveContext ec)
10384 count = count.Resolve (ec);
10388 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
10389 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
10394 Constant c = count as Constant;
10395 if (c != null && c.IsNegative) {
10396 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
10399 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
10400 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
10403 otype = t.ResolveAsType (ec);
10407 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
10410 type = PointerContainer.MakeType (ec.Module, otype);
10411 eclass = ExprClass.Value;
10416 public override void Emit (EmitContext ec)
10418 int size = BuiltinTypeSpec.GetSize (otype);
10423 ec.Emit (OpCodes.Sizeof, otype);
10427 ec.Emit (OpCodes.Mul_Ovf_Un);
10428 ec.Emit (OpCodes.Localloc);
10431 protected override void CloneTo (CloneContext clonectx, Expression t)
10433 StackAlloc target = (StackAlloc) t;
10434 target.count = count.Clone (clonectx);
10435 target.t = t.Clone (clonectx);
10438 public override object Accept (StructuralVisitor visitor)
10440 return visitor.Visit (this);
10445 // An object initializer expression
10447 public class ElementInitializer : Assign
10449 public readonly string Name;
10451 public ElementInitializer (string name, Expression initializer, Location loc)
10452 : base (null, initializer, loc)
10457 protected override void CloneTo (CloneContext clonectx, Expression t)
10459 ElementInitializer target = (ElementInitializer) t;
10460 target.source = source.Clone (clonectx);
10463 public override Expression CreateExpressionTree (ResolveContext ec)
10465 Arguments args = new Arguments (2);
10466 FieldExpr fe = target as FieldExpr;
10468 args.Add (new Argument (fe.CreateTypeOfExpression ()));
10470 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
10473 Expression arg_expr;
10474 var cinit = source as CollectionOrObjectInitializers;
10475 if (cinit == null) {
10477 arg_expr = source.CreateExpressionTree (ec);
10479 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
10480 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
10483 args.Add (new Argument (arg_expr));
10484 return CreateExpressionFactoryCall (ec, mname, args);
10487 protected override Expression DoResolve (ResolveContext ec)
10489 if (source == null)
10490 return EmptyExpressionStatement.Instance;
10492 var t = ec.CurrentInitializerVariable.Type;
10493 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10494 Arguments args = new Arguments (1);
10495 args.Add (new Argument (ec.CurrentInitializerVariable));
10496 target = new DynamicMemberBinder (Name, args, loc);
10499 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10500 if (member == null) {
10501 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10503 if (member != null) {
10504 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
10505 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
10510 if (member == null) {
10511 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
10515 if (!(member is PropertyExpr || member is FieldExpr)) {
10516 ec.Report.Error (1913, loc,
10517 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
10518 member.GetSignatureForError ());
10523 var me = member as MemberExpr;
10525 ec.Report.Error (1914, loc,
10526 "Static field or property `{0}' cannot be assigned in an object initializer",
10527 me.GetSignatureForError ());
10531 me.InstanceExpression = ec.CurrentInitializerVariable;
10534 if (source is CollectionOrObjectInitializers) {
10535 Expression previous = ec.CurrentInitializerVariable;
10536 ec.CurrentInitializerVariable = target;
10537 source = source.Resolve (ec);
10538 ec.CurrentInitializerVariable = previous;
10539 if (source == null)
10542 eclass = source.eclass;
10543 type = source.Type;
10547 return base.DoResolve (ec);
10550 public override void EmitStatement (EmitContext ec)
10552 if (source is CollectionOrObjectInitializers)
10555 base.EmitStatement (ec);
10560 // A collection initializer expression
10562 class CollectionElementInitializer : Invocation
10564 public class ElementInitializerArgument : Argument
10566 public ElementInitializerArgument (Expression e)
10572 sealed class AddMemberAccess : MemberAccess
10574 public AddMemberAccess (Expression expr, Location loc)
10575 : base (expr, "Add", loc)
10579 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10581 if (TypeManager.HasElementType (type))
10584 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10588 public CollectionElementInitializer (Expression argument)
10589 : base (null, new Arguments (1))
10591 base.arguments.Add (new ElementInitializerArgument (argument));
10592 this.loc = argument.Location;
10595 public CollectionElementInitializer (List<Expression> arguments, Location loc)
10596 : base (null, new Arguments (arguments.Count))
10598 foreach (Expression e in arguments)
10599 base.arguments.Add (new ElementInitializerArgument (e));
10604 public CollectionElementInitializer (Location loc)
10605 : base (null, null)
10610 public override Expression CreateExpressionTree (ResolveContext ec)
10612 Arguments args = new Arguments (2);
10613 args.Add (new Argument (mg.CreateExpressionTree (ec)));
10615 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
10616 foreach (Argument a in arguments)
10617 expr_initializers.Add (a.CreateExpressionTree (ec));
10619 args.Add (new Argument (new ArrayCreation (
10620 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
10621 return CreateExpressionFactoryCall (ec, "ElementInit", args);
10624 protected override void CloneTo (CloneContext clonectx, Expression t)
10626 CollectionElementInitializer target = (CollectionElementInitializer) t;
10627 if (arguments != null)
10628 target.arguments = arguments.Clone (clonectx);
10631 protected override Expression DoResolve (ResolveContext ec)
10633 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
10635 return base.DoResolve (ec);
10640 // A block of object or collection initializers
10642 public class CollectionOrObjectInitializers : ExpressionStatement
10644 IList<Expression> initializers;
10645 bool is_collection_initialization;
10647 public CollectionOrObjectInitializers (Location loc)
10648 : this (new Expression[0], loc)
10652 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10654 this.initializers = initializers;
10658 public IList<Expression> Initializers {
10660 return initializers;
10664 public bool IsEmpty {
10666 return initializers.Count == 0;
10670 public bool IsCollectionInitializer {
10672 return is_collection_initialization;
10676 protected override void CloneTo (CloneContext clonectx, Expression target)
10678 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10680 t.initializers = new List<Expression> (initializers.Count);
10681 foreach (var e in initializers)
10682 t.initializers.Add (e.Clone (clonectx));
10685 public override bool ContainsEmitWithAwait ()
10687 foreach (var e in initializers) {
10688 if (e.ContainsEmitWithAwait ())
10695 public override Expression CreateExpressionTree (ResolveContext ec)
10697 return CreateExpressionTree (ec, false);
10700 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10702 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10703 foreach (Expression e in initializers) {
10704 Expression expr = e.CreateExpressionTree (ec);
10706 expr_initializers.Add (expr);
10710 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10712 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10715 protected override Expression DoResolve (ResolveContext ec)
10717 List<string> element_names = null;
10718 for (int i = 0; i < initializers.Count; ++i) {
10719 Expression initializer = initializers [i];
10720 ElementInitializer element_initializer = initializer as ElementInitializer;
10723 if (element_initializer != null) {
10724 element_names = new List<string> (initializers.Count);
10725 element_names.Add (element_initializer.Name);
10726 } else if (initializer is CompletingExpression){
10727 initializer.Resolve (ec);
10728 throw new InternalErrorException ("This line should never be reached");
10730 var t = ec.CurrentInitializerVariable.Type;
10731 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10732 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10733 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10734 "object initializer because type `{1}' does not implement `{2}' interface",
10735 ec.CurrentInitializerVariable.GetSignatureForError (),
10736 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10737 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10740 is_collection_initialization = true;
10743 if (is_collection_initialization != (element_initializer == null)) {
10744 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10745 is_collection_initialization ? "collection initializer" : "object initializer");
10749 if (!is_collection_initialization) {
10750 if (element_names.Contains (element_initializer.Name)) {
10751 ec.Report.Error (1912, element_initializer.Location,
10752 "An object initializer includes more than one member `{0}' initialization",
10753 element_initializer.Name);
10755 element_names.Add (element_initializer.Name);
10760 Expression e = initializer.Resolve (ec);
10761 if (e == EmptyExpressionStatement.Instance)
10762 initializers.RemoveAt (i--);
10764 initializers [i] = e;
10767 type = ec.CurrentInitializerVariable.Type;
10768 if (is_collection_initialization) {
10769 if (TypeManager.HasElementType (type)) {
10770 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10771 type.GetSignatureForError ());
10775 eclass = ExprClass.Variable;
10779 public override void Emit (EmitContext ec)
10781 EmitStatement (ec);
10784 public override void EmitStatement (EmitContext ec)
10786 foreach (ExpressionStatement e in initializers) {
10787 // TODO: need location region
10788 ec.Mark (e.Location);
10789 e.EmitStatement (ec);
10795 // New expression with element/object initializers
10797 public class NewInitialize : New
10800 // This class serves as a proxy for variable initializer target instances.
10801 // A real variable is assigned later when we resolve left side of an
10804 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10806 NewInitialize new_instance;
10808 public InitializerTargetExpression (NewInitialize newInstance)
10810 this.type = newInstance.type;
10811 this.loc = newInstance.loc;
10812 this.eclass = newInstance.eclass;
10813 this.new_instance = newInstance;
10816 public override bool ContainsEmitWithAwait ()
10821 public override Expression CreateExpressionTree (ResolveContext ec)
10823 // Should not be reached
10824 throw new NotSupportedException ("ET");
10827 protected override Expression DoResolve (ResolveContext ec)
10832 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10837 public override void Emit (EmitContext ec)
10839 Expression e = (Expression) new_instance.instance;
10843 public override Expression EmitToField (EmitContext ec)
10845 return (Expression) new_instance.instance;
10848 #region IMemoryLocation Members
10850 public void AddressOf (EmitContext ec, AddressOp mode)
10852 new_instance.instance.AddressOf (ec, mode);
10858 CollectionOrObjectInitializers initializers;
10859 IMemoryLocation instance;
10860 DynamicExpressionStatement dynamic;
10862 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10863 : base (requested_type, arguments, l)
10865 this.initializers = initializers;
10868 public CollectionOrObjectInitializers Initializers {
10870 return initializers;
10874 protected override void CloneTo (CloneContext clonectx, Expression t)
10876 base.CloneTo (clonectx, t);
10878 NewInitialize target = (NewInitialize) t;
10879 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
10882 public override bool ContainsEmitWithAwait ()
10884 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
10887 public override Expression CreateExpressionTree (ResolveContext ec)
10889 Arguments args = new Arguments (2);
10890 args.Add (new Argument (base.CreateExpressionTree (ec)));
10891 if (!initializers.IsEmpty)
10892 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
10894 return CreateExpressionFactoryCall (ec,
10895 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
10899 protected override Expression DoResolve (ResolveContext ec)
10901 Expression e = base.DoResolve (ec);
10905 if (type.IsDelegate) {
10906 ec.Report.Error (1958, Initializers.Location,
10907 "Object and collection initializers cannot be used to instantiate a delegate");
10910 Expression previous = ec.CurrentInitializerVariable;
10911 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
10912 initializers.Resolve (ec);
10913 ec.CurrentInitializerVariable = previous;
10915 dynamic = e as DynamicExpressionStatement;
10916 if (dynamic != null)
10922 public override bool Emit (EmitContext ec, IMemoryLocation target)
10924 bool left_on_stack;
10925 if (dynamic != null) {
10927 left_on_stack = true;
10929 left_on_stack = base.Emit (ec, target);
10932 if (initializers.IsEmpty)
10933 return left_on_stack;
10935 LocalTemporary temp = null;
10937 instance = target as LocalTemporary;
10939 if (instance == null) {
10940 if (!left_on_stack) {
10941 VariableReference vr = target as VariableReference;
10943 // FIXME: This still does not work correctly for pre-set variables
10944 if (vr != null && vr.IsRef)
10945 target.AddressOf (ec, AddressOp.Load);
10947 ((Expression) target).Emit (ec);
10948 left_on_stack = true;
10951 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
10952 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
10954 temp = new LocalTemporary (type);
10959 if (left_on_stack && temp != null)
10962 initializers.Emit (ec);
10964 if (left_on_stack) {
10965 if (temp != null) {
10969 ((Expression) instance).Emit (ec);
10973 return left_on_stack;
10976 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
10978 instance = base.EmitAddressOf (ec, Mode);
10980 if (!initializers.IsEmpty)
10981 initializers.Emit (ec);
10986 public override object Accept (StructuralVisitor visitor)
10988 return visitor.Visit (this);
10992 public class NewAnonymousType : New
10994 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
10996 List<AnonymousTypeParameter> parameters;
10997 readonly TypeContainer parent;
10998 AnonymousTypeClass anonymous_type;
11000 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
11001 : base (null, null, loc)
11003 this.parameters = parameters;
11004 this.parent = parent;
11007 public List<AnonymousTypeParameter> Parameters {
11009 return this.parameters;
11013 protected override void CloneTo (CloneContext clonectx, Expression target)
11015 if (parameters == null)
11018 NewAnonymousType t = (NewAnonymousType) target;
11019 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
11020 foreach (AnonymousTypeParameter atp in parameters)
11021 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
11024 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
11026 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
11030 type = AnonymousTypeClass.Create (parent, parameters, loc);
11034 int errors = ec.Report.Errors;
11035 type.CreateContainer ();
11036 type.DefineContainer ();
11038 if ((ec.Report.Errors - errors) == 0) {
11039 parent.Module.AddAnonymousType (type);
11045 public override Expression CreateExpressionTree (ResolveContext ec)
11047 if (parameters == null)
11048 return base.CreateExpressionTree (ec);
11050 var init = new ArrayInitializer (parameters.Count, loc);
11051 foreach (var m in anonymous_type.Members) {
11052 var p = m as Property;
11054 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
11057 var ctor_args = new ArrayInitializer (arguments.Count, loc);
11058 foreach (Argument a in arguments)
11059 ctor_args.Add (a.CreateExpressionTree (ec));
11061 Arguments args = new Arguments (3);
11062 args.Add (new Argument (new TypeOfMethod (method, loc)));
11063 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
11064 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
11066 return CreateExpressionFactoryCall (ec, "New", args);
11069 protected override Expression DoResolve (ResolveContext ec)
11071 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
11072 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
11076 if (parameters == null) {
11077 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
11078 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
11079 return base.DoResolve (ec);
11082 bool error = false;
11083 arguments = new Arguments (parameters.Count);
11084 var t_args = new TypeSpec [parameters.Count];
11085 for (int i = 0; i < parameters.Count; ++i) {
11086 Expression e = parameters [i].Resolve (ec);
11092 arguments.Add (new Argument (e));
11093 t_args [i] = e.Type;
11099 anonymous_type = CreateAnonymousType (ec, parameters);
11100 if (anonymous_type == null)
11103 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
11104 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
11105 eclass = ExprClass.Value;
11109 public override object Accept (StructuralVisitor visitor)
11111 return visitor.Visit (this);
11115 public class AnonymousTypeParameter : ShimExpression
11117 public readonly string Name;
11119 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
11120 : base (initializer)
11126 public AnonymousTypeParameter (Parameter parameter)
11127 : base (new SimpleName (parameter.Name, parameter.Location))
11129 this.Name = parameter.Name;
11130 this.loc = parameter.Location;
11133 public override bool Equals (object o)
11135 AnonymousTypeParameter other = o as AnonymousTypeParameter;
11136 return other != null && Name == other.Name;
11139 public override int GetHashCode ()
11141 return Name.GetHashCode ();
11144 protected override Expression DoResolve (ResolveContext ec)
11146 Expression e = expr.Resolve (ec);
11150 if (e.eclass == ExprClass.MethodGroup) {
11151 Error_InvalidInitializer (ec, e.ExprClassName);
11156 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
11157 Error_InvalidInitializer (ec, type.GetSignatureForError ());
11164 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
11166 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
11167 Name, initializer);