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.
13 namespace Mono.CSharp {
15 using System.Collections.Generic;
16 using System.Reflection;
17 using System.Reflection.Emit;
20 using SLE = System.Linq.Expressions;
23 // This is an user operator expression, automatically created during
26 public class UserOperatorCall : Expression {
27 public delegate Expression ExpressionTreeExpression (ResolveContext ec, MethodGroupExpr mg);
29 protected readonly Arguments arguments;
30 protected readonly MethodGroupExpr mg;
31 readonly ExpressionTreeExpression expr_tree;
33 public UserOperatorCall (MethodGroupExpr mg, Arguments args, ExpressionTreeExpression expr_tree, Location loc)
36 this.arguments = args;
37 this.expr_tree = expr_tree;
39 type = mg.BestCandidate.ReturnType;
40 eclass = ExprClass.Value;
44 public override Expression CreateExpressionTree (ResolveContext ec)
46 if (expr_tree != null)
47 return expr_tree (ec, mg);
49 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
50 new NullLiteral (loc),
51 mg.CreateExpressionTree (ec));
53 return CreateExpressionFactoryCall (ec, "Call", args);
56 protected override void CloneTo (CloneContext context, Expression target)
61 protected override Expression DoResolve (ResolveContext ec)
64 // We are born fully resolved
69 public override void Emit (EmitContext ec)
71 mg.EmitCall (ec, arguments);
74 public override SLE.Expression MakeExpression (BuilderContext ctx)
76 var method = mg.BestCandidate.GetMetaInfo () as MethodInfo;
77 return SLE.Expression.Call (method, Arguments.MakeExpression (arguments, ctx));
80 public MethodGroupExpr Method {
85 public class ParenthesizedExpression : ShimExpression
87 public ParenthesizedExpression (Expression expr)
93 protected override Expression DoResolve (ResolveContext ec)
95 return expr.Resolve (ec);
98 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
100 return expr.DoResolveLValue (ec, right_side);
105 // Unary implements unary expressions.
107 public class Unary : Expression
109 public enum Operator : byte {
110 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
114 static TypeSpec[][] predefined_operators;
116 public readonly Operator Oper;
117 public Expression Expr;
118 Expression enum_conversion;
120 public Unary (Operator op, Expression expr, Location loc)
128 // This routine will attempt to simplify the unary expression when the
129 // argument is a constant.
131 Constant TryReduceConstant (ResolveContext ec, Constant e)
133 if (e is EmptyConstantCast)
134 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
136 if (e is SideEffectConstant) {
137 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
138 return r == null ? null : new SideEffectConstant (r, e, r.Location);
141 TypeSpec expr_type = e.Type;
144 case Operator.UnaryPlus:
145 // Unary numeric promotions
146 if (expr_type == TypeManager.byte_type)
147 return new IntConstant (((ByteConstant)e).Value, e.Location);
148 if (expr_type == TypeManager.sbyte_type)
149 return new IntConstant (((SByteConstant)e).Value, e.Location);
150 if (expr_type == TypeManager.short_type)
151 return new IntConstant (((ShortConstant)e).Value, e.Location);
152 if (expr_type == TypeManager.ushort_type)
153 return new IntConstant (((UShortConstant)e).Value, e.Location);
154 if (expr_type == TypeManager.char_type)
155 return new IntConstant (((CharConstant)e).Value, e.Location);
157 // Predefined operators
158 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
159 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
160 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
161 expr_type == TypeManager.decimal_type) {
167 case Operator.UnaryNegation:
168 // Unary numeric promotions
169 if (expr_type == TypeManager.byte_type)
170 return new IntConstant (-((ByteConstant)e).Value, e.Location);
171 if (expr_type == TypeManager.sbyte_type)
172 return new IntConstant (-((SByteConstant)e).Value, e.Location);
173 if (expr_type == TypeManager.short_type)
174 return new IntConstant (-((ShortConstant)e).Value, e.Location);
175 if (expr_type == TypeManager.ushort_type)
176 return new IntConstant (-((UShortConstant)e).Value, e.Location);
177 if (expr_type == TypeManager.char_type)
178 return new IntConstant (-((CharConstant)e).Value, e.Location);
180 // Predefined operators
181 if (expr_type == TypeManager.int32_type) {
182 int value = ((IntConstant)e).Value;
183 if (value == int.MinValue) {
184 if (ec.ConstantCheckState) {
185 ConstantFold.Error_CompileTimeOverflow (ec, loc);
190 return new IntConstant (-value, e.Location);
192 if (expr_type == TypeManager.int64_type) {
193 long value = ((LongConstant)e).Value;
194 if (value == long.MinValue) {
195 if (ec.ConstantCheckState) {
196 ConstantFold.Error_CompileTimeOverflow (ec, loc);
201 return new LongConstant (-value, e.Location);
204 if (expr_type == TypeManager.uint32_type) {
205 UIntLiteral uil = e as UIntLiteral;
207 if (uil.Value == int.MaxValue + (uint) 1)
208 return new IntLiteral (int.MinValue, e.Location);
209 return new LongLiteral (-uil.Value, e.Location);
211 return new LongConstant (-((UIntConstant)e).Value, e.Location);
214 if (expr_type == TypeManager.uint64_type) {
215 ULongLiteral ull = e as ULongLiteral;
216 if (ull != null && ull.Value == 9223372036854775808)
217 return new LongLiteral (long.MinValue, e.Location);
221 if (expr_type == TypeManager.float_type) {
222 FloatLiteral fl = e as FloatLiteral;
223 // For better error reporting
225 return new FloatLiteral (-fl.Value, e.Location);
227 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
229 if (expr_type == TypeManager.double_type) {
230 DoubleLiteral dl = e as DoubleLiteral;
231 // For better error reporting
233 return new DoubleLiteral (-dl.Value, e.Location);
235 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
237 if (expr_type == TypeManager.decimal_type)
238 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
242 case Operator.LogicalNot:
243 if (expr_type != TypeManager.bool_type)
246 bool b = (bool)e.GetValue ();
247 return new BoolConstant (!b, e.Location);
249 case Operator.OnesComplement:
250 // Unary numeric promotions
251 if (expr_type == TypeManager.byte_type)
252 return new IntConstant (~((ByteConstant)e).Value, e.Location);
253 if (expr_type == TypeManager.sbyte_type)
254 return new IntConstant (~((SByteConstant)e).Value, e.Location);
255 if (expr_type == TypeManager.short_type)
256 return new IntConstant (~((ShortConstant)e).Value, e.Location);
257 if (expr_type == TypeManager.ushort_type)
258 return new IntConstant (~((UShortConstant)e).Value, e.Location);
259 if (expr_type == TypeManager.char_type)
260 return new IntConstant (~((CharConstant)e).Value, e.Location);
262 // Predefined operators
263 if (expr_type == TypeManager.int32_type)
264 return new IntConstant (~((IntConstant)e).Value, e.Location);
265 if (expr_type == TypeManager.uint32_type)
266 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
267 if (expr_type == TypeManager.int64_type)
268 return new LongConstant (~((LongConstant)e).Value, e.Location);
269 if (expr_type == TypeManager.uint64_type){
270 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
272 if (e is EnumConstant) {
273 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
275 e = new EnumConstant (e, expr_type);
280 throw new Exception ("Can not constant fold: " + Oper.ToString());
283 protected Expression ResolveOperator (ResolveContext ec, Expression expr)
285 eclass = ExprClass.Value;
287 if (predefined_operators == null)
288 CreatePredefinedOperatorsTable ();
290 TypeSpec expr_type = expr.Type;
291 Expression best_expr;
294 // Primitive types first
296 if (TypeManager.IsPrimitiveType (expr_type)) {
297 best_expr = ResolvePrimitivePredefinedType (expr);
298 if (best_expr == null)
301 type = best_expr.Type;
307 // E operator ~(E x);
309 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
310 return ResolveEnumOperator (ec, expr);
312 return ResolveUserType (ec, expr);
315 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr)
317 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
318 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
319 if (best_expr == null)
323 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
325 return EmptyCast.Create (this, type);
328 public override Expression CreateExpressionTree (ResolveContext ec)
330 return CreateExpressionTree (ec, null);
333 Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr user_op)
337 case Operator.AddressOf:
338 Error_PointerInsideExpressionTree (ec);
340 case Operator.UnaryNegation:
341 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
342 method_name = "NegateChecked";
344 method_name = "Negate";
346 case Operator.OnesComplement:
347 case Operator.LogicalNot:
350 case Operator.UnaryPlus:
351 method_name = "UnaryPlus";
354 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
357 Arguments args = new Arguments (2);
358 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
360 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
361 return CreateExpressionFactoryCall (ec, method_name, args);
364 static void CreatePredefinedOperatorsTable ()
366 predefined_operators = new TypeSpec [(int) Operator.TOP] [];
369 // 7.6.1 Unary plus operator
371 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
372 TypeManager.int32_type, TypeManager.uint32_type,
373 TypeManager.int64_type, TypeManager.uint64_type,
374 TypeManager.float_type, TypeManager.double_type,
375 TypeManager.decimal_type
379 // 7.6.2 Unary minus operator
381 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
382 TypeManager.int32_type,
383 TypeManager.int64_type,
384 TypeManager.float_type, TypeManager.double_type,
385 TypeManager.decimal_type
389 // 7.6.3 Logical negation operator
391 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
392 TypeManager.bool_type
396 // 7.6.4 Bitwise complement operator
398 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
399 TypeManager.int32_type, TypeManager.uint32_type,
400 TypeManager.int64_type, TypeManager.uint64_type
405 // Unary numeric promotions
407 static Expression DoNumericPromotion (Operator op, Expression expr)
409 TypeSpec expr_type = expr.Type;
410 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
411 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
412 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
413 expr_type == TypeManager.char_type)
414 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
416 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
417 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
422 protected override Expression DoResolve (ResolveContext ec)
424 if (Oper == Operator.AddressOf) {
425 return ResolveAddressOf (ec);
428 Expr = Expr.Resolve (ec);
432 if (Expr.Type == InternalType.Dynamic) {
433 Arguments args = new Arguments (1);
434 args.Add (new Argument (Expr));
435 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
438 if (TypeManager.IsNullableType (Expr.Type))
439 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
442 // Attempt to use a constant folding operation.
444 Constant cexpr = Expr as Constant;
446 cexpr = TryReduceConstant (ec, cexpr);
448 return cexpr.Resolve (ec);
451 Expression expr = ResolveOperator (ec, Expr);
453 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
456 // Reduce unary operator on predefined types
458 if (expr == this && Oper == Operator.UnaryPlus)
464 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
469 public override void Emit (EmitContext ec)
471 EmitOperator (ec, type);
474 protected void EmitOperator (EmitContext ec, TypeSpec type)
477 case Operator.UnaryPlus:
481 case Operator.UnaryNegation:
482 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
483 ec.Emit (OpCodes.Ldc_I4_0);
484 if (type == TypeManager.int64_type)
485 ec.Emit (OpCodes.Conv_U8);
487 ec.Emit (OpCodes.Sub_Ovf);
490 ec.Emit (OpCodes.Neg);
495 case Operator.LogicalNot:
497 ec.Emit (OpCodes.Ldc_I4_0);
498 ec.Emit (OpCodes.Ceq);
501 case Operator.OnesComplement:
503 ec.Emit (OpCodes.Not);
506 case Operator.AddressOf:
507 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
511 throw new Exception ("This should not happen: Operator = "
516 // Same trick as in Binary expression
518 if (enum_conversion != null)
519 enum_conversion.Emit (ec);
522 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
524 if (Oper == Operator.LogicalNot)
525 Expr.EmitBranchable (ec, target, !on_true);
527 base.EmitBranchable (ec, target, on_true);
530 public override void EmitSideEffect (EmitContext ec)
532 Expr.EmitSideEffect (ec);
535 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Location loc, string oper, TypeSpec t)
537 ec.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
538 oper, TypeManager.CSharpName (t));
542 // Converts operator to System.Linq.Expressions.ExpressionType enum name
544 string GetOperatorExpressionTypeName ()
547 case Operator.OnesComplement:
548 return "OnesComplement";
549 case Operator.LogicalNot:
551 case Operator.UnaryNegation:
553 case Operator.UnaryPlus:
556 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
560 static bool IsFloat (TypeSpec t)
562 return t == TypeManager.float_type || t == TypeManager.double_type;
566 // Returns a stringified representation of the Operator
568 public static string OperName (Operator oper)
571 case Operator.UnaryPlus:
573 case Operator.UnaryNegation:
575 case Operator.LogicalNot:
577 case Operator.OnesComplement:
579 case Operator.AddressOf:
583 throw new NotImplementedException (oper.ToString ());
586 public override SLE.Expression MakeExpression (BuilderContext ctx)
588 var expr = Expr.MakeExpression (ctx);
589 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
592 case Operator.UnaryNegation:
593 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
594 case Operator.LogicalNot:
595 return SLE.Expression.Not (expr);
597 case Operator.OnesComplement:
598 return SLE.Expression.OnesComplement (expr);
601 throw new NotImplementedException (Oper.ToString ());
605 public static void Reset ()
607 predefined_operators = null;
610 Expression ResolveAddressOf (ResolveContext ec)
613 UnsafeError (ec, loc);
615 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
616 if (Expr == null || Expr.eclass != ExprClass.Variable) {
617 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
621 if (!TypeManager.VerifyUnmanaged (ec.Compiler, Expr.Type, loc)) {
625 IVariableReference vr = Expr as IVariableReference;
628 VariableInfo vi = vr.VariableInfo;
630 if (vi.LocalInfo != null)
631 vi.LocalInfo.Used = true;
634 // A variable is considered definitely assigned if you take its address.
639 is_fixed = vr.IsFixed;
640 vr.SetHasAddressTaken ();
643 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
646 IFixedExpression fe = Expr as IFixedExpression;
647 is_fixed = fe != null && fe.IsFixed;
650 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
651 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
654 type = PointerContainer.MakeType (Expr.Type);
655 eclass = ExprClass.Value;
659 Expression ResolvePrimitivePredefinedType (Expression expr)
661 expr = DoNumericPromotion (Oper, expr);
662 TypeSpec expr_type = expr.Type;
663 TypeSpec[] predefined = predefined_operators [(int) Oper];
664 foreach (TypeSpec t in predefined) {
672 // Perform user-operator overload resolution
674 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
676 CSharp.Operator.OpType op_type;
678 case Operator.LogicalNot:
679 op_type = CSharp.Operator.OpType.LogicalNot; break;
680 case Operator.OnesComplement:
681 op_type = CSharp.Operator.OpType.OnesComplement; break;
682 case Operator.UnaryNegation:
683 op_type = CSharp.Operator.OpType.UnaryNegation; break;
684 case Operator.UnaryPlus:
685 op_type = CSharp.Operator.OpType.UnaryPlus; break;
687 throw new InternalErrorException (Oper.ToString ());
690 string op_name = CSharp.Operator.GetMetadataName (op_type);
691 MethodGroupExpr user_op = MethodLookup (ec.Compiler, ec.CurrentType, expr.Type, MemberKind.Operator, op_name, 0, expr.Location);
695 Arguments args = new Arguments (1);
696 args.Add (new Argument (expr));
697 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
702 Expr = args [0].Expr;
703 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
707 // Unary user type overload resolution
709 Expression ResolveUserType (ResolveContext ec, Expression expr)
711 Expression best_expr = ResolveUserOperator (ec, expr);
712 if (best_expr != null)
715 TypeSpec[] predefined = predefined_operators [(int) Oper];
716 foreach (TypeSpec t in predefined) {
717 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
718 if (oper_expr == null)
722 // decimal type is predefined but has user-operators
724 if (oper_expr.Type == TypeManager.decimal_type)
725 oper_expr = ResolveUserType (ec, oper_expr);
727 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
729 if (oper_expr == null)
732 if (best_expr == null) {
733 best_expr = oper_expr;
737 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
739 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
740 OperName (Oper), TypeManager.CSharpName (expr.Type));
745 best_expr = oper_expr;
748 if (best_expr == null)
752 // HACK: Decimal user-operator is included in standard operators
754 if (best_expr.Type == TypeManager.decimal_type)
758 type = best_expr.Type;
762 protected override void CloneTo (CloneContext clonectx, Expression t)
764 Unary target = (Unary) t;
766 target.Expr = Expr.Clone (clonectx);
771 // Unary operators are turned into Indirection expressions
772 // after semantic analysis (this is so we can take the address
773 // of an indirection).
775 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
777 LocalTemporary temporary;
780 public Indirection (Expression expr, Location l)
786 public override Expression CreateExpressionTree (ResolveContext ec)
788 Error_PointerInsideExpressionTree (ec);
792 protected override void CloneTo (CloneContext clonectx, Expression t)
794 Indirection target = (Indirection) t;
795 target.expr = expr.Clone (clonectx);
798 public override void Emit (EmitContext ec)
803 ec.EmitLoadFromPtr (Type);
806 public void Emit (EmitContext ec, bool leave_copy)
810 ec.Emit (OpCodes.Dup);
811 temporary = new LocalTemporary (expr.Type);
812 temporary.Store (ec);
816 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
818 prepared = prepare_for_load;
822 if (prepare_for_load)
823 ec.Emit (OpCodes.Dup);
827 ec.Emit (OpCodes.Dup);
828 temporary = new LocalTemporary (expr.Type);
829 temporary.Store (ec);
832 ec.EmitStoreFromPtr (type);
834 if (temporary != null) {
836 temporary.Release (ec);
840 public void AddressOf (EmitContext ec, AddressOp Mode)
845 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
847 return DoResolve (ec);
850 protected override Expression DoResolve (ResolveContext ec)
852 expr = expr.Resolve (ec);
857 UnsafeError (ec, loc);
859 if (!expr.Type.IsPointer) {
860 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
864 if (expr.Type == TypeManager.void_ptr_type) {
865 ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
869 type = TypeManager.GetElementType (expr.Type);
870 eclass = ExprClass.Variable;
874 public bool IsFixed {
878 public override string ToString ()
880 return "*(" + expr + ")";
885 /// Unary Mutator expressions (pre and post ++ and --)
889 /// UnaryMutator implements ++ and -- expressions. It derives from
890 /// ExpressionStatement becuase the pre/post increment/decrement
891 /// operators can be used in a statement context.
893 /// FIXME: Idea, we could split this up in two classes, one simpler
894 /// for the common case, and one with the extra fields for more complex
895 /// classes (indexers require temporary access; overloaded require method)
898 public class UnaryMutator : ExpressionStatement
900 class DynamicPostMutator : Expression, IAssignMethod
905 public DynamicPostMutator (Expression expr)
908 this.type = expr.Type;
909 this.loc = expr.Location;
912 public override Expression CreateExpressionTree (ResolveContext ec)
914 throw new NotImplementedException ("ET");
917 protected override Expression DoResolve (ResolveContext rc)
919 eclass = expr.eclass;
923 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
925 expr.DoResolveLValue (ec, right_side);
926 return DoResolve (ec);
929 public override void Emit (EmitContext ec)
934 public void Emit (EmitContext ec, bool leave_copy)
936 throw new NotImplementedException ();
940 // Emits target assignment using unmodified source value
942 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
945 // Allocate temporary variable to keep original value before it's modified
947 temp = new LocalTemporary (type);
951 ((IAssignMethod) expr).EmitAssign (ec, source, false, prepare_for_load);
962 public enum Mode : byte {
969 PreDecrement = IsDecrement,
970 PostIncrement = IsPost,
971 PostDecrement = IsPost | IsDecrement
975 bool is_expr, recurse;
979 // Holds the real operation
980 Expression operation;
982 public UnaryMutator (Mode m, Expression e, Location loc)
989 public override Expression CreateExpressionTree (ResolveContext ec)
991 return new SimpleAssign (this, this).CreateExpressionTree (ec);
994 protected override Expression DoResolve (ResolveContext ec)
996 expr = expr.Resolve (ec);
1001 if (expr.Type == InternalType.Dynamic) {
1003 // Handle postfix unary operators using local
1004 // temporary variable
1006 if ((mode & Mode.IsPost) != 0)
1007 expr = new DynamicPostMutator (expr);
1009 Arguments args = new Arguments (1);
1010 args.Add (new Argument (expr));
1011 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1014 if (TypeManager.IsNullableType (expr.Type))
1015 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1017 eclass = ExprClass.Value;
1019 return ResolveOperator (ec);
1022 void EmitCode (EmitContext ec, bool is_expr)
1025 this.is_expr = is_expr;
1026 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1029 public override void Emit (EmitContext ec)
1032 // We use recurse to allow ourselfs to be the source
1033 // of an assignment. This little hack prevents us from
1034 // having to allocate another expression
1037 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1039 operation.Emit (ec);
1045 EmitCode (ec, true);
1048 public override void EmitStatement (EmitContext ec)
1050 EmitCode (ec, false);
1054 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1056 string GetOperatorExpressionTypeName ()
1058 return IsDecrement ? "Decrement" : "Increment";
1062 get { return (mode & Mode.IsDecrement) != 0; }
1066 // Returns whether an object of type `t' can be incremented
1067 // or decremented with add/sub (ie, basically whether we can
1068 // use pre-post incr-decr operations on it, but it is not a
1069 // System.Decimal, which we require operator overloading to catch)
1071 static bool IsPredefinedOperator (TypeSpec t)
1073 return (TypeManager.IsPrimitiveType (t) && t != TypeManager.bool_type) ||
1074 TypeManager.IsEnumType (t) ||
1075 t.IsPointer && t != TypeManager.void_ptr_type;
1079 public override SLE.Expression MakeExpression (BuilderContext ctx)
1081 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1082 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1083 return SLE.Expression.Assign (target, source);
1087 protected override void CloneTo (CloneContext clonectx, Expression t)
1089 UnaryMutator target = (UnaryMutator) t;
1091 target.expr = expr.Clone (clonectx);
1094 Expression ResolveOperator (ResolveContext ec)
1096 if (expr is RuntimeValueExpression) {
1099 // Use itself at the top of the stack
1100 operation = new EmptyExpression (type);
1104 // The operand of the prefix/postfix increment decrement operators
1105 // should be an expression that is classified as a variable,
1106 // a property access or an indexer access
1108 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1109 expr = expr.ResolveLValue (ec, expr);
1111 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1115 // 1. Check predefined types
1117 if (IsPredefinedOperator (type)) {
1118 // TODO: Move to IntConstant once I get rid of int32_type
1119 var one = new IntConstant (1, loc);
1121 // TODO: Cache this based on type when using EmptyExpression in
1123 Binary.Operator op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1124 operation = new Binary (op, operation, one, loc);
1125 operation = operation.Resolve (ec);
1126 if (operation != null && operation.Type != type)
1127 operation = Convert.ExplicitNumericConversion (operation, type);
1133 // Step 2: Perform Operator Overload location
1138 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
1140 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
1142 var mg = MethodLookup (ec.Compiler, ec.CurrentType, type, MemberKind.Operator, op_name, 0, loc);
1145 Arguments args = new Arguments (1);
1146 args.Add (new Argument (expr));
1147 mg = mg.OverloadResolve (ec, ref args, false, loc);
1151 args[0].Expr = operation;
1152 operation = new UserOperatorCall (mg, args, null, loc);
1153 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1157 string name = IsDecrement ?
1158 Operator.GetName (Operator.OpType.Decrement) :
1159 Operator.GetName (Operator.OpType.Increment);
1161 Unary.Error_OperatorCannotBeApplied (ec, loc, name, type);
1167 /// Base class for the `Is' and `As' classes.
1171 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1174 public abstract class Probe : Expression {
1175 public Expression ProbeType;
1176 protected Expression expr;
1177 protected TypeExpr probe_type_expr;
1179 public Probe (Expression expr, Expression probe_type, Location l)
1181 ProbeType = probe_type;
1186 public Expression Expr {
1192 protected override Expression DoResolve (ResolveContext ec)
1194 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1195 if (probe_type_expr == null)
1198 expr = expr.Resolve (ec);
1202 if (probe_type_expr.Type.IsStatic) {
1203 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1207 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1208 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1213 if (expr.Type == InternalType.AnonymousMethod) {
1214 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1222 protected abstract string OperatorName { get; }
1224 protected override void CloneTo (CloneContext clonectx, Expression t)
1226 Probe target = (Probe) t;
1228 target.expr = expr.Clone (clonectx);
1229 target.ProbeType = ProbeType.Clone (clonectx);
1235 /// Implementation of the `is' operator.
1237 public class Is : Probe {
1238 Nullable.Unwrap expr_unwrap;
1240 public Is (Expression expr, Expression probe_type, Location l)
1241 : base (expr, probe_type, l)
1245 public override Expression CreateExpressionTree (ResolveContext ec)
1247 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1248 expr.CreateExpressionTree (ec),
1249 new TypeOf (probe_type_expr, loc));
1251 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1254 public override void Emit (EmitContext ec)
1256 if (expr_unwrap != null) {
1257 expr_unwrap.EmitCheck (ec);
1262 ec.Emit (OpCodes.Isinst, probe_type_expr.Type);
1263 ec.Emit (OpCodes.Ldnull);
1264 ec.Emit (OpCodes.Cgt_Un);
1267 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1269 if (expr_unwrap != null) {
1270 expr_unwrap.EmitCheck (ec);
1273 ec.Emit (OpCodes.Isinst, probe_type_expr.Type);
1275 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1278 Expression CreateConstantResult (ResolveContext ec, bool result)
1281 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1282 TypeManager.CSharpName (probe_type_expr.Type));
1284 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1285 TypeManager.CSharpName (probe_type_expr.Type));
1287 return ReducedExpression.Create (new BoolConstant (result, loc).Resolve (ec), this);
1290 protected override Expression DoResolve (ResolveContext ec)
1292 if (base.DoResolve (ec) == null)
1295 TypeSpec d = expr.Type;
1296 bool d_is_nullable = false;
1299 // If E is a method group or the null literal, or if the type of E is a reference
1300 // type or a nullable type and the value of E is null, the result is false
1302 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1303 return CreateConstantResult (ec, false);
1305 if (TypeManager.IsNullableType (d)) {
1306 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1307 if (!ut.IsGenericParameter) {
1309 d_is_nullable = true;
1313 type = TypeManager.bool_type;
1314 eclass = ExprClass.Value;
1315 TypeSpec t = probe_type_expr.Type;
1316 bool t_is_nullable = false;
1317 if (TypeManager.IsNullableType (t)) {
1318 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1319 if (!ut.IsGenericParameter) {
1321 t_is_nullable = true;
1325 if (TypeManager.IsStruct (t)) {
1328 // D and T are the same value types but D can be null
1330 if (d_is_nullable && !t_is_nullable) {
1331 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1336 // The result is true if D and T are the same value types
1338 return CreateConstantResult (ec, true);
1341 var tp = d as TypeParameterSpec;
1343 return ResolveGenericParameter (ec, t, tp);
1346 // An unboxing conversion exists
1348 if (Convert.ExplicitReferenceConversionExists (d, t))
1351 if (TypeManager.IsGenericParameter (t))
1352 return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
1354 if (TypeManager.IsStruct (d)) {
1355 if (Convert.ImplicitBoxingConversion (null, d, t) != null)
1356 return CreateConstantResult (ec, true);
1358 if (TypeManager.IsGenericParameter (d))
1359 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1361 if (TypeManager.ContainsGenericParameters (d))
1364 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1365 Convert.ExplicitReferenceConversionExists (d, t)) {
1371 return CreateConstantResult (ec, false);
1374 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1376 if (t.IsReferenceType) {
1377 if (TypeManager.IsStruct (d))
1378 return CreateConstantResult (ec, false);
1381 if (TypeManager.IsGenericParameter (expr.Type)) {
1382 if (t.IsValueType && expr.Type == t)
1383 return CreateConstantResult (ec, true);
1385 expr = new BoxedCast (expr, d);
1391 protected override string OperatorName {
1392 get { return "is"; }
1397 /// Implementation of the `as' operator.
1399 public class As : Probe {
1401 Expression resolved_type;
1403 public As (Expression expr, Expression probe_type, Location l)
1404 : base (expr, probe_type, l)
1408 public override Expression CreateExpressionTree (ResolveContext ec)
1410 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1411 expr.CreateExpressionTree (ec),
1412 new TypeOf (probe_type_expr, loc));
1414 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1417 public override void Emit (EmitContext ec)
1422 ec.Emit (OpCodes.Isinst, type);
1424 if (TypeManager.IsGenericParameter (type) || TypeManager.IsNullableType (type))
1425 ec.Emit (OpCodes.Unbox_Any, type);
1428 protected override Expression DoResolve (ResolveContext ec)
1430 if (resolved_type == null) {
1431 resolved_type = base.DoResolve (ec);
1433 if (resolved_type == null)
1437 type = probe_type_expr.Type;
1438 eclass = ExprClass.Value;
1439 TypeSpec etype = expr.Type;
1441 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1442 if (TypeManager.IsGenericParameter (type)) {
1443 ec.Report.Error (413, loc,
1444 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1445 probe_type_expr.GetSignatureForError ());
1447 ec.Report.Error (77, loc,
1448 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1449 TypeManager.CSharpName (type));
1454 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1455 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1458 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1465 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1466 if (TypeManager.IsGenericParameter (etype))
1467 expr = new BoxedCast (expr, etype);
1473 if (TypeManager.ContainsGenericParameters (etype) ||
1474 TypeManager.ContainsGenericParameters (type)) {
1475 expr = new BoxedCast (expr, etype);
1480 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1481 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1486 protected override string OperatorName {
1487 get { return "as"; }
1492 // This represents a typecast in the source language.
1494 public class Cast : ShimExpression {
1495 Expression target_type;
1497 public Cast (Expression cast_type, Expression expr, Location loc)
1500 this.target_type = cast_type;
1504 public Expression TargetType {
1505 get { return target_type; }
1508 protected override Expression DoResolve (ResolveContext ec)
1510 expr = expr.Resolve (ec);
1514 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1520 if (type.IsStatic) {
1521 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1525 eclass = ExprClass.Value;
1527 Constant c = expr as Constant;
1529 c = c.TryReduce (ec, type, loc);
1534 if (type.IsPointer && !ec.IsUnsafe) {
1535 UnsafeError (ec, loc);
1536 } else if (expr.Type == InternalType.Dynamic) {
1537 Arguments arg = new Arguments (1);
1538 arg.Add (new Argument (expr));
1539 return new DynamicConversion (type, CSharpBinderFlags.ConvertExplicit, arg, loc).Resolve (ec);
1542 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1544 return EmptyCast.Create (res, type);
1549 protected override void CloneTo (CloneContext clonectx, Expression t)
1551 Cast target = (Cast) t;
1553 target.target_type = target_type.Clone (clonectx);
1554 target.expr = expr.Clone (clonectx);
1558 public class ImplicitCast : ShimExpression
1562 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1565 this.loc = expr.Location;
1567 this.arrayAccess = arrayAccess;
1570 protected override Expression DoResolve (ResolveContext ec)
1572 expr = expr.Resolve (ec);
1577 expr = ConvertExpressionToArrayIndex (ec, expr);
1579 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1586 // C# 2.0 Default value expression
1588 public class DefaultValueExpression : Expression
1592 public DefaultValueExpression (Expression expr, Location loc)
1598 public override Expression CreateExpressionTree (ResolveContext ec)
1600 Arguments args = new Arguments (2);
1601 args.Add (new Argument (this));
1602 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1603 return CreateExpressionFactoryCall (ec, "Constant", args);
1606 protected override Expression DoResolve (ResolveContext ec)
1608 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1614 if (type.IsStatic) {
1615 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1619 return new NullLiteral (Location).ConvertImplicitly (ec, type);
1621 if (TypeManager.IsReferenceType (type))
1622 return new NullConstant (type, loc);
1624 Constant c = New.Constantify (type);
1626 return c.Resolve (ec);
1628 eclass = ExprClass.Variable;
1632 public override void Emit (EmitContext ec)
1634 LocalTemporary temp_storage = new LocalTemporary(type);
1636 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1637 ec.Emit(OpCodes.Initobj, type);
1638 temp_storage.Emit(ec);
1641 protected override void CloneTo (CloneContext clonectx, Expression t)
1643 DefaultValueExpression target = (DefaultValueExpression) t;
1645 target.expr = expr.Clone (clonectx);
1650 /// Binary operators
1652 public class Binary : Expression, IDynamicBinder
1654 protected class PredefinedOperator {
1655 protected readonly TypeSpec left;
1656 protected readonly TypeSpec right;
1657 public readonly Operator OperatorsMask;
1658 public TypeSpec ReturnType;
1660 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1661 : this (ltype, rtype, op_mask, ltype)
1665 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1666 : this (type, type, op_mask, return_type)
1670 public PredefinedOperator (TypeSpec type, Operator op_mask)
1671 : this (type, type, op_mask, type)
1675 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1677 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1678 throw new InternalErrorException ("Only masked values can be used");
1682 this.OperatorsMask = op_mask;
1683 this.ReturnType = return_type;
1686 public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1688 b.type = ReturnType;
1690 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1691 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1694 // A user operators does not support multiple user conversions, but decimal type
1695 // is considered to be predefined type therefore we apply predefined operators rules
1696 // and then look for decimal user-operator implementation
1698 if (left == TypeManager.decimal_type)
1699 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1701 var c = b.right as Constant;
1703 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr || b.oper == Operator.Subtraction))
1704 return ReducedExpression.Create (b.left, b).Resolve (ec);
1705 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
1706 return ReducedExpression.Create (b.left, b).Resolve (ec);
1710 c = b.left as Constant;
1712 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr))
1713 return ReducedExpression.Create (b.right, b).Resolve (ec);
1714 if (b.oper == Operator.Multiply && c.IsOneInteger)
1715 return ReducedExpression.Create (b.right, b).Resolve (ec);
1722 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
1725 // We are dealing with primitive types only
1727 return left == ltype && ltype == rtype;
1730 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1732 if (TypeManager.IsEqual (left, lexpr.Type) &&
1733 TypeManager.IsEqual (right, rexpr.Type))
1736 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1737 Convert.ImplicitConversionExists (ec, rexpr, right);
1740 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1743 if (left != null && best_operator.left != null) {
1744 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1748 // When second arguments are same as the first one, the result is same
1750 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1751 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1754 if (result == 0 || result > 2)
1757 return result == 1 ? best_operator : this;
1761 class PredefinedStringOperator : PredefinedOperator {
1762 public PredefinedStringOperator (TypeSpec type, Operator op_mask)
1763 : base (type, op_mask, type)
1765 ReturnType = TypeManager.string_type;
1768 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1769 : base (ltype, rtype, op_mask)
1771 ReturnType = TypeManager.string_type;
1774 public override Expression ConvertResult (ResolveContext ec, Binary b)
1777 // Use original expression for nullable arguments
1779 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1781 b.left = unwrap.Original;
1783 unwrap = b.right as Nullable.Unwrap;
1785 b.right = unwrap.Original;
1787 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1788 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1791 // Start a new concat expression using converted expression
1793 return StringConcat.Create (ec, b.left, b.right, b.loc);
1797 class PredefinedShiftOperator : PredefinedOperator {
1798 public PredefinedShiftOperator (TypeSpec ltype, Operator op_mask) :
1799 base (ltype, TypeManager.int32_type, op_mask)
1803 public override Expression ConvertResult (ResolveContext ec, Binary b)
1805 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1807 Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, TypeManager.int32_type, b.right.Location);
1809 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1812 // b = b.left >> b.right & (0x1f|0x3f)
1814 b.right = new Binary (Operator.BitwiseAnd,
1815 b.right, new IntConstant (right_mask, b.right.Location), b.loc).Resolve (ec);
1818 // Expression tree representation does not use & mask
1820 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1821 b.type = ReturnType;
1824 // Optimize shift by 0
1826 var c = b.right as Constant;
1827 if (c != null && c.IsDefaultValue)
1828 return ReducedExpression.Create (b.left, b).Resolve (ec);
1834 class PredefinedPointerOperator : PredefinedOperator {
1835 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1836 : base (ltype, rtype, op_mask)
1840 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
1841 : base (ltype, rtype, op_mask, retType)
1845 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1846 : base (type, op_mask, return_type)
1850 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1853 if (!lexpr.Type.IsPointer)
1856 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1860 if (right == null) {
1861 if (!rexpr.Type.IsPointer)
1864 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1871 public override Expression ConvertResult (ResolveContext ec, Binary b)
1874 b.left = EmptyCast.Create (b.left, left);
1875 } else if (right != null) {
1876 b.right = EmptyCast.Create (b.right, right);
1879 TypeSpec r_type = ReturnType;
1880 Expression left_arg, right_arg;
1881 if (r_type == null) {
1884 right_arg = b.right;
1885 r_type = b.left.Type;
1889 r_type = b.right.Type;
1893 right_arg = b.right;
1896 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1901 public enum Operator {
1902 Multiply = 0 | ArithmeticMask,
1903 Division = 1 | ArithmeticMask,
1904 Modulus = 2 | ArithmeticMask,
1905 Addition = 3 | ArithmeticMask | AdditionMask,
1906 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1908 LeftShift = 5 | ShiftMask,
1909 RightShift = 6 | ShiftMask,
1911 LessThan = 7 | ComparisonMask | RelationalMask,
1912 GreaterThan = 8 | ComparisonMask | RelationalMask,
1913 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1914 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1915 Equality = 11 | ComparisonMask | EqualityMask,
1916 Inequality = 12 | ComparisonMask | EqualityMask,
1918 BitwiseAnd = 13 | BitwiseMask,
1919 ExclusiveOr = 14 | BitwiseMask,
1920 BitwiseOr = 15 | BitwiseMask,
1922 LogicalAnd = 16 | LogicalMask,
1923 LogicalOr = 17 | LogicalMask,
1928 ValuesOnlyMask = ArithmeticMask - 1,
1929 ArithmeticMask = 1 << 5,
1931 ComparisonMask = 1 << 7,
1932 EqualityMask = 1 << 8,
1933 BitwiseMask = 1 << 9,
1934 LogicalMask = 1 << 10,
1935 AdditionMask = 1 << 11,
1936 SubtractionMask = 1 << 12,
1937 RelationalMask = 1 << 13
1940 readonly Operator oper;
1941 protected Expression left, right;
1942 readonly bool is_compound;
1943 Expression enum_conversion;
1945 static PredefinedOperator[] standard_operators;
1946 static PredefinedOperator[] pointer_operators;
1948 public Binary (Operator oper, Expression left, Expression right, bool isCompound, Location loc)
1949 : this (oper, left, right, loc)
1951 this.is_compound = isCompound;
1954 public Binary (Operator oper, Expression left, Expression right, Location loc)
1962 public Operator Oper {
1969 /// Returns a stringified representation of the Operator
1971 string OperName (Operator oper)
1975 case Operator.Multiply:
1978 case Operator.Division:
1981 case Operator.Modulus:
1984 case Operator.Addition:
1987 case Operator.Subtraction:
1990 case Operator.LeftShift:
1993 case Operator.RightShift:
1996 case Operator.LessThan:
1999 case Operator.GreaterThan:
2002 case Operator.LessThanOrEqual:
2005 case Operator.GreaterThanOrEqual:
2008 case Operator.Equality:
2011 case Operator.Inequality:
2014 case Operator.BitwiseAnd:
2017 case Operator.BitwiseOr:
2020 case Operator.ExclusiveOr:
2023 case Operator.LogicalOr:
2026 case Operator.LogicalAnd:
2030 s = oper.ToString ();
2040 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2042 new Binary (oper, left, right, loc).Error_OperatorCannotBeApplied (ec, left, right);
2045 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2048 l = TypeManager.CSharpName (left.Type);
2049 r = TypeManager.CSharpName (right.Type);
2051 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2055 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2057 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2061 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2063 string GetOperatorExpressionTypeName ()
2066 case Operator.Addition:
2067 return is_compound ? "AddAssign" : "Add";
2068 case Operator.BitwiseAnd:
2069 return is_compound ? "AndAssign" : "And";
2070 case Operator.BitwiseOr:
2071 return is_compound ? "OrAssign" : "Or";
2072 case Operator.Division:
2073 return is_compound ? "DivideAssign" : "Divide";
2074 case Operator.ExclusiveOr:
2075 return is_compound ? "ExclusiveOrAssign" : "ExclusiveOr";
2076 case Operator.Equality:
2078 case Operator.GreaterThan:
2079 return "GreaterThan";
2080 case Operator.GreaterThanOrEqual:
2081 return "GreaterThanOrEqual";
2082 case Operator.Inequality:
2084 case Operator.LeftShift:
2085 return is_compound ? "LeftShiftAssign" : "LeftShift";
2086 case Operator.LessThan:
2088 case Operator.LessThanOrEqual:
2089 return "LessThanOrEqual";
2090 case Operator.LogicalAnd:
2092 case Operator.LogicalOr:
2094 case Operator.Modulus:
2095 return is_compound ? "ModuloAssign" : "Modulo";
2096 case Operator.Multiply:
2097 return is_compound ? "MultiplyAssign" : "Multiply";
2098 case Operator.RightShift:
2099 return is_compound ? "RightShiftAssign" : "RightShift";
2100 case Operator.Subtraction:
2101 return is_compound ? "SubtractAssign" : "Subtract";
2103 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2107 static string GetOperatorMetadataName (Operator op)
2109 CSharp.Operator.OpType op_type;
2111 case Operator.Addition:
2112 op_type = CSharp.Operator.OpType.Addition; break;
2113 case Operator.BitwiseAnd:
2114 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2115 case Operator.BitwiseOr:
2116 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2117 case Operator.Division:
2118 op_type = CSharp.Operator.OpType.Division; break;
2119 case Operator.Equality:
2120 op_type = CSharp.Operator.OpType.Equality; break;
2121 case Operator.ExclusiveOr:
2122 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2123 case Operator.GreaterThan:
2124 op_type = CSharp.Operator.OpType.GreaterThan; break;
2125 case Operator.GreaterThanOrEqual:
2126 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2127 case Operator.Inequality:
2128 op_type = CSharp.Operator.OpType.Inequality; break;
2129 case Operator.LeftShift:
2130 op_type = CSharp.Operator.OpType.LeftShift; break;
2131 case Operator.LessThan:
2132 op_type = CSharp.Operator.OpType.LessThan; break;
2133 case Operator.LessThanOrEqual:
2134 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2135 case Operator.Modulus:
2136 op_type = CSharp.Operator.OpType.Modulus; break;
2137 case Operator.Multiply:
2138 op_type = CSharp.Operator.OpType.Multiply; break;
2139 case Operator.RightShift:
2140 op_type = CSharp.Operator.OpType.RightShift; break;
2141 case Operator.Subtraction:
2142 op_type = CSharp.Operator.OpType.Subtraction; break;
2144 throw new InternalErrorException (op.ToString ());
2147 return CSharp.Operator.GetMetadataName (op_type);
2150 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l)
2155 case Operator.Multiply:
2156 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2157 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2158 opcode = OpCodes.Mul_Ovf;
2159 else if (!IsFloat (l))
2160 opcode = OpCodes.Mul_Ovf_Un;
2162 opcode = OpCodes.Mul;
2164 opcode = OpCodes.Mul;
2168 case Operator.Division:
2170 opcode = OpCodes.Div_Un;
2172 opcode = OpCodes.Div;
2175 case Operator.Modulus:
2177 opcode = OpCodes.Rem_Un;
2179 opcode = OpCodes.Rem;
2182 case Operator.Addition:
2183 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2184 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2185 opcode = OpCodes.Add_Ovf;
2186 else if (!IsFloat (l))
2187 opcode = OpCodes.Add_Ovf_Un;
2189 opcode = OpCodes.Add;
2191 opcode = OpCodes.Add;
2194 case Operator.Subtraction:
2195 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2196 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2197 opcode = OpCodes.Sub_Ovf;
2198 else if (!IsFloat (l))
2199 opcode = OpCodes.Sub_Ovf_Un;
2201 opcode = OpCodes.Sub;
2203 opcode = OpCodes.Sub;
2206 case Operator.RightShift:
2208 opcode = OpCodes.Shr_Un;
2210 opcode = OpCodes.Shr;
2213 case Operator.LeftShift:
2214 opcode = OpCodes.Shl;
2217 case Operator.Equality:
2218 opcode = OpCodes.Ceq;
2221 case Operator.Inequality:
2222 ec.Emit (OpCodes.Ceq);
2223 ec.Emit (OpCodes.Ldc_I4_0);
2225 opcode = OpCodes.Ceq;
2228 case Operator.LessThan:
2230 opcode = OpCodes.Clt_Un;
2232 opcode = OpCodes.Clt;
2235 case Operator.GreaterThan:
2237 opcode = OpCodes.Cgt_Un;
2239 opcode = OpCodes.Cgt;
2242 case Operator.LessThanOrEqual:
2243 if (IsUnsigned (l) || IsFloat (l))
2244 ec.Emit (OpCodes.Cgt_Un);
2246 ec.Emit (OpCodes.Cgt);
2247 ec.Emit (OpCodes.Ldc_I4_0);
2249 opcode = OpCodes.Ceq;
2252 case Operator.GreaterThanOrEqual:
2253 if (IsUnsigned (l) || IsFloat (l))
2254 ec.Emit (OpCodes.Clt_Un);
2256 ec.Emit (OpCodes.Clt);
2258 ec.Emit (OpCodes.Ldc_I4_0);
2260 opcode = OpCodes.Ceq;
2263 case Operator.BitwiseOr:
2264 opcode = OpCodes.Or;
2267 case Operator.BitwiseAnd:
2268 opcode = OpCodes.And;
2271 case Operator.ExclusiveOr:
2272 opcode = OpCodes.Xor;
2276 throw new InternalErrorException (oper.ToString ());
2282 static bool IsUnsigned (TypeSpec t)
2287 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2288 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2291 static bool IsFloat (TypeSpec t)
2293 return t == TypeManager.float_type || t == TypeManager.double_type;
2296 public static void Reset ()
2298 pointer_operators = standard_operators = null;
2301 Expression ResolveOperator (ResolveContext ec)
2303 TypeSpec l = left.Type;
2304 TypeSpec r = right.Type;
2306 bool primitives_only = false;
2308 if (standard_operators == null)
2309 CreateStandardOperatorsTable ();
2312 // Handles predefined primitive types
2314 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2315 if ((oper & Operator.ShiftMask) == 0) {
2316 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2319 primitives_only = true;
2323 if (l.IsPointer || r.IsPointer)
2324 return ResolveOperatorPointer (ec, l, r);
2327 bool lenum = TypeManager.IsEnumType (l);
2328 bool renum = TypeManager.IsEnumType (r);
2329 if (lenum || renum) {
2330 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2332 // TODO: Can this be ambiguous
2338 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2339 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2341 expr = ResolveOperatorDelegate (ec, l, r);
2343 // TODO: Can this be ambiguous
2349 expr = ResolveUserOperator (ec, l, r);
2353 // Predefined reference types equality
2354 if ((oper & Operator.EqualityMask) != 0) {
2355 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2361 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2364 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2365 // if 'left' is not an enumeration constant, create one from the type of 'right'
2366 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2369 case Operator.BitwiseOr:
2370 case Operator.BitwiseAnd:
2371 case Operator.ExclusiveOr:
2372 case Operator.Equality:
2373 case Operator.Inequality:
2374 case Operator.LessThan:
2375 case Operator.LessThanOrEqual:
2376 case Operator.GreaterThan:
2377 case Operator.GreaterThanOrEqual:
2378 if (TypeManager.IsEnumType (left.Type))
2381 if (left.IsZeroInteger)
2382 return left.TryReduce (ec, right.Type, loc);
2386 case Operator.Addition:
2387 case Operator.Subtraction:
2390 case Operator.Multiply:
2391 case Operator.Division:
2392 case Operator.Modulus:
2393 case Operator.LeftShift:
2394 case Operator.RightShift:
2395 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2399 Error_OperatorCannotBeApplied (ec, this.left, this.right);
2404 // The `|' operator used on types which were extended is dangerous
2406 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2408 OpcodeCast lcast = left as OpcodeCast;
2409 if (lcast != null) {
2410 if (IsUnsigned (lcast.UnderlyingType))
2414 OpcodeCast rcast = right as OpcodeCast;
2415 if (rcast != null) {
2416 if (IsUnsigned (rcast.UnderlyingType))
2420 if (lcast == null && rcast == null)
2423 // FIXME: consider constants
2425 ec.Report.Warning (675, 3, loc,
2426 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2427 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2430 static void CreatePointerOperatorsTable ()
2432 var temp = new List<PredefinedPointerOperator> ();
2435 // Pointer arithmetic:
2437 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2438 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2439 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2440 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2442 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2443 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2444 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2445 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2448 // T* operator + (int y, T* x);
2449 // T* operator + (uint y, T *x);
2450 // T* operator + (long y, T *x);
2451 // T* operator + (ulong y, T *x);
2453 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2454 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2455 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2456 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2459 // long operator - (T* x, T *y)
2461 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2463 pointer_operators = temp.ToArray ();
2466 static void CreateStandardOperatorsTable ()
2468 var temp = new List<PredefinedOperator> ();
2469 TypeSpec bool_type = TypeManager.bool_type;
2471 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2472 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2473 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2474 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2475 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2476 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2477 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2479 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2480 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2481 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2482 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2483 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2484 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2485 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2487 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2489 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2490 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2491 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2493 temp.Add (new PredefinedOperator (bool_type,
2494 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2496 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2497 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2498 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2499 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2501 standard_operators = temp.ToArray ();
2505 // Rules used during binary numeric promotion
2507 static bool DoNumericPromotion (ResolveContext rc, ref Expression prim_expr, ref Expression second_expr, TypeSpec type)
2512 Constant c = prim_expr as Constant;
2514 temp = c.ConvertImplicitly (rc, type);
2521 if (type == TypeManager.uint32_type) {
2522 etype = prim_expr.Type;
2523 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2524 type = TypeManager.int64_type;
2526 if (type != second_expr.Type) {
2527 c = second_expr as Constant;
2529 temp = c.ConvertImplicitly (rc, type);
2531 temp = Convert.ImplicitNumericConversion (second_expr, type);
2537 } else if (type == TypeManager.uint64_type) {
2539 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2541 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2542 type == TypeManager.short_type || type == TypeManager.sbyte_type)
2546 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2555 // 7.2.6.2 Binary numeric promotions
2557 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2559 TypeSpec ltype = left.Type;
2560 TypeSpec rtype = right.Type;
2563 foreach (TypeSpec t in ConstantFold.BinaryPromotionsTypes) {
2565 return t == rtype || DoNumericPromotion (ec, ref right, ref left, t);
2568 return t == ltype || DoNumericPromotion (ec, ref left, ref right, t);
2571 TypeSpec int32 = TypeManager.int32_type;
2572 if (ltype != int32) {
2573 Constant c = left as Constant;
2575 temp = c.ConvertImplicitly (ec, int32);
2577 temp = Convert.ImplicitNumericConversion (left, int32);
2584 if (rtype != int32) {
2585 Constant c = right as Constant;
2587 temp = c.ConvertImplicitly (ec, int32);
2589 temp = Convert.ImplicitNumericConversion (right, int32);
2599 protected override Expression DoResolve (ResolveContext ec)
2604 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2605 left = ((ParenthesizedExpression) left).Expr;
2606 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2610 if (left.eclass == ExprClass.Type) {
2611 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2615 left = left.Resolve (ec);
2620 Constant lc = left as Constant;
2622 if (lc != null && lc.Type == TypeManager.bool_type &&
2623 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2624 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2626 // FIXME: resolve right expression as unreachable
2627 // right.Resolve (ec);
2629 ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2633 right = right.Resolve (ec);
2637 eclass = ExprClass.Value;
2638 Constant rc = right as Constant;
2640 // The conversion rules are ignored in enum context but why
2641 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2642 lc = EnumLiftUp (ec, lc, rc, loc);
2644 rc = EnumLiftUp (ec, rc, lc, loc);
2647 if (rc != null && lc != null) {
2648 int prev_e = ec.Report.Errors;
2649 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
2653 if (e != null || ec.Report.Errors != prev_e)
2657 // Comparison warnings
2658 if ((oper & Operator.ComparisonMask) != 0) {
2659 if (left.Equals (right)) {
2660 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2662 CheckUselessComparison (ec, lc, right.Type);
2663 CheckUselessComparison (ec, rc, left.Type);
2666 if (left.Type == InternalType.Dynamic || right.Type == InternalType.Dynamic) {
2667 Arguments args = new Arguments (2);
2668 args.Add (new Argument (left));
2669 args.Add (new Argument (right));
2670 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
2673 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2674 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2675 (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
2676 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2677 (TypeManager.IsValueType (right.Type) && left is NullLiteral)))
2678 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2680 return DoResolveCore (ec, left, right);
2683 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
2685 Expression expr = ResolveOperator (ec);
2687 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
2689 if (left == null || right == null)
2690 throw new InternalErrorException ("Invalid conversion");
2692 if (oper == Operator.BitwiseOr)
2693 CheckBitwiseOrOnSignExtended (ec);
2698 public override SLE.Expression MakeExpression (BuilderContext ctx)
2700 var le = left.MakeExpression (ctx);
2701 var re = right.MakeExpression (ctx);
2702 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
2705 case Operator.Addition:
2706 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
2707 case Operator.BitwiseAnd:
2708 return SLE.Expression.And (le, re);
2709 case Operator.BitwiseOr:
2710 return SLE.Expression.Or (le, re);
2711 case Operator.Division:
2712 return SLE.Expression.Divide (le, re);
2713 case Operator.Equality:
2714 return SLE.Expression.Equal (le, re);
2715 case Operator.ExclusiveOr:
2716 return SLE.Expression.ExclusiveOr (le, re);
2717 case Operator.GreaterThan:
2718 return SLE.Expression.GreaterThan (le, re);
2719 case Operator.GreaterThanOrEqual:
2720 return SLE.Expression.GreaterThanOrEqual (le, re);
2721 case Operator.Inequality:
2722 return SLE.Expression.NotEqual (le, re);
2723 case Operator.LeftShift:
2724 return SLE.Expression.LeftShift (le, re);
2725 case Operator.LessThan:
2726 return SLE.Expression.LessThan (le, re);
2727 case Operator.LessThanOrEqual:
2728 return SLE.Expression.LessThanOrEqual (le, re);
2729 case Operator.LogicalAnd:
2730 return SLE.Expression.AndAlso (le, re);
2731 case Operator.LogicalOr:
2732 return SLE.Expression.OrElse (le, re);
2733 case Operator.Modulus:
2734 return SLE.Expression.Modulo (le, re);
2735 case Operator.Multiply:
2736 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
2737 case Operator.RightShift:
2738 return SLE.Expression.RightShift (le, re);
2739 case Operator.Subtraction:
2740 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
2742 throw new NotImplementedException (oper.ToString ());
2747 // D operator + (D x, D y)
2748 // D operator - (D x, D y)
2749 // bool operator == (D x, D y)
2750 // bool operator != (D x, D y)
2752 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
2754 bool is_equality = (oper & Operator.EqualityMask) != 0;
2755 if (!TypeManager.IsEqual (l, r) && !TypeSpecComparer.Variant.IsEqual (r, l)) {
2757 if (right.eclass == ExprClass.MethodGroup || (r == InternalType.AnonymousMethod && !is_equality)) {
2758 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2763 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod && !is_equality)) {
2764 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2775 // Resolve delegate equality as a user operator
2778 return ResolveUserOperator (ec, l, r);
2781 Arguments args = new Arguments (2);
2782 args.Add (new Argument (left));
2783 args.Add (new Argument (right));
2785 if (oper == Operator.Addition) {
2786 if (TypeManager.delegate_combine_delegate_delegate == null) {
2787 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2788 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2791 method = TypeManager.delegate_combine_delegate_delegate;
2793 if (TypeManager.delegate_remove_delegate_delegate == null) {
2794 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2795 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2798 method = TypeManager.delegate_remove_delegate_delegate;
2802 return new EmptyExpression (TypeManager.decimal_type);
2804 MethodGroupExpr mg = new MethodGroupExpr (method, TypeManager.delegate_type, loc);
2805 mg = mg.OverloadResolve (ec, ref args, false, loc);
2807 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2811 // Enumeration operators
2813 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
2816 // bool operator == (E x, E y);
2817 // bool operator != (E x, E y);
2818 // bool operator < (E x, E y);
2819 // bool operator > (E x, E y);
2820 // bool operator <= (E x, E y);
2821 // bool operator >= (E x, E y);
2823 // E operator & (E x, E y);
2824 // E operator | (E x, E y);
2825 // E operator ^ (E x, E y);
2827 // U operator - (E e, E f)
2828 // E operator - (E e, U x)
2830 // E operator + (U x, E e)
2831 // E operator + (E e, U x)
2833 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2834 (oper == Operator.Subtraction && lenum) ||
2835 (oper == Operator.Addition && (lenum != renum || type != null)))) // type != null for lifted null
2838 Expression ltemp = left;
2839 Expression rtemp = right;
2840 TypeSpec underlying_type;
2843 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2845 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2851 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2859 if (TypeManager.IsEqual (ltype, rtype)) {
2860 underlying_type = EnumSpec.GetUnderlyingType (ltype);
2862 if (left is Constant)
2863 left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
2865 left = EmptyCast.Create (left, underlying_type);
2867 if (right is Constant)
2868 right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
2870 right = EmptyCast.Create (right, underlying_type);
2872 underlying_type = EnumSpec.GetUnderlyingType (ltype);
2874 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2875 Constant c = right as Constant;
2876 if (c == null || !c.IsDefaultValue)
2879 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2882 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2885 if (left is Constant)
2886 left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
2888 left = EmptyCast.Create (left, underlying_type);
2891 underlying_type = EnumSpec.GetUnderlyingType (rtype);
2893 if (oper != Operator.Addition) {
2894 Constant c = left as Constant;
2895 if (c == null || !c.IsDefaultValue)
2898 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2901 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2904 if (right is Constant)
2905 right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
2907 right = EmptyCast.Create (right, underlying_type);
2914 // C# specification uses explicit cast syntax which means binary promotion
2915 // should happen, however it seems that csc does not do that
2917 if (!DoBinaryOperatorPromotion (ec)) {
2923 TypeSpec res_type = null;
2924 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2925 TypeSpec promoted_type = lenum ? left.Type : right.Type;
2926 enum_conversion = Convert.ExplicitNumericConversion (
2927 new EmptyExpression (promoted_type), underlying_type);
2929 if (oper == Operator.Subtraction && renum && lenum)
2930 res_type = underlying_type;
2931 else if (oper == Operator.Addition && renum)
2937 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2938 if (!is_compound || expr == null)
2946 // If the return type of the selected operator is implicitly convertible to the type of x
2948 if (Convert.ImplicitConversionExists (ec, expr, ltype))
2952 // Otherwise, if the selected operator is a predefined operator, if the return type of the
2953 // selected operator is explicitly convertible to the type of x, and if y is implicitly
2954 // convertible to the type of x or the operator is a shift operator, then the operation
2955 // is evaluated as x = (T)(x op y), where T is the type of x
2957 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
2961 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
2968 // 7.9.6 Reference type equality operators
2970 Binary ResolveOperatorEqualityRerefence (ResolveContext ec, TypeSpec l, TypeSpec r)
2973 // operator != (object a, object b)
2974 // operator == (object a, object b)
2977 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2979 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2982 type = TypeManager.bool_type;
2984 var lgen = l as TypeParameterSpec;
2987 if (l is InternalType)
2992 // Only allow to compare same reference type parameter
2994 if (TypeManager.IsReferenceType (l)) {
2995 left = new BoxedCast (left, TypeManager.object_type);
2996 right = new BoxedCast (right, TypeManager.object_type);
3003 if (TypeManager.IsValueType (l))
3009 var rgen = r as TypeParameterSpec;
3012 // a, Both operands are reference-type values or the value null
3013 // b, One operand is a value of type T where T is a type-parameter and
3014 // the other operand is the value null. Furthermore T does not have the
3015 // value type constrain
3017 if (left is NullLiteral || right is NullLiteral) {
3019 if (lgen.HasSpecialStruct)
3022 left = new BoxedCast (left, TypeManager.object_type);
3027 if (rgen.HasSpecialStruct)
3030 right = new BoxedCast (right, TypeManager.object_type);
3036 // An interface is converted to the object before the
3037 // standard conversion is applied. It's not clear from the
3038 // standard but it looks like it works like that.
3041 if (!TypeManager.IsReferenceType (l))
3044 l = TypeManager.object_type;
3045 left = new BoxedCast (left, l);
3046 } else if (l.IsInterface) {
3047 l = TypeManager.object_type;
3048 } else if (TypeManager.IsStruct (l)) {
3053 if (!TypeManager.IsReferenceType (r))
3056 r = TypeManager.object_type;
3057 right = new BoxedCast (right, r);
3058 } else if (r.IsInterface) {
3059 r = TypeManager.object_type;
3060 } else if (TypeManager.IsStruct (r)) {
3065 const string ref_comparison = "Possible unintended reference comparison. " +
3066 "Consider casting the {0} side of the expression to `string' to compare the values";
3069 // A standard implicit conversion exists from the type of either
3070 // operand to the type of the other operand
3072 if (Convert.ImplicitReferenceConversionExists (left, r)) {
3073 if (l == TypeManager.string_type)
3074 ec.Report.Warning (253, 2, loc, ref_comparison, "right");
3079 if (Convert.ImplicitReferenceConversionExists (right, l)) {
3080 if (r == TypeManager.string_type)
3081 ec.Report.Warning (252, 2, loc, ref_comparison, "left");
3090 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3093 // bool operator == (void* x, void* y);
3094 // bool operator != (void* x, void* y);
3095 // bool operator < (void* x, void* y);
3096 // bool operator > (void* x, void* y);
3097 // bool operator <= (void* x, void* y);
3098 // bool operator >= (void* x, void* y);
3100 if ((oper & Operator.ComparisonMask) != 0) {
3103 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3110 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3116 type = TypeManager.bool_type;
3120 if (pointer_operators == null)
3121 CreatePointerOperatorsTable ();
3123 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
3127 // Build-in operators method overloading
3129 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, TypeSpec enum_type)
3131 PredefinedOperator best_operator = null;
3132 TypeSpec l = left.Type;
3133 TypeSpec r = right.Type;
3134 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3136 foreach (PredefinedOperator po in operators) {
3137 if ((po.OperatorsMask & oper_mask) == 0)
3140 if (primitives_only) {
3141 if (!po.IsPrimitiveApplicable (l, r))
3144 if (!po.IsApplicable (ec, left, right))
3148 if (best_operator == null) {
3150 if (primitives_only)
3156 best_operator = po.ResolveBetterOperator (ec, best_operator);
3158 if (best_operator == null) {
3159 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3160 OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
3167 if (best_operator == null)
3170 Expression expr = best_operator.ConvertResult (ec, this);
3173 // Optimize &/&& constant expressions with 0 value
3175 if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
3176 Constant rc = right as Constant;
3177 Constant lc = left as Constant;
3178 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
3180 // The result is a constant with side-effect
3182 Constant side_effect = rc == null ?
3183 new SideEffectConstant (lc, right, loc) :
3184 new SideEffectConstant (rc, left, loc);
3186 return ReducedExpression.Create (side_effect.Resolve (ec), expr);
3190 if (enum_type == null)
3194 // HACK: required by enum_conversion
3196 expr.Type = enum_type;
3197 return EmptyCast.Create (expr, enum_type);
3201 // Performs user-operator overloading
3203 protected virtual Expression ResolveUserOperator (ResolveContext ec, TypeSpec l, TypeSpec r)
3206 if (oper == Operator.LogicalAnd)
3207 user_oper = Operator.BitwiseAnd;
3208 else if (oper == Operator.LogicalOr)
3209 user_oper = Operator.BitwiseOr;
3213 string op = GetOperatorMetadataName (user_oper);
3215 MethodGroupExpr left_operators = MethodLookup (ec.Compiler, ec.CurrentType, l, MemberKind.Operator, op, 0, loc);
3216 MethodGroupExpr right_operators = null;
3218 if (!TypeManager.IsEqual (r, l)) {
3219 right_operators = MethodLookup (ec.Compiler, ec.CurrentType, r, MemberKind.Operator, op, 0, loc);
3220 if (right_operators == null && left_operators == null)
3222 } else if (left_operators == null) {
3226 Arguments args = new Arguments (2);
3227 Argument larg = new Argument (left);
3229 Argument rarg = new Argument (right);
3232 MethodGroupExpr union;
3235 // User-defined operator implementations always take precedence
3236 // over predefined operator implementations
3238 if (left_operators != null && right_operators != null) {
3239 if (IsPredefinedUserOperator (l, user_oper)) {
3240 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3242 union = left_operators;
3243 } else if (IsPredefinedUserOperator (r, user_oper)) {
3244 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3246 union = right_operators;
3248 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3250 } else if (left_operators != null) {
3251 union = left_operators;
3253 union = right_operators;
3256 union = union.OverloadResolve (ec, ref args, true, loc);
3260 Expression oper_expr;
3262 // TODO: CreateExpressionTree is allocated every time
3263 if (user_oper != oper) {
3264 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3265 oper == Operator.LogicalAnd, loc).Resolve (ec);
3267 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3270 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3271 // and not invoke user operator
3273 if ((oper & Operator.EqualityMask) != 0) {
3274 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3275 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3276 type = TypeManager.bool_type;
3277 if (left is NullLiteral || right is NullLiteral)
3278 oper_expr = ReducedExpression.Create (this, oper_expr);
3279 } else if (l != r) {
3280 var mi = union.BestCandidate;
3283 // Two System.Delegate(s) are never equal
3285 if (mi.DeclaringType == TypeManager.multicast_delegate_type)
3296 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3301 private void CheckUselessComparison (ResolveContext ec, Constant c, TypeSpec type)
3303 if (c == null || !IsTypeIntegral (type)
3304 || c is StringConstant
3305 || c is BoolConstant
3306 || c is FloatConstant
3307 || c is DoubleConstant
3308 || c is DecimalConstant
3314 if (c is ULongConstant) {
3315 ulong uvalue = ((ULongConstant) c).Value;
3316 if (uvalue > long.MaxValue) {
3317 if (type == TypeManager.byte_type ||
3318 type == TypeManager.sbyte_type ||
3319 type == TypeManager.short_type ||
3320 type == TypeManager.ushort_type ||
3321 type == TypeManager.int32_type ||
3322 type == TypeManager.uint32_type ||
3323 type == TypeManager.int64_type ||
3324 type == TypeManager.char_type)
3325 WarnUselessComparison (ec, type);
3328 value = (long) uvalue;
3330 else if (c is ByteConstant)
3331 value = ((ByteConstant) c).Value;
3332 else if (c is SByteConstant)
3333 value = ((SByteConstant) c).Value;
3334 else if (c is ShortConstant)
3335 value = ((ShortConstant) c).Value;
3336 else if (c is UShortConstant)
3337 value = ((UShortConstant) c).Value;
3338 else if (c is IntConstant)
3339 value = ((IntConstant) c).Value;
3340 else if (c is UIntConstant)
3341 value = ((UIntConstant) c).Value;
3342 else if (c is LongConstant)
3343 value = ((LongConstant) c).Value;
3344 else if (c is CharConstant)
3345 value = ((CharConstant)c).Value;
3350 if (IsValueOutOfRange (value, type))
3351 WarnUselessComparison (ec, type);
3354 static bool IsValueOutOfRange (long value, TypeSpec type)
3356 if (IsTypeUnsigned (type) && value < 0)
3358 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3359 type == TypeManager.byte_type && value >= 0x100 ||
3360 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3361 type == TypeManager.ushort_type && value >= 0x10000 ||
3362 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3363 type == TypeManager.uint32_type && value >= 0x100000000;
3366 static bool IsBuildInEqualityOperator (TypeSpec t)
3368 return t == TypeManager.object_type || t == TypeManager.string_type ||
3369 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3372 static bool IsPredefinedUserOperator (TypeSpec t, Operator op)
3375 // Some predefined types have user operators
3377 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3380 private static bool IsTypeIntegral (TypeSpec type)
3382 return type == TypeManager.uint64_type ||
3383 type == TypeManager.int64_type ||
3384 type == TypeManager.uint32_type ||
3385 type == TypeManager.int32_type ||
3386 type == TypeManager.ushort_type ||
3387 type == TypeManager.short_type ||
3388 type == TypeManager.sbyte_type ||
3389 type == TypeManager.byte_type ||
3390 type == TypeManager.char_type;
3393 private static bool IsTypeUnsigned (TypeSpec type)
3395 return type == TypeManager.uint64_type ||
3396 type == TypeManager.uint32_type ||
3397 type == TypeManager.ushort_type ||
3398 type == TypeManager.byte_type ||
3399 type == TypeManager.char_type;
3402 private void WarnUselessComparison (ResolveContext ec, TypeSpec type)
3404 ec.Report.Warning (652, 2, loc, "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
3405 TypeManager.CSharpName (type));
3409 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3410 /// context of a conditional bool expression. This function will return
3411 /// false if it is was possible to use EmitBranchable, or true if it was.
3413 /// The expression's code is generated, and we will generate a branch to `target'
3414 /// if the resulting expression value is equal to isTrue
3416 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3419 // This is more complicated than it looks, but its just to avoid
3420 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3421 // but on top of that we want for == and != to use a special path
3422 // if we are comparing against null
3424 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
3425 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3428 // put the constant on the rhs, for simplicity
3430 if (left is Constant) {
3431 Expression swap = right;
3437 // brtrue/brfalse works with native int only
3439 if (((Constant) right).IsZeroInteger && right.Type != TypeManager.int64_type && right.Type != TypeManager.uint64_type) {
3440 left.EmitBranchable (ec, target, my_on_true);
3443 if (right.Type == TypeManager.bool_type) {
3444 // right is a boolean, and it's not 'false' => it is 'true'
3445 left.EmitBranchable (ec, target, !my_on_true);
3449 } else if (oper == Operator.LogicalAnd) {
3452 Label tests_end = ec.DefineLabel ();
3454 left.EmitBranchable (ec, tests_end, false);
3455 right.EmitBranchable (ec, target, true);
3456 ec.MarkLabel (tests_end);
3459 // This optimizes code like this
3460 // if (true && i > 4)
3462 if (!(left is Constant))
3463 left.EmitBranchable (ec, target, false);
3465 if (!(right is Constant))
3466 right.EmitBranchable (ec, target, false);
3471 } else if (oper == Operator.LogicalOr){
3473 left.EmitBranchable (ec, target, true);
3474 right.EmitBranchable (ec, target, true);
3477 Label tests_end = ec.DefineLabel ();
3478 left.EmitBranchable (ec, tests_end, true);
3479 right.EmitBranchable (ec, target, false);
3480 ec.MarkLabel (tests_end);
3485 } else if ((oper & Operator.ComparisonMask) == 0) {
3486 base.EmitBranchable (ec, target, on_true);
3493 TypeSpec t = left.Type;
3494 bool is_float = IsFloat (t);
3495 bool is_unsigned = is_float || IsUnsigned (t);
3498 case Operator.Equality:
3500 ec.Emit (OpCodes.Beq, target);
3502 ec.Emit (OpCodes.Bne_Un, target);
3505 case Operator.Inequality:
3507 ec.Emit (OpCodes.Bne_Un, target);
3509 ec.Emit (OpCodes.Beq, target);
3512 case Operator.LessThan:
3514 if (is_unsigned && !is_float)
3515 ec.Emit (OpCodes.Blt_Un, target);
3517 ec.Emit (OpCodes.Blt, target);
3520 ec.Emit (OpCodes.Bge_Un, target);
3522 ec.Emit (OpCodes.Bge, target);
3525 case Operator.GreaterThan:
3527 if (is_unsigned && !is_float)
3528 ec.Emit (OpCodes.Bgt_Un, target);
3530 ec.Emit (OpCodes.Bgt, target);
3533 ec.Emit (OpCodes.Ble_Un, target);
3535 ec.Emit (OpCodes.Ble, target);
3538 case Operator.LessThanOrEqual:
3540 if (is_unsigned && !is_float)
3541 ec.Emit (OpCodes.Ble_Un, target);
3543 ec.Emit (OpCodes.Ble, target);
3546 ec.Emit (OpCodes.Bgt_Un, target);
3548 ec.Emit (OpCodes.Bgt, target);
3552 case Operator.GreaterThanOrEqual:
3554 if (is_unsigned && !is_float)
3555 ec.Emit (OpCodes.Bge_Un, target);
3557 ec.Emit (OpCodes.Bge, target);
3560 ec.Emit (OpCodes.Blt_Un, target);
3562 ec.Emit (OpCodes.Blt, target);
3565 throw new InternalErrorException (oper.ToString ());
3569 public override void Emit (EmitContext ec)
3571 EmitOperator (ec, left.Type);
3574 protected virtual void EmitOperator (EmitContext ec, TypeSpec l)
3577 // Handle short-circuit operators differently
3580 if ((oper & Operator.LogicalMask) != 0) {
3581 Label load_result = ec.DefineLabel ();
3582 Label end = ec.DefineLabel ();
3584 bool is_or = oper == Operator.LogicalOr;
3585 left.EmitBranchable (ec, load_result, is_or);
3587 ec.Emit (OpCodes.Br_S, end);
3589 ec.MarkLabel (load_result);
3590 ec.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3596 // Optimize zero-based operations which cannot be optimized at expression level
3598 if (oper == Operator.Subtraction) {
3599 var lc = left as IntegralConstant;
3600 if (lc != null && lc.IsDefaultValue) {
3602 ec.Emit (OpCodes.Neg);
3609 EmitOperatorOpcode (ec, oper, l);
3612 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3613 // expression because that would wrap lifted binary operation
3615 if (enum_conversion != null)
3616 enum_conversion.Emit (ec);
3619 public override void EmitSideEffect (EmitContext ec)
3621 if ((oper & Operator.LogicalMask) != 0 ||
3622 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3623 base.EmitSideEffect (ec);
3625 left.EmitSideEffect (ec);
3626 right.EmitSideEffect (ec);
3630 protected override void CloneTo (CloneContext clonectx, Expression t)
3632 Binary target = (Binary) t;
3634 target.left = left.Clone (clonectx);
3635 target.right = right.Clone (clonectx);
3638 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3640 Arguments binder_args = new Arguments (4);
3642 MemberAccess sle = new MemberAccess (new MemberAccess (
3643 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3645 CSharpBinderFlags flags = 0;
3646 if (ec.HasSet (ResolveContext.Options.CheckedScope))
3647 flags = CSharpBinderFlags.CheckedContext;
3649 if ((oper & Operator.LogicalMask) != 0)
3650 flags |= CSharpBinderFlags.BinaryOperationLogical;
3652 binder_args.Add (new Argument (new EnumConstant (new IntLiteral ((int) flags, loc), TypeManager.binder_flags)));
3653 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3654 binder_args.Add (new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc)));
3655 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
3657 return new Invocation (DynamicExpressionStatement.GetBinder ("BinaryOperation", loc), binder_args);
3660 public override Expression CreateExpressionTree (ResolveContext ec)
3662 return CreateExpressionTree (ec, null);
3665 Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr method)
3668 bool lift_arg = false;
3671 case Operator.Addition:
3672 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3673 method_name = "AddChecked";
3675 method_name = "Add";
3677 case Operator.BitwiseAnd:
3678 method_name = "And";
3680 case Operator.BitwiseOr:
3683 case Operator.Division:
3684 method_name = "Divide";
3686 case Operator.Equality:
3687 method_name = "Equal";
3690 case Operator.ExclusiveOr:
3691 method_name = "ExclusiveOr";
3693 case Operator.GreaterThan:
3694 method_name = "GreaterThan";
3697 case Operator.GreaterThanOrEqual:
3698 method_name = "GreaterThanOrEqual";
3701 case Operator.Inequality:
3702 method_name = "NotEqual";
3705 case Operator.LeftShift:
3706 method_name = "LeftShift";
3708 case Operator.LessThan:
3709 method_name = "LessThan";
3712 case Operator.LessThanOrEqual:
3713 method_name = "LessThanOrEqual";
3716 case Operator.LogicalAnd:
3717 method_name = "AndAlso";
3719 case Operator.LogicalOr:
3720 method_name = "OrElse";
3722 case Operator.Modulus:
3723 method_name = "Modulo";
3725 case Operator.Multiply:
3726 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3727 method_name = "MultiplyChecked";
3729 method_name = "Multiply";
3731 case Operator.RightShift:
3732 method_name = "RightShift";
3734 case Operator.Subtraction:
3735 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3736 method_name = "SubtractChecked";
3738 method_name = "Subtract";
3742 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3745 Arguments args = new Arguments (2);
3746 args.Add (new Argument (left.CreateExpressionTree (ec)));
3747 args.Add (new Argument (right.CreateExpressionTree (ec)));
3748 if (method != null) {
3750 args.Add (new Argument (new BoolConstant (false, loc)));
3752 args.Add (new Argument (method.CreateExpressionTree (ec)));
3755 return CreateExpressionFactoryCall (ec, method_name, args);
3760 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3761 // b, c, d... may be strings or objects.
3763 public class StringConcat : Expression {
3764 Arguments arguments;
3766 public StringConcat (Expression left, Expression right, Location loc)
3769 type = TypeManager.string_type;
3770 eclass = ExprClass.Value;
3772 arguments = new Arguments (2);
3775 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
3777 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
3778 throw new ArgumentException ();
3780 var s = new StringConcat (left, right, loc);
3781 s.Append (rc, left);
3782 s.Append (rc, right);
3786 public override Expression CreateExpressionTree (ResolveContext ec)
3788 Argument arg = arguments [0];
3789 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
3793 // Creates nested calls tree from an array of arguments used for IL emit
3795 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
3797 Arguments concat_args = new Arguments (2);
3798 Arguments add_args = new Arguments (3);
3800 concat_args.Add (left);
3801 add_args.Add (new Argument (left_etree));
3803 concat_args.Add (arguments [pos]);
3804 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
3806 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3810 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3814 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3816 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
3817 if (++pos == arguments.Count)
3820 left = new Argument (new EmptyExpression (method.BestCandidate.ReturnType));
3821 return CreateExpressionAddCall (ec, left, expr, pos);
3824 protected override Expression DoResolve (ResolveContext ec)
3829 void Append (ResolveContext rc, Expression operand)
3834 StringConstant sc = operand as StringConstant;
3836 if (arguments.Count != 0) {
3837 Argument last_argument = arguments [arguments.Count - 1];
3838 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3839 if (last_expr_constant != null) {
3840 last_argument.Expr = new StringConstant (
3841 last_expr_constant.Value + sc.Value, sc.Location).Resolve (rc);
3847 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3849 StringConcat concat_oper = operand as StringConcat;
3850 if (concat_oper != null) {
3851 arguments.AddRange (concat_oper.arguments);
3856 arguments.Add (new Argument (operand));
3859 Expression CreateConcatMemberExpression ()
3861 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3864 public override void Emit (EmitContext ec)
3866 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3867 concat = concat.Resolve (new ResolveContext (ec.MemberContext));
3872 public override SLE.Expression MakeExpression (BuilderContext ctx)
3874 if (arguments.Count != 2)
3875 throw new NotImplementedException ("arguments.Count != 2");
3877 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
3878 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
3883 // User-defined conditional logical operator
3885 public class ConditionalLogicalOperator : UserOperatorCall {
3886 readonly bool is_and;
3889 public ConditionalLogicalOperator (MethodGroupExpr oper_method, Arguments arguments,
3890 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3891 : base (oper_method, arguments, expr_tree, loc)
3893 this.is_and = is_and;
3894 eclass = ExprClass.Unresolved;
3897 protected override Expression DoResolve (ResolveContext ec)
3899 var method = mg.BestCandidate;
3900 type = method.ReturnType;
3901 AParametersCollection pd = method.Parameters;
3902 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3903 ec.Report.Error (217, loc,
3904 "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",
3905 TypeManager.CSharpSignature (method));
3909 Expression left_dup = new EmptyExpression (type);
3910 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3911 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3912 if (op_true == null || op_false == null) {
3913 ec.Report.Error (218, loc,
3914 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3915 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3919 oper = is_and ? op_false : op_true;
3920 eclass = ExprClass.Value;
3924 public override void Emit (EmitContext ec)
3926 Label end_target = ec.DefineLabel ();
3929 // Emit and duplicate left argument
3931 arguments [0].Expr.Emit (ec);
3932 ec.Emit (OpCodes.Dup);
3933 arguments.RemoveAt (0);
3935 oper.EmitBranchable (ec, end_target, true);
3937 ec.MarkLabel (end_target);
3941 public class PointerArithmetic : Expression {
3942 Expression left, right;
3946 // We assume that `l' is always a pointer
3948 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
3957 public override Expression CreateExpressionTree (ResolveContext ec)
3959 Error_PointerInsideExpressionTree (ec);
3963 protected override Expression DoResolve (ResolveContext ec)
3965 eclass = ExprClass.Variable;
3967 if (left.Type == TypeManager.void_ptr_type) {
3968 ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
3975 public override void Emit (EmitContext ec)
3977 TypeSpec op_type = left.Type;
3979 // It must be either array or fixed buffer
3981 if (TypeManager.HasElementType (op_type)) {
3982 element = TypeManager.GetElementType (op_type);
3984 FieldExpr fe = left as FieldExpr;
3986 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
3991 int size = GetTypeSize (element);
3992 TypeSpec rtype = right.Type;
3994 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3996 // handle (pointer - pointer)
4000 ec.Emit (OpCodes.Sub);
4004 ec.Emit (OpCodes.Sizeof, element);
4007 ec.Emit (OpCodes.Div);
4009 ec.Emit (OpCodes.Conv_I8);
4012 // handle + and - on (pointer op int)
4014 Constant left_const = left as Constant;
4015 if (left_const != null) {
4017 // Optimize ((T*)null) pointer operations
4019 if (left_const.IsDefaultValue) {
4020 left = EmptyExpression.Null;
4028 var right_const = right as Constant;
4029 if (right_const != null) {
4031 // Optimize 0-based arithmetic
4033 if (right_const.IsDefaultValue)
4037 right = new IntConstant (size, right.Location);
4039 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
4041 // TODO: Should be the checks resolve context sensitive?
4042 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
4043 right = new Binary (Binary.Operator.Multiply, right, right_const, loc).Resolve (rc);
4049 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
4050 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
4051 ec.Emit (OpCodes.Conv_I);
4052 } else if (rtype == TypeManager.uint32_type) {
4053 ec.Emit (OpCodes.Conv_U);
4056 if (right_const == null && size != 1){
4058 ec.Emit (OpCodes.Sizeof, element);
4061 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
4062 ec.Emit (OpCodes.Conv_I8);
4064 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4067 if (left_const == null) {
4068 if (rtype == TypeManager.int64_type)
4069 ec.Emit (OpCodes.Conv_I);
4070 else if (rtype == TypeManager.uint64_type)
4071 ec.Emit (OpCodes.Conv_U);
4073 Binary.EmitOperatorOpcode (ec, op, op_type);
4080 // A boolean-expression is an expression that yields a result
4083 public class BooleanExpression : ShimExpression
4085 public BooleanExpression (Expression expr)
4088 this.loc = expr.Location;
4091 public override Expression CreateExpressionTree (ResolveContext ec)
4093 // TODO: We should emit IsTrue (v4) instead of direct user operator
4094 // call but that would break csc compatibility
4095 return base.CreateExpressionTree (ec);
4098 protected override Expression DoResolve (ResolveContext ec)
4100 // A boolean-expression is required to be of a type
4101 // that can be implicitly converted to bool or of
4102 // a type that implements operator true
4104 expr = expr.Resolve (ec);
4108 Assign ass = expr as Assign;
4109 if (ass != null && ass.Source is Constant) {
4110 ec.Report.Warning (665, 3, loc,
4111 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4114 if (expr.Type == TypeManager.bool_type)
4117 if (expr.Type == InternalType.Dynamic) {
4118 Arguments args = new Arguments (1);
4119 args.Add (new Argument (expr));
4120 return new DynamicUnaryConversion ("IsTrue", args, loc).Resolve (ec);
4123 type = TypeManager.bool_type;
4124 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4125 if (converted != null)
4129 // If no implicit conversion to bool exists, try using `operator true'
4131 converted = GetOperatorTrue (ec, expr, loc);
4132 if (converted == null) {
4133 expr.Error_ValueCannotBeConverted (ec, loc, type, false);
4142 /// Implements the ternary conditional operator (?:)
4144 public class Conditional : Expression {
4145 Expression expr, true_expr, false_expr;
4147 public Conditional (BooleanExpression expr, Expression true_expr, Expression false_expr, Location loc)
4150 this.true_expr = true_expr;
4151 this.false_expr = false_expr;
4155 public Expression Expr {
4161 public Expression TrueExpr {
4167 public Expression FalseExpr {
4173 public override Expression CreateExpressionTree (ResolveContext ec)
4175 Arguments args = new Arguments (3);
4176 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4177 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4178 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4179 return CreateExpressionFactoryCall (ec, "Condition", args);
4182 protected override Expression DoResolve (ResolveContext ec)
4184 expr = expr.Resolve (ec);
4185 true_expr = true_expr.Resolve (ec);
4186 false_expr = false_expr.Resolve (ec);
4188 if (true_expr == null || false_expr == null || expr == null)
4191 eclass = ExprClass.Value;
4192 TypeSpec true_type = true_expr.Type;
4193 TypeSpec false_type = false_expr.Type;
4197 // First, if an implicit conversion exists from true_expr
4198 // to false_expr, then the result type is of type false_expr.Type
4200 if (!TypeManager.IsEqual (true_type, false_type)) {
4201 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4204 // Check if both can convert implicitly to each other's type
4206 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
4207 ec.Report.Error (172, true_expr.Location,
4208 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
4209 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4214 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4217 ec.Report.Error (173, true_expr.Location,
4218 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4219 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4224 // Dead code optimalization
4225 Constant c = expr as Constant;
4227 bool is_false = c.IsDefaultValue;
4228 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
4229 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
4235 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
4240 public override void Emit (EmitContext ec)
4242 Label false_target = ec.DefineLabel ();
4243 Label end_target = ec.DefineLabel ();
4245 expr.EmitBranchable (ec, false_target, false);
4246 true_expr.Emit (ec);
4248 if (type.IsInterface) {
4249 LocalBuilder temp = ec.GetTemporaryLocal (type);
4250 ec.Emit (OpCodes.Stloc, temp);
4251 ec.Emit (OpCodes.Ldloc, temp);
4252 ec.FreeTemporaryLocal (temp, type);
4255 ec.Emit (OpCodes.Br, end_target);
4256 ec.MarkLabel (false_target);
4257 false_expr.Emit (ec);
4258 ec.MarkLabel (end_target);
4261 protected override void CloneTo (CloneContext clonectx, Expression t)
4263 Conditional target = (Conditional) t;
4265 target.expr = expr.Clone (clonectx);
4266 target.true_expr = true_expr.Clone (clonectx);
4267 target.false_expr = false_expr.Clone (clonectx);
4271 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4272 LocalTemporary temp;
4275 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4276 public abstract bool IsFixed { get; }
4277 public abstract bool IsRef { get; }
4278 public abstract string Name { get; }
4279 public abstract void SetHasAddressTaken ();
4282 // Variable IL data, it has to be protected to encapsulate hoisted variables
4284 protected abstract ILocalVariable Variable { get; }
4287 // Variable flow-analysis data
4289 public abstract VariableInfo VariableInfo { get; }
4292 public virtual void AddressOf (EmitContext ec, AddressOp mode)
4294 HoistedVariable hv = GetHoistedVariable (ec);
4296 hv.AddressOf (ec, mode);
4300 Variable.EmitAddressOf (ec);
4303 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4305 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4308 public HoistedVariable GetHoistedVariable (EmitContext ec)
4310 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4313 public override string GetSignatureForError ()
4318 public override void Emit (EmitContext ec)
4323 public override void EmitSideEffect (EmitContext ec)
4329 // This method is used by parameters that are references, that are
4330 // being passed as references: we only want to pass the pointer (that
4331 // is already stored in the parameter, not the address of the pointer,
4332 // and not the value of the variable).
4334 public void EmitLoad (EmitContext ec)
4339 public void Emit (EmitContext ec, bool leave_copy)
4341 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4343 HoistedVariable hv = GetHoistedVariable (ec);
4345 hv.Emit (ec, leave_copy);
4353 // If we are a reference, we loaded on the stack a pointer
4354 // Now lets load the real value
4356 ec.EmitLoadFromPtr (type);
4360 ec.Emit (OpCodes.Dup);
4363 temp = new LocalTemporary (Type);
4369 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4370 bool prepare_for_load)
4372 HoistedVariable hv = GetHoistedVariable (ec);
4374 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4378 New n_source = source as New;
4379 if (n_source != null) {
4380 if (!n_source.Emit (ec, this)) {
4393 ec.Emit (OpCodes.Dup);
4395 temp = new LocalTemporary (Type);
4401 ec.EmitStoreFromPtr (type);
4403 Variable.EmitAssign (ec);
4411 public bool IsHoisted {
4412 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4419 public class LocalVariableReference : VariableReference {
4420 readonly string name;
4422 public LocalInfo local_info;
4425 public LocalVariableReference (Block block, string name, Location l)
4433 // Setting `is_readonly' to false will allow you to create a writable
4434 // reference to a read-only variable. This is used by foreach and using.
4436 public LocalVariableReference (Block block, string name, Location l,
4437 LocalInfo local_info, bool is_readonly)
4438 : this (block, name, l)
4440 this.local_info = local_info;
4441 this.is_readonly = is_readonly;
4444 public override VariableInfo VariableInfo {
4445 get { return local_info.VariableInfo; }
4448 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4450 return local_info.HoistedVariant;
4454 // A local variable is always fixed
4456 public override bool IsFixed {
4457 get { return true; }
4460 public override bool IsRef {
4461 get { return false; }
4464 public bool IsReadOnly {
4465 get { return is_readonly; }
4468 public override string Name {
4469 get { return name; }
4472 public bool VerifyAssigned (ResolveContext ec)
4474 VariableInfo variable_info = local_info.VariableInfo;
4475 return variable_info == null || variable_info.IsAssigned (ec, loc);
4478 void ResolveLocalInfo ()
4480 if (local_info == null) {
4481 local_info = Block.GetLocalInfo (Name);
4482 type = local_info.VariableType;
4483 is_readonly = local_info.ReadOnly;
4487 public override void SetHasAddressTaken ()
4489 local_info.AddressTaken = true;
4492 public override Expression CreateExpressionTree (ResolveContext ec)
4494 HoistedVariable hv = GetHoistedVariable (ec);
4496 return hv.CreateExpressionTree ();
4498 Arguments arg = new Arguments (1);
4499 arg.Add (new Argument (this));
4500 return CreateExpressionFactoryCall (ec, "Constant", arg);
4503 Expression DoResolveBase (ResolveContext ec)
4505 Expression e = Block.GetConstantExpression (Name);
4507 return e.Resolve (ec);
4509 VerifyAssigned (ec);
4512 // If we are referencing a variable from the external block
4513 // flag it for capturing
4515 if (ec.MustCaptureVariable (local_info)) {
4516 if (local_info.AddressTaken)
4517 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4519 if (ec.IsVariableCapturingRequired) {
4520 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4521 storey.CaptureLocalVariable (ec, local_info);
4525 eclass = ExprClass.Variable;
4526 type = local_info.VariableType;
4530 protected override Expression DoResolve (ResolveContext ec)
4532 ResolveLocalInfo ();
4533 local_info.Used = true;
4535 if (type == null && local_info.Type is VarExpr) {
4536 local_info.VariableType = TypeManager.object_type;
4537 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
4541 return DoResolveBase (ec);
4544 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4546 ResolveLocalInfo ();
4549 if (right_side == EmptyExpression.OutAccess.Instance)
4550 local_info.Used = true;
4552 // Infer implicitly typed local variable
4554 VarExpr ve = local_info.Type as VarExpr;
4556 if (!ve.InferType (ec, right_side))
4558 type = local_info.VariableType = ve.Type;
4565 if (right_side == EmptyExpression.OutAccess.Instance) {
4566 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4567 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4568 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4569 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4570 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4571 } else if (right_side == EmptyExpression.UnaryAddress) {
4572 code = 459; msg = "Cannot take the address of {1} `{0}'";
4574 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4576 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4577 } else if (VariableInfo != null) {
4578 VariableInfo.SetAssigned (ec);
4581 return DoResolveBase (ec);
4584 public override int GetHashCode ()
4586 return Name.GetHashCode ();
4589 public override bool Equals (object obj)
4591 LocalVariableReference lvr = obj as LocalVariableReference;
4595 return Name == lvr.Name && Block == lvr.Block;
4598 protected override ILocalVariable Variable {
4599 get { return local_info; }
4602 public override string ToString ()
4604 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4607 protected override void CloneTo (CloneContext clonectx, Expression t)
4609 LocalVariableReference target = (LocalVariableReference) t;
4611 target.Block = clonectx.LookupBlock (Block);
4612 if (local_info != null)
4613 target.local_info = clonectx.LookupVariable (local_info);
4618 /// This represents a reference to a parameter in the intermediate
4621 public class ParameterReference : VariableReference {
4622 readonly ToplevelParameterInfo pi;
4624 public ParameterReference (ToplevelParameterInfo pi, Location loc)
4630 public override bool IsRef {
4631 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4634 bool HasOutModifier {
4635 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4638 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4640 return pi.Parameter.HoistedVariant;
4644 // A ref or out parameter is classified as a moveable variable, even
4645 // if the argument given for the parameter is a fixed variable
4647 public override bool IsFixed {
4648 get { return !IsRef; }
4651 public override string Name {
4652 get { return Parameter.Name; }
4655 public Parameter Parameter {
4656 get { return pi.Parameter; }
4659 public override VariableInfo VariableInfo {
4660 get { return pi.VariableInfo; }
4663 protected override ILocalVariable Variable {
4664 get { return Parameter; }
4667 public bool IsAssigned (ResolveContext ec, Location loc)
4669 // HACK: Variables are not captured in probing mode
4670 if (ec.IsInProbingMode)
4673 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4676 ec.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4680 public override void SetHasAddressTaken ()
4682 Parameter.HasAddressTaken = true;
4685 void SetAssigned (ResolveContext ec)
4687 if (HasOutModifier && ec.DoFlowAnalysis)
4688 ec.CurrentBranching.SetAssigned (VariableInfo);
4691 bool DoResolveBase (ResolveContext ec)
4693 type = pi.ParameterType;
4694 eclass = ExprClass.Variable;
4696 AnonymousExpression am = ec.CurrentAnonymousMethod;
4700 Block b = ec.CurrentBlock;
4703 IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
4704 for (int i = 0; i < p.Length; ++i) {
4705 if (p [i] != Parameter)
4709 // Don't capture local parameters
4711 if (b == ec.CurrentBlock.Toplevel && !am.IsIterator)
4715 ec.Report.Error (1628, loc,
4716 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4717 Name, am.ContainerType);
4720 if (pi.Parameter.HasAddressTaken)
4721 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4723 if (ec.IsVariableCapturingRequired && !b.Toplevel.IsExpressionTree) {
4724 AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
4725 storey.CaptureParameter (ec, this);
4737 public override int GetHashCode ()
4739 return Name.GetHashCode ();
4742 public override bool Equals (object obj)
4744 ParameterReference pr = obj as ParameterReference;
4748 return Name == pr.Name;
4751 public override void AddressOf (EmitContext ec, AddressOp mode)
4754 // ParameterReferences might already be a reference
4761 base.AddressOf (ec, mode);
4764 protected override void CloneTo (CloneContext clonectx, Expression target)
4769 public override Expression CreateExpressionTree (ResolveContext ec)
4771 HoistedVariable hv = GetHoistedVariable (ec);
4773 return hv.CreateExpressionTree ();
4775 return Parameter.ExpressionTreeVariableReference ();
4779 // Notice that for ref/out parameters, the type exposed is not the
4780 // same type exposed externally.
4783 // externally we expose "int&"
4784 // here we expose "int".
4786 // We record this in "is_ref". This means that the type system can treat
4787 // the type as it is expected, but when we generate the code, we generate
4788 // the alternate kind of code.
4790 protected override Expression DoResolve (ResolveContext ec)
4792 if (!DoResolveBase (ec))
4795 // HACK: Variables are not captured in probing mode
4796 if (ec.IsInProbingMode)
4799 if (HasOutModifier && ec.DoFlowAnalysis &&
4800 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4806 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4808 if (!DoResolveBase (ec))
4815 static public void EmitLdArg (EmitContext ec, int x)
4818 case 0: ec.Emit (OpCodes.Ldarg_0); break;
4819 case 1: ec.Emit (OpCodes.Ldarg_1); break;
4820 case 2: ec.Emit (OpCodes.Ldarg_2); break;
4821 case 3: ec.Emit (OpCodes.Ldarg_3); break;
4823 if (x > byte.MaxValue)
4824 ec.Emit (OpCodes.Ldarg, x);
4826 ec.Emit (OpCodes.Ldarg_S, (byte) x);
4833 /// Invocation of methods or delegates.
4835 public class Invocation : ExpressionStatement
4837 protected Arguments arguments;
4838 protected Expression expr;
4839 protected MethodGroupExpr mg;
4840 bool arguments_resolved;
4843 // arguments is an ArrayList, but we do not want to typecast,
4844 // as it might be null.
4846 public Invocation (Expression expr, Arguments arguments)
4848 SimpleName sn = expr as SimpleName;
4850 this.expr = sn.GetMethodGroup ();
4854 this.arguments = arguments;
4856 loc = expr.Location;
4859 public Invocation (Expression expr, Arguments arguments, bool arguments_resolved)
4860 : this (expr, arguments)
4862 this.arguments_resolved = arguments_resolved;
4865 public override Expression CreateExpressionTree (ResolveContext ec)
4867 Expression instance = mg.IsInstance ?
4868 mg.InstanceExpression.CreateExpressionTree (ec) :
4869 new NullLiteral (loc);
4871 var args = Arguments.CreateForExpressionTree (ec, arguments,
4873 mg.CreateExpressionTree (ec));
4876 MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
4878 return CreateExpressionFactoryCall (ec, "Call", args);
4881 protected override Expression DoResolve (ResolveContext ec)
4883 Expression member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4884 if (member_expr == null)
4888 // Next, evaluate all the expressions in the argument list
4890 bool dynamic_arg = false;
4891 if (arguments != null && !arguments_resolved)
4892 arguments.Resolve (ec, out dynamic_arg);
4894 TypeSpec expr_type = member_expr.Type;
4895 mg = member_expr as MethodGroupExpr;
4897 bool dynamic_member = expr_type == InternalType.Dynamic;
4899 if (!dynamic_member) {
4900 Expression invoke = null;
4903 if (expr_type != null && TypeManager.IsDelegateType (expr_type)) {
4904 invoke = new DelegateInvocation (member_expr, arguments, loc);
4905 invoke = invoke.Resolve (ec);
4906 if (invoke == null || !dynamic_arg)
4909 MemberExpr me = member_expr as MemberExpr;
4911 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
4915 mg = ec.LookupExtensionMethod (me.Type, me.Name, -1, loc);
4917 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4918 member_expr.GetSignatureForError ());
4922 ((ExtensionMethodGroupExpr) mg).ExtensionExpression = me.InstanceExpression;
4926 if (invoke == null) {
4927 mg = DoResolveOverload (ec);
4933 if (dynamic_arg || dynamic_member)
4934 return DoResolveDynamic (ec, member_expr);
4936 var method = mg.BestCandidate;
4937 if (method != null) {
4938 type = method.ReturnType;
4942 // Only base will allow this invocation to happen.
4944 if (mg.IsBase && method.IsAbstract){
4945 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature (method));
4949 if (arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
4951 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4953 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4957 IsSpecialMethodInvocation (ec, method, loc);
4959 if (mg.InstanceExpression != null)
4960 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4962 eclass = ExprClass.Value;
4966 Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
4969 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
4971 args = dmb.Arguments;
4972 if (arguments != null)
4973 args.AddRange (arguments);
4974 } else if (mg == null) {
4975 if (arguments == null)
4976 args = new Arguments (1);
4980 args.Insert (0, new Argument (memberExpr));
4984 ec.Report.Error (1971, loc,
4985 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
4990 if (arguments == null)
4991 args = new Arguments (1);
4995 MemberAccess ma = expr as MemberAccess;
4997 var left_type = ma.Left as TypeExpr;
4998 if (left_type != null) {
4999 args.Insert (0, new Argument (new TypeOf (left_type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5001 args.Insert (0, new Argument (ma.Left));
5003 } else { // is SimpleName
5005 args.Insert (0, new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc).Resolve (ec), Argument.AType.DynamicTypeName));
5007 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5012 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5015 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5017 return mg.OverloadResolve (ec, ref arguments, false, loc);
5020 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
5022 if (!method.IsReservedMethod)
5025 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName))
5028 ec.Report.SymbolRelatedToPreviousError (method);
5029 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5030 method.GetSignatureForError ());
5035 static Type[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
5037 AParametersCollection pd = mb.Parameters;
5039 Argument a = arguments [pd.Count - 1];
5040 Arglist list = (Arglist) a.Expr;
5042 return list.ArgumentTypes;
5046 /// is_base tells whether we want to force the use of the `call'
5047 /// opcode instead of using callvirt. Call is required to call
5048 /// a specific method, while callvirt will always use the most
5049 /// recent method in the vtable.
5051 /// is_static tells whether this is an invocation on a static method
5053 /// instance_expr is an expression that represents the instance
5054 /// it must be non-null if is_static is false.
5056 /// method is the method to invoke.
5058 /// Arguments is the list of arguments to pass to the method or constructor.
5060 public static void EmitCall (EmitContext ec, bool is_base,
5061 Expression instance_expr,
5062 MethodSpec method, Arguments Arguments, Location loc)
5064 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
5067 // `dup_args' leaves an extra copy of the arguments on the stack
5068 // `omit_args' does not leave any arguments at all.
5069 // So, basically, you could make one call with `dup_args' set to true,
5070 // and then another with `omit_args' set to true, and the two calls
5071 // would have the same set of arguments. However, each argument would
5072 // only have been evaluated once.
5073 public static void EmitCall (EmitContext ec, bool is_base,
5074 Expression instance_expr,
5075 MethodSpec method, Arguments Arguments, Location loc,
5076 bool dup_args, bool omit_args)
5078 LocalTemporary this_arg = null;
5080 TypeSpec decl_type = method.DeclaringType;
5082 // Speed up the check by not doing it on not allowed targets
5083 if (method.ReturnType == TypeManager.void_type && method.IsConditionallyExcluded (loc))
5087 TypeSpec iexpr_type;
5089 if (method.IsStatic) {
5091 call_op = OpCodes.Call;
5093 iexpr_type = instance_expr.Type;
5095 if (is_base || decl_type.IsStruct || decl_type.IsEnum || (instance_expr is This && !method.IsVirtual)) {
5096 call_op = OpCodes.Call;
5098 call_op = OpCodes.Callvirt;
5102 // If this is ourselves, push "this"
5105 TypeSpec t = iexpr_type;
5108 // Push the instance expression
5110 if ((iexpr_type.IsStruct && (call_op == OpCodes.Callvirt || (call_op == OpCodes.Call && decl_type == iexpr_type))) ||
5111 iexpr_type.IsGenericParameter || TypeManager.IsNullableType (decl_type)) {
5113 // If the expression implements IMemoryLocation, then
5114 // we can optimize and use AddressOf on the
5117 // If not we have to use some temporary storage for
5119 var iml = instance_expr as IMemoryLocation;
5121 iml.AddressOf (ec, AddressOp.LoadStore);
5123 LocalTemporary temp = new LocalTemporary (iexpr_type);
5124 instance_expr.Emit (ec);
5126 temp.AddressOf (ec, AddressOp.Load);
5129 // avoid the overhead of doing this all the time.
5131 t = ReferenceContainer.MakeType (iexpr_type);
5132 } else if (iexpr_type.IsEnum || iexpr_type.IsStruct) {
5133 instance_expr.Emit (ec);
5134 ec.Emit (OpCodes.Box, iexpr_type);
5135 t = iexpr_type = TypeManager.object_type;
5137 instance_expr.Emit (ec);
5141 ec.Emit (OpCodes.Dup);
5142 if (Arguments != null && Arguments.Count != 0) {
5143 this_arg = new LocalTemporary (t);
5144 this_arg.Store (ec);
5150 if (!omit_args && Arguments != null)
5151 Arguments.Emit (ec, dup_args, this_arg);
5153 if (call_op == OpCodes.Callvirt && (iexpr_type.IsGenericParameter || iexpr_type.IsStruct)) {
5154 ec.Emit (OpCodes.Constrained, iexpr_type);
5157 if (method.Parameters.HasArglist) {
5158 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5159 ec.Emit (call_op, method, varargs_types);
5166 // and DoFoo is not virtual, you can omit the callvirt,
5167 // because you don't need the null checking behavior.
5169 ec.Emit (call_op, method);
5172 public override void Emit (EmitContext ec)
5174 mg.EmitCall (ec, arguments);
5177 public override void EmitStatement (EmitContext ec)
5182 // Pop the return value if there is one
5184 if (type != TypeManager.void_type)
5185 ec.Emit (OpCodes.Pop);
5188 protected override void CloneTo (CloneContext clonectx, Expression t)
5190 Invocation target = (Invocation) t;
5192 if (arguments != null)
5193 target.arguments = arguments.Clone (clonectx);
5195 target.expr = expr.Clone (clonectx);
5198 public override SLE.Expression MakeExpression (BuilderContext ctx)
5200 return MakeExpression (ctx, mg.InstanceExpression, (MethodSpec) mg, arguments);
5203 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
5205 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5206 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
5211 /// Implements the new expression
5213 public class New : ExpressionStatement, IMemoryLocation {
5214 protected Arguments Arguments;
5217 // During bootstrap, it contains the RequestedType,
5218 // but if `type' is not null, it *might* contain a NewDelegate
5219 // (because of field multi-initialization)
5221 protected Expression RequestedType;
5223 protected MethodGroupExpr method;
5225 public New (Expression requested_type, Arguments arguments, Location l)
5227 RequestedType = requested_type;
5228 Arguments = arguments;
5233 /// Converts complex core type syntax like 'new int ()' to simple constant
5235 public static Constant Constantify (TypeSpec t)
5237 if (t == TypeManager.int32_type)
5238 return new IntConstant (0, Location.Null);
5239 if (t == TypeManager.uint32_type)
5240 return new UIntConstant (0, Location.Null);
5241 if (t == TypeManager.int64_type)
5242 return new LongConstant (0, Location.Null);
5243 if (t == TypeManager.uint64_type)
5244 return new ULongConstant (0, Location.Null);
5245 if (t == TypeManager.float_type)
5246 return new FloatConstant (0, Location.Null);
5247 if (t == TypeManager.double_type)
5248 return new DoubleConstant (0, Location.Null);
5249 if (t == TypeManager.short_type)
5250 return new ShortConstant (0, Location.Null);
5251 if (t == TypeManager.ushort_type)
5252 return new UShortConstant (0, Location.Null);
5253 if (t == TypeManager.sbyte_type)
5254 return new SByteConstant (0, Location.Null);
5255 if (t == TypeManager.byte_type)
5256 return new ByteConstant (0, Location.Null);
5257 if (t == TypeManager.char_type)
5258 return new CharConstant ('\0', Location.Null);
5259 if (t == TypeManager.bool_type)
5260 return new BoolConstant (false, Location.Null);
5261 if (t == TypeManager.decimal_type)
5262 return new DecimalConstant (0, Location.Null);
5263 if (TypeManager.IsEnumType (t))
5264 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t)), t);
5265 if (TypeManager.IsNullableType (t))
5266 return Nullable.LiftedNull.Create (t, Location.Null);
5272 // Checks whether the type is an interface that has the
5273 // [ComImport, CoClass] attributes and must be treated
5276 public Expression CheckComImport (ResolveContext ec)
5278 if (!type.IsInterface)
5282 // Turn the call into:
5283 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5285 var real_class = type.MemberDefinition.GetAttributeCoClass ();
5286 if (real_class == null)
5289 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5290 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5291 return cast.Resolve (ec);
5294 public override Expression CreateExpressionTree (ResolveContext ec)
5297 if (method == null) {
5298 args = new Arguments (1);
5299 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5301 args = Arguments.CreateForExpressionTree (ec,
5303 method.CreateExpressionTree (ec));
5306 return CreateExpressionFactoryCall (ec, "New", args);
5309 protected override Expression DoResolve (ResolveContext ec)
5311 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5317 if (type.IsPointer) {
5318 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5319 TypeManager.CSharpName (type));
5323 if (Arguments == null) {
5324 Constant c = Constantify (type);
5326 return ReducedExpression.Create (c.Resolve (ec), this);
5329 if (TypeManager.IsDelegateType (type)) {
5330 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5333 var tparam = type as TypeParameterSpec;
5334 if (tparam != null) {
5335 if (!tparam.HasSpecialConstructor && !tparam.HasSpecialStruct) {
5336 ec.Report.Error (304, loc,
5337 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
5338 TypeManager.CSharpName (type));
5341 if ((Arguments != null) && (Arguments.Count != 0)) {
5342 ec.Report.Error (417, loc,
5343 "`{0}': cannot provide arguments when creating an instance of a variable type",
5344 TypeManager.CSharpName (type));
5347 if (TypeManager.activator_create_instance == null) {
5348 TypeSpec activator_type = TypeManager.CoreLookupType (ec.Compiler, "System", "Activator", MemberKind.Class, true);
5349 if (activator_type != null) {
5350 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5351 activator_type, MemberFilter.Method ("CreateInstance", 1, ParametersCompiled.EmptyReadOnlyParameters, null), loc);
5355 eclass = ExprClass.Value;
5359 if (type.IsStatic) {
5360 ec.Report.SymbolRelatedToPreviousError (type);
5361 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5365 if (type.IsInterface || type.IsAbstract){
5366 if (!TypeManager.IsGenericType (type)) {
5367 RequestedType = CheckComImport (ec);
5368 if (RequestedType != null)
5369 return RequestedType;
5372 ec.Report.SymbolRelatedToPreviousError (type);
5373 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5377 bool is_struct = TypeManager.IsStruct (type);
5378 eclass = ExprClass.Value;
5381 // SRE returns a match for .ctor () on structs (the object constructor),
5382 // so we have to manually ignore it.
5384 if (is_struct && Arguments == null)
5387 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5388 Expression ml = MemberLookupFinal (ec, type, type, ConstructorInfo.ConstructorName, 0,
5389 MemberKind.Constructor, BindingRestriction.AccessibleOnly | BindingRestriction.DeclaredOnly, loc);
5392 if (Arguments != null) {
5393 Arguments.Resolve (ec, out dynamic);
5401 method = ml as MethodGroupExpr;
5402 if (method == null) {
5403 ml.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5407 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5412 Arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5413 return new DynamicConstructorBinder (type, Arguments, loc).Resolve (ec);
5419 bool DoEmitTypeParameter (EmitContext ec)
5421 var ctor_factory = TypeManager.activator_create_instance.MakeGenericMethod (type);
5422 var tparam = (TypeParameterSpec) type;
5424 if (tparam.IsReferenceType) {
5425 ec.Emit (OpCodes.Call, ctor_factory);
5429 // Allow DoEmit() to be called multiple times.
5430 // We need to create a new LocalTemporary each time since
5431 // you can't share LocalBuilders among ILGeneators.
5432 LocalTemporary temp = new LocalTemporary (type);
5434 Label label_activator = ec.DefineLabel ();
5435 Label label_end = ec.DefineLabel ();
5437 temp.AddressOf (ec, AddressOp.Store);
5438 ec.Emit (OpCodes.Initobj, type);
5441 ec.Emit (OpCodes.Box, type);
5442 ec.Emit (OpCodes.Brfalse, label_activator);
5444 temp.AddressOf (ec, AddressOp.Store);
5445 ec.Emit (OpCodes.Initobj, type);
5447 ec.Emit (OpCodes.Br_S, label_end);
5449 ec.MarkLabel (label_activator);
5451 ec.Emit (OpCodes.Call, ctor_factory);
5452 ec.MarkLabel (label_end);
5457 // This Emit can be invoked in two contexts:
5458 // * As a mechanism that will leave a value on the stack (new object)
5459 // * As one that wont (init struct)
5461 // If we are dealing with a ValueType, we have a few
5462 // situations to deal with:
5464 // * The target is a ValueType, and we have been provided
5465 // the instance (this is easy, we are being assigned).
5467 // * The target of New is being passed as an argument,
5468 // to a boxing operation or a function that takes a
5471 // In this case, we need to create a temporary variable
5472 // that is the argument of New.
5474 // Returns whether a value is left on the stack
5476 // *** Implementation note ***
5478 // To benefit from this optimization, each assignable expression
5479 // has to manually cast to New and call this Emit.
5481 // TODO: It's worth to implement it for arrays and fields
5483 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5485 bool is_value_type = TypeManager.IsValueType (type);
5486 VariableReference vr = target as VariableReference;
5488 if (target != null && is_value_type && (vr != null || method == null)) {
5489 target.AddressOf (ec, AddressOp.Store);
5490 } else if (vr != null && vr.IsRef) {
5494 if (Arguments != null)
5495 Arguments.Emit (ec);
5497 if (is_value_type) {
5498 if (method == null) {
5499 ec.Emit (OpCodes.Initobj, type);
5504 ec.Emit (OpCodes.Call, method.BestCandidate);
5509 if (type is TypeParameterSpec)
5510 return DoEmitTypeParameter (ec);
5512 ec.Emit (OpCodes.Newobj, method.BestCandidate);
5516 public override void Emit (EmitContext ec)
5518 LocalTemporary v = null;
5519 if (method == null && TypeManager.IsValueType (type)) {
5520 // TODO: Use temporary variable from pool
5521 v = new LocalTemporary (type);
5528 public override void EmitStatement (EmitContext ec)
5530 LocalTemporary v = null;
5531 if (method == null && TypeManager.IsValueType (type)) {
5532 // TODO: Use temporary variable from pool
5533 v = new LocalTemporary (type);
5537 ec.Emit (OpCodes.Pop);
5540 public virtual bool HasInitializer {
5546 public void AddressOf (EmitContext ec, AddressOp mode)
5548 EmitAddressOf (ec, mode);
5551 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5553 LocalTemporary value_target = new LocalTemporary (type);
5555 if (type is TypeParameterSpec) {
5556 DoEmitTypeParameter (ec);
5557 value_target.Store (ec);
5558 value_target.AddressOf (ec, mode);
5559 return value_target;
5562 if (!TypeManager.IsStruct (type)){
5564 // We throw an exception. So far, I believe we only need to support
5566 // foreach (int j in new StructType ())
5569 throw new Exception ("AddressOf should not be used for classes");
5572 value_target.AddressOf (ec, AddressOp.Store);
5574 if (method == null) {
5575 ec.Emit (OpCodes.Initobj, type);
5577 if (Arguments != null)
5578 Arguments.Emit (ec);
5580 ec.Emit (OpCodes.Call, method.BestCandidate);
5583 value_target.AddressOf (ec, mode);
5584 return value_target;
5587 protected override void CloneTo (CloneContext clonectx, Expression t)
5589 New target = (New) t;
5591 target.RequestedType = RequestedType.Clone (clonectx);
5592 if (Arguments != null){
5593 target.Arguments = Arguments.Clone (clonectx);
5597 public override SLE.Expression MakeExpression (BuilderContext ctx)
5599 return SLE.Expression.New ((ConstructorInfo) method.BestCandidate.GetMetaInfo (), Arguments.MakeExpression (Arguments, ctx));
5603 public class ArrayInitializer : Expression
5605 List<Expression> elements;
5607 public ArrayInitializer (List<Expression> init, Location loc)
5613 public ArrayInitializer (int count, Location loc)
5615 elements = new List<Expression> (count);
5619 public ArrayInitializer (Location loc)
5624 public void Add (Expression expr)
5626 elements.Add (expr);
5629 public override Expression CreateExpressionTree (ResolveContext ec)
5631 throw new NotSupportedException ("ET");
5634 protected override void CloneTo (CloneContext clonectx, Expression t)
5636 var target = (ArrayInitializer) t;
5638 target.elements = new List<Expression> (elements.Count);
5639 foreach (var element in elements)
5640 target.elements.Add (element.Clone (clonectx));
5644 get { return elements.Count; }
5647 protected override Expression DoResolve (ResolveContext rc)
5649 throw new NotImplementedException ();
5652 public override void Emit (EmitContext ec)
5654 throw new InternalErrorException ("Missing Resolve call");
5657 public Expression this [int index] {
5658 get { return elements [index]; }
5663 /// 14.5.10.2: Represents an array creation expression.
5667 /// There are two possible scenarios here: one is an array creation
5668 /// expression that specifies the dimensions and optionally the
5669 /// initialization data and the other which does not need dimensions
5670 /// specified but where initialization data is mandatory.
5672 public class ArrayCreation : Expression
5674 FullNamedExpression requested_base_type;
5675 ArrayInitializer initializers;
5678 // The list of Argument types.
5679 // This is used to construct the `newarray' or constructor signature
5681 protected List<Expression> arguments;
5683 protected TypeSpec array_element_type;
5684 int num_arguments = 0;
5685 protected int dimensions;
5686 protected readonly ComposedTypeSpecifier rank;
5687 Expression first_emit;
5688 LocalTemporary first_emit_temp;
5690 protected List<Expression> array_data;
5692 Dictionary<int, int> bounds;
5694 // The number of constants in array initializers
5695 int const_initializers_count;
5696 bool only_constant_initializers;
5698 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
5699 : this (requested_base_type, rank, initializers, l)
5701 arguments = new List<Expression> (exprs);
5702 num_arguments = arguments.Count;
5706 // For expressions like int[] foo = new int[] { 1, 2, 3 };
5708 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
5710 this.requested_base_type = requested_base_type;
5712 this.initializers = initializers;
5716 num_arguments = rank.Dimension;
5720 // For compiler generated single dimensional arrays only
5722 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
5723 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
5728 // For expressions like int[] foo = { 1, 2, 3 };
5730 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
5731 : this (requested_base_type, null, initializers, initializers.Location)
5735 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
5737 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
5740 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
5742 if (initializers != null && bounds == null) {
5744 // We use this to store all the date values in the order in which we
5745 // will need to store them in the byte blob later
5747 array_data = new List<Expression> ();
5748 bounds = new Dictionary<int, int> ();
5751 if (specified_dims) {
5752 Expression a = arguments [idx];
5757 a = ConvertExpressionToArrayIndex (ec, a);
5763 if (initializers != null) {
5764 Constant c = a as Constant;
5765 if (c == null && a is ArrayIndexCast)
5766 c = ((ArrayIndexCast) a).Child as Constant;
5769 ec.Report.Error (150, a.Location, "A constant value is expected");
5775 value = System.Convert.ToInt32 (c.GetValue ());
5777 ec.Report.Error (150, a.Location, "A constant value is expected");
5781 // TODO: probe.Count does not fit ulong in
5782 if (value != probe.Count) {
5783 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
5787 bounds[idx] = value;
5791 if (initializers == null)
5794 only_constant_initializers = true;
5795 for (int i = 0; i < probe.Count; ++i) {
5797 if (o is ArrayInitializer) {
5798 var sub_probe = o as ArrayInitializer;
5799 if (idx + 1 >= dimensions){
5800 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5804 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
5807 } else if (child_bounds > 1) {
5808 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
5810 Expression element = ResolveArrayElement (ec, o);
5811 if (element == null)
5814 // Initializers with the default values can be ignored
5815 Constant c = element as Constant;
5817 if (!c.IsDefaultInitializer (array_element_type)) {
5818 ++const_initializers_count;
5821 only_constant_initializers = false;
5824 array_data.Add (element);
5831 public override Expression CreateExpressionTree (ResolveContext ec)
5835 if (array_data == null) {
5836 args = new Arguments (arguments.Count + 1);
5837 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5838 foreach (Expression a in arguments)
5839 args.Add (new Argument (a.CreateExpressionTree (ec)));
5841 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
5844 if (dimensions > 1) {
5845 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5849 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
5850 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5851 if (array_data != null) {
5852 for (int i = 0; i < array_data.Count; ++i) {
5853 Expression e = array_data [i];
5854 args.Add (new Argument (e.CreateExpressionTree (ec)));
5858 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
5861 public void UpdateIndices ()
5864 for (var probe = initializers; probe != null;) {
5865 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
5866 Expression e = new IntConstant (probe.Count, Location.Null);
5869 bounds [i++] = probe.Count;
5871 probe = (ArrayInitializer) probe[0];
5874 Expression e = new IntConstant (probe.Count, Location.Null);
5877 bounds [i++] = probe.Count;
5883 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
5885 element = element.Resolve (ec);
5886 if (element == null)
5889 if (element is CompoundAssign.TargetExpression) {
5890 if (first_emit != null)
5891 throw new InternalErrorException ("Can only handle one mutator at a time");
5892 first_emit = element;
5893 element = first_emit_temp = new LocalTemporary (element.Type);
5896 return Convert.ImplicitConversionRequired (
5897 ec, element, array_element_type, loc);
5900 protected bool ResolveInitializers (ResolveContext ec)
5902 if (arguments != null) {
5904 for (int i = 0; i < arguments.Count; ++i) {
5905 res &= CheckIndices (ec, initializers, i, true, dimensions);
5906 if (initializers != null)
5913 arguments = new List<Expression> ();
5915 if (!CheckIndices (ec, initializers, 0, false, dimensions))
5924 // Resolved the type of the array
5926 bool ResolveArrayType (ResolveContext ec)
5928 if (requested_base_type is VarExpr) {
5929 ec.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5936 FullNamedExpression array_type_expr;
5937 if (num_arguments > 0) {
5938 array_type_expr = new ComposedCast (requested_base_type, rank);
5940 array_type_expr = requested_base_type;
5943 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5944 if (array_type_expr == null)
5947 type = array_type_expr.Type;
5948 var ac = type as ArrayContainer;
5950 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5954 array_element_type = ac.Element;
5955 dimensions = ac.Rank;
5960 protected override Expression DoResolve (ResolveContext ec)
5965 if (!ResolveArrayType (ec))
5969 // validate the initializers and fill in any missing bits
5971 if (!ResolveInitializers (ec))
5974 eclass = ExprClass.Value;
5978 byte [] MakeByteBlob ()
5983 int count = array_data.Count;
5985 TypeSpec element_type = array_element_type;
5986 if (TypeManager.IsEnumType (element_type))
5987 element_type = EnumSpec.GetUnderlyingType (element_type);
5989 factor = GetTypeSize (element_type);
5991 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
5993 data = new byte [(count * factor + 3) & ~3];
5996 for (int i = 0; i < count; ++i) {
5997 object v = array_data [i];
5999 if (v is EnumConstant)
6000 v = ((EnumConstant) v).Child;
6002 if (v is Constant && !(v is StringConstant))
6003 v = ((Constant) v).GetValue ();
6009 if (element_type == TypeManager.int64_type){
6010 if (!(v is Expression)){
6011 long val = (long) v;
6013 for (int j = 0; j < factor; ++j) {
6014 data [idx + j] = (byte) (val & 0xFF);
6018 } else if (element_type == TypeManager.uint64_type){
6019 if (!(v is Expression)){
6020 ulong val = (ulong) v;
6022 for (int j = 0; j < factor; ++j) {
6023 data [idx + j] = (byte) (val & 0xFF);
6027 } else if (element_type == TypeManager.float_type) {
6028 if (!(v is Expression)){
6029 element = BitConverter.GetBytes ((float) v);
6031 for (int j = 0; j < factor; ++j)
6032 data [idx + j] = element [j];
6033 if (!BitConverter.IsLittleEndian)
6034 System.Array.Reverse (data, idx, 4);
6036 } else if (element_type == TypeManager.double_type) {
6037 if (!(v is Expression)){
6038 element = BitConverter.GetBytes ((double) v);
6040 for (int j = 0; j < factor; ++j)
6041 data [idx + j] = element [j];
6043 // FIXME: Handle the ARM float format.
6044 if (!BitConverter.IsLittleEndian)
6045 System.Array.Reverse (data, idx, 8);
6047 } else if (element_type == TypeManager.char_type){
6048 if (!(v is Expression)){
6049 int val = (int) ((char) v);
6051 data [idx] = (byte) (val & 0xff);
6052 data [idx+1] = (byte) (val >> 8);
6054 } else if (element_type == TypeManager.short_type){
6055 if (!(v is Expression)){
6056 int val = (int) ((short) v);
6058 data [idx] = (byte) (val & 0xff);
6059 data [idx+1] = (byte) (val >> 8);
6061 } else if (element_type == TypeManager.ushort_type){
6062 if (!(v is Expression)){
6063 int val = (int) ((ushort) v);
6065 data [idx] = (byte) (val & 0xff);
6066 data [idx+1] = (byte) (val >> 8);
6068 } else if (element_type == TypeManager.int32_type) {
6069 if (!(v is Expression)){
6072 data [idx] = (byte) (val & 0xff);
6073 data [idx+1] = (byte) ((val >> 8) & 0xff);
6074 data [idx+2] = (byte) ((val >> 16) & 0xff);
6075 data [idx+3] = (byte) (val >> 24);
6077 } else if (element_type == TypeManager.uint32_type) {
6078 if (!(v is Expression)){
6079 uint val = (uint) v;
6081 data [idx] = (byte) (val & 0xff);
6082 data [idx+1] = (byte) ((val >> 8) & 0xff);
6083 data [idx+2] = (byte) ((val >> 16) & 0xff);
6084 data [idx+3] = (byte) (val >> 24);
6086 } else if (element_type == TypeManager.sbyte_type) {
6087 if (!(v is Expression)){
6088 sbyte val = (sbyte) v;
6089 data [idx] = (byte) val;
6091 } else if (element_type == TypeManager.byte_type) {
6092 if (!(v is Expression)){
6093 byte val = (byte) v;
6094 data [idx] = (byte) val;
6096 } else if (element_type == TypeManager.bool_type) {
6097 if (!(v is Expression)){
6098 bool val = (bool) v;
6099 data [idx] = (byte) (val ? 1 : 0);
6101 } else if (element_type == TypeManager.decimal_type){
6102 if (!(v is Expression)){
6103 int [] bits = Decimal.GetBits ((decimal) v);
6106 // FIXME: For some reason, this doesn't work on the MS runtime.
6107 int [] nbits = new int [4];
6108 nbits [0] = bits [3];
6109 nbits [1] = bits [2];
6110 nbits [2] = bits [0];
6111 nbits [3] = bits [1];
6113 for (int j = 0; j < 4; j++){
6114 data [p++] = (byte) (nbits [j] & 0xff);
6115 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6116 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6117 data [p++] = (byte) (nbits [j] >> 24);
6121 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6131 public override SLE.Expression MakeExpression (BuilderContext ctx)
6133 var initializers = new SLE.Expression [array_data.Count];
6134 for (var i = 0; i < initializers.Length; i++) {
6135 if (array_data [i] == null)
6136 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
6138 initializers [i] = array_data [i].MakeExpression (ctx);
6141 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
6145 // Emits the initializers for the array
6147 void EmitStaticInitializers (EmitContext ec)
6149 // FIXME: This should go to Resolve !
6150 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6151 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6152 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6153 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6154 if (TypeManager.void_initializearray_array_fieldhandle == null)
6159 // First, the static data
6163 byte [] data = MakeByteBlob ();
6165 fb = RootContext.MakeStaticData (data);
6167 ec.Emit (OpCodes.Dup);
6168 ec.Emit (OpCodes.Ldtoken, fb);
6169 ec.Emit (OpCodes.Call, TypeManager.void_initializearray_array_fieldhandle);
6173 // Emits pieces of the array that can not be computed at compile
6174 // time (variables and string locations).
6176 // This always expect the top value on the stack to be the array
6178 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6180 int dims = bounds.Count;
6181 var current_pos = new int [dims];
6183 for (int i = 0; i < array_data.Count; i++){
6185 Expression e = array_data [i];
6186 var c = e as Constant;
6188 // Constant can be initialized via StaticInitializer
6189 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
6190 TypeSpec etype = e.Type;
6192 ec.Emit (OpCodes.Dup);
6194 for (int idx = 0; idx < dims; idx++)
6195 ec.EmitInt (current_pos [idx]);
6198 // If we are dealing with a struct, get the
6199 // address of it, so we can store it.
6201 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6202 (!TypeManager.IsBuiltinOrEnum (etype) ||
6203 etype == TypeManager.decimal_type)) {
6205 ec.Emit (OpCodes.Ldelema, etype);
6210 ec.EmitArrayStore ((ArrayContainer) type);
6216 for (int j = dims - 1; j >= 0; j--){
6218 if (current_pos [j] < bounds [j])
6220 current_pos [j] = 0;
6225 public override void Emit (EmitContext ec)
6227 if (first_emit != null) {
6228 first_emit.Emit (ec);
6229 first_emit_temp.Store (ec);
6232 foreach (Expression e in arguments)
6235 ec.EmitArrayNew ((ArrayContainer) type);
6237 if (initializers == null)
6240 // Emit static initializer for arrays which have contain more than 2 items and
6241 // the static initializer will initialize at least 25% of array values.
6242 // NOTE: const_initializers_count does not contain default constant values.
6243 if (const_initializers_count > 2 && const_initializers_count * 4 > (array_data.Count) &&
6244 (TypeManager.IsPrimitiveType (array_element_type) || TypeManager.IsEnumType (array_element_type))) {
6245 EmitStaticInitializers (ec);
6247 if (!only_constant_initializers)
6248 EmitDynamicInitializers (ec, false);
6250 EmitDynamicInitializers (ec, true);
6253 if (first_emit_temp != null)
6254 first_emit_temp.Release (ec);
6257 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
6259 // no multi dimensional or jagged arrays
6260 if (arguments.Count != 1 || array_element_type.IsArray) {
6261 base.EncodeAttributeValue (rc, enc, targetType);
6265 // No array covariance, except for array -> object
6266 if (type != targetType) {
6267 if (targetType != TypeManager.object_type) {
6268 base.EncodeAttributeValue (rc, enc, targetType);
6275 // Single dimensional array of 0 size
6276 if (array_data == null) {
6277 IntConstant ic = arguments[0] as IntConstant;
6278 if (ic == null || !ic.IsDefaultValue) {
6279 base.EncodeAttributeValue (rc, enc, targetType);
6281 enc.Stream.Write (0);
6287 enc.Stream.Write ((int) array_data.Count);
6288 foreach (var element in array_data) {
6289 element.EncodeAttributeValue (rc, enc, array_element_type);
6293 protected override void CloneTo (CloneContext clonectx, Expression t)
6295 ArrayCreation target = (ArrayCreation) t;
6297 if (requested_base_type != null)
6298 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6300 if (arguments != null){
6301 target.arguments = new List<Expression> (arguments.Count);
6302 foreach (Expression e in arguments)
6303 target.arguments.Add (e.Clone (clonectx));
6306 if (initializers != null)
6307 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
6312 // Represents an implicitly typed array epxression
6314 class ImplicitlyTypedArrayCreation : ArrayCreation
6316 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6317 : base (null, rank, initializers, loc)
6321 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
6322 : base (null, initializers, loc)
6326 protected override Expression DoResolve (ResolveContext ec)
6331 dimensions = rank.Dimension;
6333 if (!ResolveInitializers (ec))
6336 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6337 array_element_type == TypeManager.void_type || array_element_type == InternalType.AnonymousMethod ||
6338 array_element_type == InternalType.MethodGroup ||
6339 arguments.Count != rank.Dimension) {
6340 Error_NoBestType (ec);
6345 // At this point we found common base type for all initializer elements
6346 // but we have to be sure that all static initializer elements are of
6349 UnifyInitializerElement (ec);
6351 type = ArrayContainer.MakeType (array_element_type, dimensions);
6352 eclass = ExprClass.Value;
6356 void Error_NoBestType (ResolveContext ec)
6358 ec.Report.Error (826, loc,
6359 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6363 // Converts static initializer only
6365 void UnifyInitializerElement (ResolveContext ec)
6367 for (int i = 0; i < array_data.Count; ++i) {
6368 Expression e = (Expression)array_data[i];
6370 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6374 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6376 element = element.Resolve (ec);
6377 if (element == null)
6380 if (array_element_type == null) {
6381 if (element.Type != TypeManager.null_type)
6382 array_element_type = element.Type;
6387 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6391 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6392 array_element_type = element.Type;
6396 Error_NoBestType (ec);
6401 public sealed class CompilerGeneratedThis : This
6403 public static This Instance = new CompilerGeneratedThis ();
6405 private CompilerGeneratedThis ()
6406 : base (Location.Null)
6410 public CompilerGeneratedThis (TypeSpec type, Location loc)
6416 protected override Expression DoResolve (ResolveContext ec)
6418 eclass = ExprClass.Variable;
6420 type = ec.CurrentType;
6425 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6432 /// Represents the `this' construct
6435 public class This : VariableReference
6437 sealed class ThisVariable : ILocalVariable
6439 public static readonly ILocalVariable Instance = new ThisVariable ();
6441 public void Emit (EmitContext ec)
6443 ec.Emit (OpCodes.Ldarg_0);
6446 public void EmitAssign (EmitContext ec)
6448 throw new InvalidOperationException ();
6451 public void EmitAddressOf (EmitContext ec)
6453 ec.Emit (OpCodes.Ldarg_0);
6457 VariableInfo variable_info;
6459 public This (Location loc)
6464 public override VariableInfo VariableInfo {
6465 get { return variable_info; }
6468 public override bool IsFixed {
6469 get { return false; }
6472 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6477 AnonymousMethodStorey storey = ae.Storey;
6478 while (storey != null) {
6479 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6481 return storey.HoistedThis;
6489 public override bool IsRef {
6490 get { return type.IsStruct; }
6493 protected override ILocalVariable Variable {
6494 get { return ThisVariable.Instance; }
6497 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
6499 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
6502 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
6505 if (TypeManager.IsStruct (ec.CurrentType) && ec.CurrentIterator == null)
6511 public bool ResolveBase (ResolveContext ec)
6513 eclass = ExprClass.Variable;
6514 type = ec.CurrentType;
6516 if (!IsThisAvailable (ec, false)) {
6517 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6518 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6519 } else if (ec.CurrentAnonymousMethod != null) {
6520 ec.Report.Error (1673, loc,
6521 "Anonymous methods inside structs cannot access instance members of `this'. " +
6522 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6524 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6528 var block = ec.CurrentBlock;
6529 if (block != null) {
6530 if (block.Toplevel.ThisVariable != null)
6531 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6533 AnonymousExpression am = ec.CurrentAnonymousMethod;
6534 if (am != null && ec.IsVariableCapturingRequired) {
6535 am.SetHasThisAccess ();
6543 // Called from Invocation to check if the invocation is correct
6545 public override void CheckMarshalByRefAccess (ResolveContext ec)
6547 if ((variable_info != null) && !(TypeManager.IsStruct (type) && ec.OmitStructFlowAnalysis) &&
6548 !variable_info.IsAssigned (ec)) {
6549 ec.Report.Error (188, loc,
6550 "The `this' object cannot be used before all of its fields are assigned to");
6551 variable_info.SetAssigned (ec);
6555 public override Expression CreateExpressionTree (ResolveContext ec)
6557 Arguments args = new Arguments (1);
6558 args.Add (new Argument (this));
6560 // Use typeless constant for ldarg.0 to save some
6561 // space and avoid problems with anonymous stories
6562 return CreateExpressionFactoryCall (ec, "Constant", args);
6565 protected override Expression DoResolve (ResolveContext ec)
6571 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6573 if (!ResolveBase (ec))
6576 if (variable_info != null)
6577 variable_info.SetAssigned (ec);
6579 if (ec.CurrentType.IsClass){
6580 if (right_side == EmptyExpression.UnaryAddress)
6581 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6582 else if (right_side == EmptyExpression.OutAccess.Instance)
6583 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6585 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6591 public override int GetHashCode()
6593 throw new NotImplementedException ();
6596 public override string Name {
6597 get { return "this"; }
6600 public override bool Equals (object obj)
6602 This t = obj as This;
6609 protected override void CloneTo (CloneContext clonectx, Expression t)
6614 public override void SetHasAddressTaken ()
6621 /// Represents the `__arglist' construct
6623 public class ArglistAccess : Expression
6625 public ArglistAccess (Location loc)
6630 public override Expression CreateExpressionTree (ResolveContext ec)
6632 throw new NotSupportedException ("ET");
6635 protected override Expression DoResolve (ResolveContext ec)
6637 eclass = ExprClass.Variable;
6638 type = TypeManager.runtime_argument_handle_type;
6640 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.Toplevel.Parameters.HasArglist) {
6641 ec.Report.Error (190, loc,
6642 "The __arglist construct is valid only within a variable argument method");
6648 public override void Emit (EmitContext ec)
6650 ec.Emit (OpCodes.Arglist);
6653 protected override void CloneTo (CloneContext clonectx, Expression target)
6660 /// Represents the `__arglist (....)' construct
6662 public class Arglist : Expression
6664 Arguments Arguments;
6666 public Arglist (Location loc)
6671 public Arglist (Arguments args, Location l)
6677 public Type[] ArgumentTypes {
6679 if (Arguments == null)
6680 return System.Type.EmptyTypes;
6682 var retval = new Type [Arguments.Count];
6683 for (int i = 0; i < retval.Length; i++)
6684 retval[i] = Arguments[i].Expr.Type.GetMetaInfo ();
6690 public override Expression CreateExpressionTree (ResolveContext ec)
6692 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6696 protected override Expression DoResolve (ResolveContext ec)
6698 eclass = ExprClass.Variable;
6699 type = InternalType.Arglist;
6700 if (Arguments != null) {
6701 bool dynamic; // Can be ignored as there is always only 1 overload
6702 Arguments.Resolve (ec, out dynamic);
6708 public override void Emit (EmitContext ec)
6710 if (Arguments != null)
6711 Arguments.Emit (ec);
6714 protected override void CloneTo (CloneContext clonectx, Expression t)
6716 Arglist target = (Arglist) t;
6718 if (Arguments != null)
6719 target.Arguments = Arguments.Clone (clonectx);
6724 /// Implements the typeof operator
6726 public class TypeOf : Expression {
6727 FullNamedExpression QueriedType;
6730 public TypeOf (FullNamedExpression queried_type, Location l)
6732 QueriedType = queried_type;
6737 public TypeSpec TypeArgument {
6743 public FullNamedExpression TypeExpression {
6751 public override Expression CreateExpressionTree (ResolveContext ec)
6753 Arguments args = new Arguments (2);
6754 args.Add (new Argument (this));
6755 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6756 return CreateExpressionFactoryCall (ec, "Constant", args);
6759 protected override Expression DoResolve (ResolveContext ec)
6761 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6765 typearg = texpr.Type;
6767 if (typearg == TypeManager.void_type && !(QueriedType is TypeExpression)) {
6768 ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6769 } else if (typearg.IsPointer && !ec.IsUnsafe){
6770 UnsafeError (ec, loc);
6771 } else if (texpr is DynamicTypeExpr) {
6772 ec.Report.Error (1962, QueriedType.Location,
6773 "The typeof operator cannot be used on the dynamic type");
6776 type = TypeManager.type_type;
6778 return DoResolveBase ();
6781 protected Expression DoResolveBase ()
6783 if (TypeManager.system_type_get_type_from_handle == null) {
6784 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6785 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6788 // Even though what is returned is a type object, it's treated as a value by the compiler.
6789 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6790 eclass = ExprClass.Value;
6794 static bool ContainsTypeParameter (TypeSpec type)
6796 if (type.Kind == MemberKind.TypeParameter)
6799 var element_container = type as ElementTypeSpec;
6800 if (element_container != null)
6801 return ContainsTypeParameter (element_container.Element);
6803 foreach (var t in type.TypeArguments) {
6804 if (ContainsTypeParameter (t)) {
6812 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
6814 // Target type is not System.Type therefore must be object
6815 // and we need to use different encoding sequence
6816 if (targetType != type)
6819 if (ContainsTypeParameter (typearg)) {
6820 rc.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6821 TypeManager.CSharpName (typearg));
6825 enc.EncodeTypeName (typearg);
6828 public override void Emit (EmitContext ec)
6830 ec.Emit (OpCodes.Ldtoken, typearg);
6831 ec.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6834 protected override void CloneTo (CloneContext clonectx, Expression t)
6836 TypeOf target = (TypeOf) t;
6837 if (QueriedType != null)
6838 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
6842 class TypeOfMethod : TypeOfMember<MethodSpec>
6844 public TypeOfMethod (MethodSpec method, Location loc)
6845 : base (method, loc)
6849 protected override Expression DoResolve (ResolveContext ec)
6851 if (member.IsConstructor) {
6852 type = TypeManager.ctorinfo_type;
6854 type = TypeManager.ctorinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", "ConstructorInfo", MemberKind.Class, true);
6856 type = TypeManager.methodinfo_type;
6858 type = TypeManager.methodinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", "MethodInfo", MemberKind.Class, true);
6861 return base.DoResolve (ec);
6864 public override void Emit (EmitContext ec)
6866 ec.Emit (OpCodes.Ldtoken, member);
6869 ec.Emit (OpCodes.Castclass, type);
6872 protected override string GetMethodName {
6873 get { return "GetMethodFromHandle"; }
6876 protected override string RuntimeHandleName {
6877 get { return "RuntimeMethodHandle"; }
6880 protected override MethodSpec TypeFromHandle {
6882 return TypeManager.methodbase_get_type_from_handle;
6885 TypeManager.methodbase_get_type_from_handle = value;
6889 protected override MethodSpec TypeFromHandleGeneric {
6891 return TypeManager.methodbase_get_type_from_handle_generic;
6894 TypeManager.methodbase_get_type_from_handle_generic = value;
6898 protected override string TypeName {
6899 get { return "MethodBase"; }
6903 abstract class TypeOfMember<T> : Expression where T : MemberSpec
6905 protected readonly T member;
6907 protected TypeOfMember (T member, Location loc)
6909 this.member = member;
6913 public override Expression CreateExpressionTree (ResolveContext ec)
6915 Arguments args = new Arguments (2);
6916 args.Add (new Argument (this));
6917 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6918 return CreateExpressionFactoryCall (ec, "Constant", args);
6921 protected override Expression DoResolve (ResolveContext ec)
6923 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
6924 var mi = is_generic ? TypeFromHandleGeneric : TypeFromHandle;
6927 TypeSpec t = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", TypeName, MemberKind.Class, true);
6928 TypeSpec handle_type = TypeManager.CoreLookupType (ec.Compiler, "System", RuntimeHandleName, MemberKind.Struct, true);
6930 if (t == null || handle_type == null)
6933 mi = TypeManager.GetPredefinedMethod (t, GetMethodName, loc,
6935 new TypeSpec[] { handle_type, TypeManager.runtime_handle_type } :
6936 new TypeSpec[] { handle_type } );
6939 TypeFromHandleGeneric = mi;
6941 TypeFromHandle = mi;
6944 eclass = ExprClass.Value;
6948 public override void Emit (EmitContext ec)
6950 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
6953 mi = TypeFromHandleGeneric;
6954 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
6956 mi = TypeFromHandle;
6959 ec.Emit (OpCodes.Call, mi);
6962 protected abstract string GetMethodName { get; }
6963 protected abstract string RuntimeHandleName { get; }
6964 protected abstract MethodSpec TypeFromHandle { get; set; }
6965 protected abstract MethodSpec TypeFromHandleGeneric { get; set; }
6966 protected abstract string TypeName { get; }
6969 class TypeOfField : TypeOfMember<FieldSpec>
6971 public TypeOfField (FieldSpec field, Location loc)
6976 protected override Expression DoResolve (ResolveContext ec)
6978 if (TypeManager.fieldinfo_type == null)
6979 TypeManager.fieldinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", TypeName, MemberKind.Class, true);
6981 type = TypeManager.fieldinfo_type;
6982 return base.DoResolve (ec);
6985 public override void Emit (EmitContext ec)
6987 ec.Emit (OpCodes.Ldtoken, member);
6991 protected override string GetMethodName {
6992 get { return "GetFieldFromHandle"; }
6995 protected override string RuntimeHandleName {
6996 get { return "RuntimeFieldHandle"; }
6999 protected override MethodSpec TypeFromHandle {
7001 return TypeManager.fieldinfo_get_field_from_handle;
7004 TypeManager.fieldinfo_get_field_from_handle = value;
7008 protected override MethodSpec TypeFromHandleGeneric {
7010 return TypeManager.fieldinfo_get_field_from_handle_generic;
7013 TypeManager.fieldinfo_get_field_from_handle_generic = value;
7017 protected override string TypeName {
7018 get { return "FieldInfo"; }
7023 /// Implements the sizeof expression
7025 public class SizeOf : Expression {
7026 readonly Expression QueriedType;
7027 TypeSpec type_queried;
7029 public SizeOf (Expression queried_type, Location l)
7031 this.QueriedType = queried_type;
7035 public override Expression CreateExpressionTree (ResolveContext ec)
7037 Error_PointerInsideExpressionTree (ec);
7041 protected override Expression DoResolve (ResolveContext ec)
7043 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7047 type_queried = texpr.Type;
7048 if (TypeManager.IsEnumType (type_queried))
7049 type_queried = EnumSpec.GetUnderlyingType (type_queried);
7051 int size_of = GetTypeSize (type_queried);
7053 return new IntConstant (size_of, loc).Resolve (ec);
7056 if (!TypeManager.VerifyUnmanaged (ec.Compiler, type_queried, loc)){
7061 ec.Report.Error (233, loc,
7062 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7063 TypeManager.CSharpName (type_queried));
7066 type = TypeManager.int32_type;
7067 eclass = ExprClass.Value;
7071 public override void Emit (EmitContext ec)
7073 ec.Emit (OpCodes.Sizeof, type_queried);
7076 protected override void CloneTo (CloneContext clonectx, Expression t)
7082 /// Implements the qualified-alias-member (::) expression.
7084 public class QualifiedAliasMember : MemberAccess
7086 readonly string alias;
7087 public static readonly string GlobalAlias = "global";
7089 public QualifiedAliasMember (string alias, string identifier, Location l)
7090 : base (null, identifier, l)
7095 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7096 : base (null, identifier, targs, l)
7101 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
7102 : base (null, identifier, arity, l)
7107 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7109 if (alias == GlobalAlias) {
7110 expr = GlobalRootNamespace.Instance;
7111 return base.ResolveAsTypeStep (ec, silent);
7114 int errors = ec.Compiler.Report.Errors;
7115 expr = ec.LookupNamespaceAlias (alias);
7117 if (errors == ec.Compiler.Report.Errors)
7118 ec.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7122 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7126 if (expr.eclass == ExprClass.Type) {
7128 ec.Compiler.Report.Error (431, loc,
7129 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7137 protected override Expression DoResolve (ResolveContext ec)
7139 return ResolveAsTypeStep (ec, false);
7142 protected override void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7144 rc.Compiler.Report.Error (687, loc,
7145 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7146 GetSignatureForError ());
7149 public override string GetSignatureForError ()
7152 if (targs != null) {
7153 name = Name + "<" + targs.GetSignatureForError () + ">";
7156 return alias + "::" + name;
7159 protected override void CloneTo (CloneContext clonectx, Expression t)
7166 /// Implements the member access expression
7168 public class MemberAccess : ATypeNameExpression {
7169 protected Expression expr;
7171 public MemberAccess (Expression expr, string id)
7172 : base (id, expr.Location)
7177 public MemberAccess (Expression expr, string identifier, Location loc)
7178 : base (identifier, loc)
7183 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7184 : base (identifier, args, loc)
7189 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
7190 : base (identifier, arity, loc)
7195 Expression DoResolve (ResolveContext ec, Expression right_side)
7198 throw new Exception ();
7201 // Resolve the expression with flow analysis turned off, we'll do the definite
7202 // assignment checks later. This is because we don't know yet what the expression
7203 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7204 // definite assignment check on the actual field and not on the whole struct.
7207 SimpleName original = expr as SimpleName;
7208 Expression expr_resolved;
7209 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
7211 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
7212 if (original != null) {
7213 expr_resolved = original.DoResolve (ec, true);
7214 if (expr_resolved != null) {
7215 // Ugly, simulate skipped Resolve
7216 if (expr_resolved is ConstantExpr) {
7217 expr_resolved = expr_resolved.Resolve (ec);
7218 } else if (expr_resolved is FieldExpr || expr_resolved is PropertyExpr) {
7220 } else if ((flags & expr_resolved.ExprClassToResolveFlags) == 0) {
7221 expr_resolved.Error_UnexpectedKind (ec, flags, expr.Location);
7222 expr_resolved = null;
7226 expr_resolved = expr.Resolve (ec, flags);
7230 if (expr_resolved == null)
7233 Namespace ns = expr_resolved as Namespace;
7235 FullNamedExpression retval = ns.Lookup (ec.Compiler, Name, Arity, loc);
7238 ns.Error_NamespaceDoesNotExist (loc, Name, Arity, ec);
7239 else if (HasTypeArguments)
7240 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
7242 expr = expr_resolved;
7246 TypeSpec expr_type = expr_resolved.Type;
7247 if (expr_type == InternalType.Dynamic) {
7248 Arguments args = new Arguments (1);
7249 args.Add (new Argument (expr_resolved.Resolve (ec)));
7250 expr = new DynamicMemberBinder (Name, args, loc);
7251 if (right_side != null)
7252 return expr.DoResolveLValue (ec, right_side);
7254 return expr.Resolve (ec);
7258 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
7259 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
7261 if ((expr_type.Kind & dot_kinds) == 0 || expr_type == TypeManager.void_type) {
7262 Unary.Error_OperatorCannotBeApplied (ec, loc, ".", expr_type);
7266 var arity = HasTypeArguments ? targs.Count : -1;
7268 var member_lookup = MemberLookup (ec.Compiler,
7269 ec.CurrentType, expr_type, expr_type, Name, arity, BindingRestriction.NoOverrides, loc);
7271 if (member_lookup == null) {
7272 expr = expr_resolved.Resolve (ec);
7274 ExprClass expr_eclass = expr.eclass;
7277 // Extension methods are not allowed on all expression types
7279 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7280 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7281 expr_eclass == ExprClass.EventAccess) {
7282 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, arity, loc);
7283 if (ex_method_lookup != null) {
7284 ex_method_lookup.ExtensionExpression = expr;
7286 if (HasTypeArguments) {
7287 if (!targs.Resolve (ec))
7290 ex_method_lookup.SetTypeArguments (ec, targs);
7293 return ex_method_lookup.Resolve (ec);
7297 member_lookup = Error_MemberLookupFailed (ec,
7298 ec.CurrentType, expr_type, expr_type, Name, arity, null,
7299 MemberKind.All, BindingRestriction.AccessibleOnly);
7300 if (member_lookup == null)
7304 expr = expr_resolved;
7307 TypeExpr texpr = member_lookup as TypeExpr;
7308 if (texpr != null) {
7309 if (!(expr_resolved is TypeExpr)) {
7310 me = expr_resolved as MemberExpr;
7311 if (me == null || me.ProbeIdenticalTypeName (ec, expr_resolved, original) == expr_resolved) {
7312 ec.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7313 Name, member_lookup.GetSignatureForError ());
7318 if (!texpr.CheckAccessLevel (ec.MemberContext)) {
7319 ec.Report.SymbolRelatedToPreviousError (member_lookup.Type);
7320 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type), ec.Report);
7324 if (HasTypeArguments) {
7325 var ct = new GenericTypeExpr (member_lookup.Type, targs, loc);
7326 return ct.ResolveAsTypeStep (ec, false);
7329 return member_lookup;
7332 me = (MemberExpr) member_lookup;
7334 if (original != null && me.IsStatic)
7335 expr_resolved = me.ProbeIdenticalTypeName (ec, expr_resolved, original);
7337 me = me.ResolveMemberAccess (ec, expr_resolved, original);
7339 if (HasTypeArguments) {
7340 if (!targs.Resolve (ec))
7343 me.SetTypeArguments (ec, targs);
7346 if (original != null && (!TypeManager.IsValueType (expr_type) || me is PropertyExpr)) {
7347 if (me.IsInstance) {
7348 LocalVariableReference var = expr_resolved as LocalVariableReference;
7349 if (var != null && !var.VerifyAssigned (ec))
7354 // The following DoResolve/DoResolveLValue will do the definite assignment
7357 if (right_side != null)
7358 return me.DoResolveLValue (ec, right_side);
7360 return me.Resolve (ec);
7363 protected override Expression DoResolve (ResolveContext ec)
7365 return DoResolve (ec, null);
7368 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7370 return DoResolve (ec, right_side);
7373 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7375 return ResolveNamespaceOrType (ec, silent);
7378 public FullNamedExpression ResolveNamespaceOrType (IMemberContext rc, bool silent)
7380 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7382 if (expr_resolved == null)
7385 Namespace ns = expr_resolved as Namespace;
7387 FullNamedExpression retval = ns.Lookup (rc.Compiler, Name, Arity, loc);
7389 if (retval == null) {
7391 ns.Error_NamespaceDoesNotExist (loc, Name, Arity, rc);
7392 } else if (HasTypeArguments) {
7393 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7399 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7400 if (tnew_expr == null)
7403 TypeSpec expr_type = tnew_expr.Type;
7404 if (TypeManager.IsGenericParameter (expr_type)) {
7405 rc.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7406 tnew_expr.GetSignatureForError ());
7410 var nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7411 if (nested == null) {
7415 Error_IdentifierNotFound (rc, expr_type, Name);
7420 if (!IsMemberAccessible (rc.CurrentType ?? InternalType.FakeInternalType, nested, out extra_check)) {
7421 ErrorIsInaccesible (loc, nested.GetSignatureForError (), rc.Compiler.Report);
7425 if (HasTypeArguments) {
7426 texpr = new GenericTypeExpr (nested, targs, loc);
7428 texpr = new TypeExpression (nested, loc);
7431 return texpr.ResolveAsTypeStep (rc, false);
7434 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7436 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
7438 if (nested != null) {
7439 Error_TypeArgumentsCannotBeUsed (rc.Compiler.Report, expr.Location, nested, Arity);
7443 var member_lookup = MemberLookup (rc.Compiler,
7444 rc.CurrentType, expr_type, expr_type, identifier, -1,
7445 MemberKind.All, BindingRestriction.None, loc);
7447 if (member_lookup == null) {
7448 rc.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7449 Name, expr_type.GetSignatureForError ());
7451 // TODO: Report.SymbolRelatedToPreviousError
7452 member_lookup.Error_UnexpectedKind (rc.Compiler.Report, null, "type", loc);
7456 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
7458 if (RootContext.Version > LanguageVersion.ISO_2 && !ec.Compiler.IsRuntimeBinder &&
7459 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7460 ec.Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7461 "extension method `{1}' of type `{0}' could be found " +
7462 "(are you missing a using directive or an assembly reference?)",
7463 TypeManager.CSharpName (type), name);
7467 base.Error_TypeDoesNotContainDefinition (ec, type, name);
7470 public override string GetSignatureForError ()
7472 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7475 public Expression Left {
7481 protected override void CloneTo (CloneContext clonectx, Expression t)
7483 MemberAccess target = (MemberAccess) t;
7485 target.expr = expr.Clone (clonectx);
7490 /// Implements checked expressions
7492 public class CheckedExpr : Expression {
7494 public Expression Expr;
7496 public CheckedExpr (Expression e, Location l)
7502 public override Expression CreateExpressionTree (ResolveContext ec)
7504 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7505 return Expr.CreateExpressionTree (ec);
7508 protected override Expression DoResolve (ResolveContext ec)
7510 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7511 Expr = Expr.Resolve (ec);
7516 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7519 eclass = Expr.eclass;
7524 public override void Emit (EmitContext ec)
7526 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7530 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7532 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7533 Expr.EmitBranchable (ec, target, on_true);
7536 public override SLE.Expression MakeExpression (BuilderContext ctx)
7538 using (ctx.With (BuilderContext.Options.AllCheckStateFlags, true)) {
7539 return Expr.MakeExpression (ctx);
7543 protected override void CloneTo (CloneContext clonectx, Expression t)
7545 CheckedExpr target = (CheckedExpr) t;
7547 target.Expr = Expr.Clone (clonectx);
7552 /// Implements the unchecked expression
7554 public class UnCheckedExpr : Expression {
7556 public Expression Expr;
7558 public UnCheckedExpr (Expression e, Location l)
7564 public override Expression CreateExpressionTree (ResolveContext ec)
7566 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7567 return Expr.CreateExpressionTree (ec);
7570 protected override Expression DoResolve (ResolveContext ec)
7572 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7573 Expr = Expr.Resolve (ec);
7578 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7581 eclass = Expr.eclass;
7586 public override void Emit (EmitContext ec)
7588 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7592 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7594 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7595 Expr.EmitBranchable (ec, target, on_true);
7598 protected override void CloneTo (CloneContext clonectx, Expression t)
7600 UnCheckedExpr target = (UnCheckedExpr) t;
7602 target.Expr = Expr.Clone (clonectx);
7607 /// An Element Access expression.
7609 /// During semantic analysis these are transformed into
7610 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7612 public class ElementAccess : Expression {
7613 public Arguments Arguments;
7614 public Expression Expr;
7616 public ElementAccess (Expression e, Arguments args, Location loc)
7620 this.Arguments = args;
7623 public override Expression CreateExpressionTree (ResolveContext ec)
7625 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
7626 Expr.CreateExpressionTree (ec));
7628 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
7631 Expression MakePointerAccess (ResolveContext ec, TypeSpec t)
7633 if (Arguments.Count != 1){
7634 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
7638 if (Arguments [0] is NamedArgument)
7639 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
7641 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), t, loc);
7642 return new Indirection (p, loc).Resolve (ec);
7645 protected override Expression DoResolve (ResolveContext ec)
7647 Expr = Expr.Resolve (ec);
7652 // We perform some simple tests, and then to "split" the emit and store
7653 // code we create an instance of a different class, and return that.
7655 // I am experimenting with this pattern.
7657 TypeSpec t = Expr.Type;
7659 if (t == TypeManager.array_type){
7660 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7665 return (new ArrayAccess (this, loc)).Resolve (ec);
7667 return MakePointerAccess (ec, t);
7669 FieldExpr fe = Expr as FieldExpr;
7671 var ff = fe.Spec as FixedFieldSpec;
7673 return MakePointerAccess (ec, ff.ElementType);
7676 return (new IndexerAccess (this, loc)).Resolve (ec);
7679 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7681 Expr = Expr.Resolve (ec);
7687 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7690 return MakePointerAccess (ec, type);
7692 if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
7693 Error_CannotModifyIntermediateExpressionValue (ec);
7695 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7698 public override void Emit (EmitContext ec)
7700 throw new Exception ("Should never be reached");
7703 public static void Error_NamedArgument (NamedArgument na, Report Report)
7705 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
7708 public override string GetSignatureForError ()
7710 return Expr.GetSignatureForError ();
7713 protected override void CloneTo (CloneContext clonectx, Expression t)
7715 ElementAccess target = (ElementAccess) t;
7717 target.Expr = Expr.Clone (clonectx);
7718 if (Arguments != null)
7719 target.Arguments = Arguments.Clone (clonectx);
7724 /// Implements array access
7726 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
7728 // Points to our "data" repository
7732 LocalTemporary temp;
7736 public ArrayAccess (ElementAccess ea_data, Location l)
7742 public override Expression CreateExpressionTree (ResolveContext ec)
7744 return ea.CreateExpressionTree (ec);
7747 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7749 return DoResolve (ec);
7752 protected override Expression DoResolve (ResolveContext ec)
7754 // dynamic is used per argument in ConvertExpressionToArrayIndex case
7756 ea.Arguments.Resolve (ec, out dynamic);
7758 var ac = ea.Expr.Type as ArrayContainer;
7759 int rank = ea.Arguments.Count;
7760 if (ac.Rank != rank) {
7761 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7762 rank.ToString (), ac.Rank.ToString ());
7767 if (type.IsPointer && !ec.IsUnsafe) {
7768 UnsafeError (ec, ea.Location);
7771 foreach (Argument a in ea.Arguments) {
7772 if (a is NamedArgument)
7773 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
7775 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7778 eclass = ExprClass.Variable;
7783 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7785 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7789 // Load the array arguments into the stack.
7791 void LoadArrayAndArguments (EmitContext ec)
7795 for (int i = 0; i < ea.Arguments.Count; ++i) {
7796 ea.Arguments [i].Emit (ec);
7800 public void Emit (EmitContext ec, bool leave_copy)
7802 var ac = ea.Expr.Type as ArrayContainer;
7805 ec.EmitLoadFromPtr (type);
7807 LoadArrayAndArguments (ec);
7808 ec.EmitArrayLoad (ac);
7812 ec.Emit (OpCodes.Dup);
7813 temp = new LocalTemporary (this.type);
7818 public override void Emit (EmitContext ec)
7823 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7825 var ac = (ArrayContainer) ea.Expr.Type;
7826 TypeSpec t = source.Type;
7827 prepared = prepare_for_load;
7830 AddressOf (ec, AddressOp.LoadStore);
7831 ec.Emit (OpCodes.Dup);
7833 LoadArrayAndArguments (ec);
7836 // If we are dealing with a struct, get the
7837 // address of it, so we can store it.
7839 // The stobj opcode used by value types will need
7840 // an address on the stack, not really an array/array
7843 if (ac.Rank == 1 && TypeManager.IsStruct (t) &&
7844 (!TypeManager.IsBuiltinOrEnum (t) ||
7845 t == TypeManager.decimal_type)) {
7847 ec.Emit (OpCodes.Ldelema, t);
7853 ec.Emit (OpCodes.Dup);
7854 temp = new LocalTemporary (this.type);
7859 ec.EmitStoreFromPtr (t);
7861 ec.EmitArrayStore (ac);
7870 public void EmitNew (EmitContext ec, New source, bool leave_copy)
7872 if (!source.Emit (ec, this)) {
7874 throw new NotImplementedException ();
7879 throw new NotImplementedException ();
7882 public void AddressOf (EmitContext ec, AddressOp mode)
7884 var ac = (ArrayContainer) ea.Expr.Type;
7886 LoadArrayAndArguments (ec);
7887 ec.EmitArrayAddress (ac);
7891 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
7893 return SLE.Expression.ArrayAccess (
7894 ea.Expr.MakeExpression (ctx),
7895 Arguments.MakeExpression (ea.Arguments, ctx));
7899 public override SLE.Expression MakeExpression (BuilderContext ctx)
7901 return SLE.Expression.ArrayIndex (
7902 ea.Expr.MakeExpression (ctx),
7903 Arguments.MakeExpression (ea.Arguments, ctx));
7908 /// Expressions that represent an indexer call.
7910 public class IndexerAccess : Expression, IDynamicAssign
7912 class IndexerMethodGroupExpr : MethodGroupExpr
7914 IEnumerable<IndexerSpec> candidates;
7916 public IndexerMethodGroupExpr (IEnumerable<IndexerSpec> indexers, Location loc)
7917 : base (FilterAccessors (indexers).ToList (), null, loc)
7919 candidates = indexers;
7922 public IndexerSpec BestIndexer ()
7924 return MemberCache.FindIndexers (BestCandidate.DeclaringType, BindingRestriction.None).
7926 (l.HasGet && l.Get.MemberDefinition == BestCandidate.MemberDefinition) ||
7927 (l.HasSet && l.Set.MemberDefinition == BestCandidate.MemberDefinition)).First ();
7930 static IEnumerable<MemberSpec> FilterAccessors (IEnumerable<IndexerSpec> indexers)
7932 foreach (IndexerSpec i in indexers) {
7940 protected override IList<MemberSpec> GetBaseTypeMethods (ResolveContext rc, TypeSpec type)
7942 candidates = GetIndexersForType (type);
7943 if (candidates == null)
7946 return FilterAccessors (candidates).ToList ();
7949 public override string Name {
7955 protected override int GetApplicableParametersCount (MethodSpec method, AParametersCollection parameters)
7958 // Here is the trick, decrease number of arguments by 1 when only
7959 // available property method is setter. This makes overload resolution
7960 // work correctly for indexers.
7963 if (method.Name [0] == 'g')
7964 return parameters.Count;
7966 return parameters.Count - 1;
7971 // Points to our "data" repository
7974 bool is_base_indexer;
7976 LocalTemporary temp;
7977 LocalTemporary prepared_value;
7978 Expression set_expr;
7980 protected TypeSpec indexer_type;
7981 protected TypeSpec current_type;
7982 protected Expression instance_expr;
7983 protected Arguments arguments;
7985 public IndexerAccess (ElementAccess ea, Location loc)
7986 : this (ea.Expr, false, loc)
7988 this.arguments = ea.Arguments;
7991 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7994 this.instance_expr = instance_expr;
7995 this.is_base_indexer = is_base_indexer;
7999 static string GetAccessorName (bool isSet)
8001 return isSet ? "set" : "get";
8004 public override Expression CreateExpressionTree (ResolveContext ec)
8006 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8007 instance_expr.CreateExpressionTree (ec),
8008 new TypeOfMethod (spec.Get, loc));
8010 return CreateExpressionFactoryCall (ec, "Call", args);
8013 static IEnumerable<IndexerSpec> GetIndexersForType (TypeSpec lookup_type)
8015 return MemberCache.FindIndexers (lookup_type, BindingRestriction.AccessibleOnly | BindingRestriction.NoOverrides);
8018 protected virtual void CommonResolve (ResolveContext ec)
8020 indexer_type = instance_expr.Type;
8021 current_type = ec.CurrentType;
8024 protected override Expression DoResolve (ResolveContext ec)
8026 return ResolveAccessor (ec, null);
8029 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8031 if (right_side == EmptyExpression.OutAccess.Instance) {
8032 right_side.DoResolveLValue (ec, this);
8036 // if the indexer returns a value type, and we try to set a field in it
8037 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8038 Error_CannotModifyIntermediateExpressionValue (ec);
8041 return ResolveAccessor (ec, right_side);
8044 Expression ResolveAccessor (ResolveContext ec, Expression right_side)
8050 arguments.Resolve (ec, out dynamic);
8052 if (indexer_type == InternalType.Dynamic) {
8055 var ilist = GetIndexersForType (indexer_type);
8056 if (ilist == null) {
8057 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8058 TypeManager.CSharpName (indexer_type));
8062 var mg = new IndexerMethodGroupExpr (ilist, loc) {
8063 InstanceExpression = instance_expr
8066 if (is_base_indexer)
8067 mg.QueriedBaseType = current_type;
8069 mg = mg.OverloadResolve (ec, ref arguments, false, loc) as IndexerMethodGroupExpr;
8074 spec = mg.BestIndexer ();
8078 Arguments args = new Arguments (arguments.Count + 1);
8079 if (is_base_indexer) {
8080 ec.Report.Error (1972, loc, "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8082 args.Add (new Argument (instance_expr));
8084 args.AddRange (arguments);
8086 var expr = new DynamicIndexBinder (args, loc);
8087 if (right_side != null)
8088 return expr.ResolveLValue (ec, right_side);
8090 return expr.Resolve (ec);
8093 type = spec.MemberType;
8094 if (type.IsPointer && !ec.IsUnsafe)
8095 UnsafeError (ec, loc);
8097 MethodSpec accessor;
8098 if (right_side == null) {
8099 accessor = spec.Get;
8101 accessor = spec.Set;
8102 if (!spec.HasSet && spec.HasGet) {
8103 ec.Report.SymbolRelatedToPreviousError (spec);
8104 ec.Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8105 spec.GetSignatureForError ());
8109 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8112 if (accessor == null) {
8113 ec.Report.SymbolRelatedToPreviousError (spec);
8114 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8115 spec.GetSignatureForError (), GetAccessorName (right_side != null));
8120 // Only base will allow this invocation to happen.
8122 if (spec.IsAbstract && this is BaseIndexerAccess) {
8123 Error_CannotCallAbstractBase (ec, spec.GetSignatureForError ());
8126 bool must_do_cs1540_check;
8127 if (!IsMemberAccessible (ec.CurrentType, accessor, out must_do_cs1540_check)) {
8128 if (spec.HasDifferentAccessibility) {
8129 ec.Report.SymbolRelatedToPreviousError (accessor);
8130 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8131 TypeManager.GetFullNameSignature (spec), GetAccessorName (right_side != null));
8133 ec.Report.SymbolRelatedToPreviousError (spec);
8134 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (spec), ec.Report);
8138 instance_expr.CheckMarshalByRefAccess (ec);
8140 if (must_do_cs1540_check && (instance_expr != EmptyExpression.Null) &&
8141 !TypeManager.IsInstantiationOfSameGenericType (instance_expr.Type, ec.CurrentType) &&
8142 !TypeManager.IsNestedChildOf (ec.CurrentType, instance_expr.Type) &&
8143 !TypeManager.IsSubclassOf (instance_expr.Type, ec.CurrentType)) {
8144 ec.Report.SymbolRelatedToPreviousError (accessor);
8145 Error_CannotAccessProtected (ec, loc, spec, instance_expr.Type, ec.CurrentType);
8149 eclass = ExprClass.IndexerAccess;
8153 public override void Emit (EmitContext ec)
8158 public void Emit (EmitContext ec, bool leave_copy)
8161 prepared_value.Emit (ec);
8163 Invocation.EmitCall (ec, is_base_indexer, instance_expr, spec.Get,
8164 arguments, loc, false, false);
8168 ec.Emit (OpCodes.Dup);
8169 temp = new LocalTemporary (Type);
8175 // source is ignored, because we already have a copy of it from the
8176 // LValue resolution and we have already constructed a pre-cached
8177 // version of the arguments (ea.set_arguments);
8179 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8181 prepared = prepare_for_load;
8182 Expression value = set_expr;
8185 Invocation.EmitCall (ec, is_base_indexer, instance_expr, spec.Get,
8186 arguments, loc, true, false);
8188 prepared_value = new LocalTemporary (type);
8189 prepared_value.Store (ec);
8191 prepared_value.Release (ec);
8194 ec.Emit (OpCodes.Dup);
8195 temp = new LocalTemporary (Type);
8198 } else if (leave_copy) {
8199 temp = new LocalTemporary (Type);
8206 arguments.Add (new Argument (value));
8208 Invocation.EmitCall (ec, is_base_indexer, instance_expr, spec.Set, arguments, loc, false, prepared);
8216 public override string GetSignatureForError ()
8218 return spec.GetSignatureForError ();
8222 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
8224 var value = new[] { set_expr.MakeExpression (ctx) };
8225 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
8227 return SLE.Expression.Block (
8228 SLE.Expression.Call (instance_expr.MakeExpression (ctx), (MethodInfo) spec.Set.GetMetaInfo (), args),
8233 public override SLE.Expression MakeExpression (BuilderContext ctx)
8235 var args = Arguments.MakeExpression (arguments, ctx);
8236 return SLE.Expression.Call (instance_expr.MakeExpression (ctx), (MethodInfo) spec.Get.GetMetaInfo (), args);
8239 protected override void CloneTo (CloneContext clonectx, Expression t)
8241 IndexerAccess target = (IndexerAccess) t;
8243 if (arguments != null)
8244 target.arguments = arguments.Clone (clonectx);
8246 if (instance_expr != null)
8247 target.instance_expr = instance_expr.Clone (clonectx);
8252 /// The base operator for method names
8254 public class BaseAccess : Expression {
8255 readonly string identifier;
8258 public BaseAccess (string member, Location l)
8260 this.identifier = member;
8264 public BaseAccess (string member, TypeArguments args, Location l)
8272 public string Identifier {
8278 public TypeArguments TypeArguments {
8285 public override Expression CreateExpressionTree (ResolveContext ec)
8287 throw new NotSupportedException ("ET");
8290 protected override Expression DoResolve (ResolveContext ec)
8292 Expression c = CommonResolve (ec);
8298 // MethodGroups use this opportunity to flag an error on lacking ()
8300 if (!(c is MethodGroupExpr))
8301 return c.Resolve (ec);
8305 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8307 Expression c = CommonResolve (ec);
8313 // MethodGroups use this opportunity to flag an error on lacking ()
8315 if (! (c is MethodGroupExpr))
8316 return c.DoResolveLValue (ec, right_side);
8321 Expression CommonResolve (ResolveContext ec)
8323 Expression member_lookup;
8324 TypeSpec current_type = ec.CurrentType;
8325 TypeSpec base_type = current_type.BaseType;
8327 if (!This.IsThisAvailable (ec, false)) {
8329 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
8331 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
8336 var arity = args == null ? -1 : args.Count;
8337 member_lookup = MemberLookup (ec.Compiler, ec.CurrentType, null, base_type, identifier, arity,
8338 MemberKind.All, BindingRestriction.AccessibleOnly | BindingRestriction.NoOverrides, loc);
8339 if (member_lookup == null) {
8340 Error_MemberLookupFailed (ec, ec.CurrentType, base_type, base_type, identifier, arity,
8341 null, MemberKind.All, BindingRestriction.AccessibleOnly);
8345 MemberExpr me = member_lookup as MemberExpr;
8347 if (member_lookup is TypeExpression){
8348 ec.Report.Error (582, loc, "{0}: Can not reference a type through an expression, try `{1}' instead",
8349 identifier, member_lookup.GetSignatureForError ());
8351 ec.Report.Error (582, loc, "{0}: Can not reference a {1} through an expression",
8352 identifier, member_lookup.ExprClassName);
8358 me.QueriedBaseType = base_type;
8362 me.SetTypeArguments (ec, args);
8368 public override void Emit (EmitContext ec)
8370 throw new Exception ("Should never be called");
8373 protected override void CloneTo (CloneContext clonectx, Expression t)
8375 BaseAccess target = (BaseAccess) t;
8378 target.args = args.Clone ();
8383 /// The base indexer operator
8385 public class BaseIndexerAccess : IndexerAccess {
8386 public BaseIndexerAccess (Arguments args, Location loc)
8387 : base (null, true, loc)
8389 this.arguments = args;
8392 protected override void CommonResolve (ResolveContext ec)
8394 instance_expr = ec.GetThis (loc);
8396 current_type = ec.CurrentType.BaseType;
8397 indexer_type = current_type;
8400 public override Expression CreateExpressionTree (ResolveContext ec)
8402 MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
8403 return base.CreateExpressionTree (ec);
8408 /// This class exists solely to pass the Type around and to be a dummy
8409 /// that can be passed to the conversion functions (this is used by
8410 /// foreach implementation to typecast the object return value from
8411 /// get_Current into the proper type. All code has been generated and
8412 /// we only care about the side effect conversions to be performed
8414 /// This is also now used as a placeholder where a no-action expression
8415 /// is needed (the `New' class).
8417 public class EmptyExpression : Expression {
8418 public static readonly Expression Null = new EmptyExpression ();
8420 public class OutAccess : EmptyExpression
8422 public static readonly OutAccess Instance = new OutAccess ();
8424 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8426 rc.Report.Error (206, right_side.Location,
8427 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
8433 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8434 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8435 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8437 static EmptyExpression temp = new EmptyExpression ();
8438 public static EmptyExpression Grab ()
8440 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8445 public static void Release (EmptyExpression e)
8452 // FIXME: Don't set to object
8453 type = TypeManager.object_type;
8454 eclass = ExprClass.Value;
8455 loc = Location.Null;
8458 public EmptyExpression (TypeSpec t)
8461 eclass = ExprClass.Value;
8462 loc = Location.Null;
8465 public override Expression CreateExpressionTree (ResolveContext ec)
8467 throw new NotSupportedException ("ET");
8470 protected override Expression DoResolve (ResolveContext ec)
8475 public override void Emit (EmitContext ec)
8477 // nothing, as we only exist to not do anything.
8480 public override void EmitSideEffect (EmitContext ec)
8485 // This is just because we might want to reuse this bad boy
8486 // instead of creating gazillions of EmptyExpressions.
8487 // (CanImplicitConversion uses it)
8489 public void SetType (TypeSpec t)
8496 // Empty statement expression
8498 public sealed class EmptyExpressionStatement : ExpressionStatement
8500 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8502 private EmptyExpressionStatement ()
8504 loc = Location.Null;
8507 public override Expression CreateExpressionTree (ResolveContext ec)
8512 public override void EmitStatement (EmitContext ec)
8517 protected override Expression DoResolve (ResolveContext ec)
8519 eclass = ExprClass.Value;
8520 type = TypeManager.object_type;
8524 public override void Emit (EmitContext ec)
8530 public class UserCast : Expression {
8534 public UserCast (MethodSpec method, Expression source, Location l)
8536 this.method = method;
8537 this.source = source;
8538 type = method.ReturnType;
8542 public Expression Source {
8548 public override Expression CreateExpressionTree (ResolveContext ec)
8550 Arguments args = new Arguments (3);
8551 args.Add (new Argument (source.CreateExpressionTree (ec)));
8552 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8553 args.Add (new Argument (new TypeOfMethod (method, loc)));
8554 return CreateExpressionFactoryCall (ec, "Convert", args);
8557 protected override Expression DoResolve (ResolveContext ec)
8559 ObsoleteAttribute oa = method.GetAttributeObsolete ();
8561 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
8563 eclass = ExprClass.Value;
8567 public override void Emit (EmitContext ec)
8570 ec.Emit (OpCodes.Call, method);
8573 public override string GetSignatureForError ()
8575 return TypeManager.CSharpSignature (method);
8578 public override SLE.Expression MakeExpression (BuilderContext ctx)
8580 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
8585 // Holds additional type specifiers like ?, *, []
8587 public class ComposedTypeSpecifier
8589 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
8591 public readonly int Dimension;
8592 public readonly Location Location;
8594 public ComposedTypeSpecifier (int specifier, Location loc)
8596 this.Dimension = specifier;
8597 this.Location = loc;
8601 public bool IsNullable {
8603 return Dimension == -1;
8607 public bool IsPointer {
8609 return Dimension == -2;
8613 public ComposedTypeSpecifier Next { get; set; }
8617 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
8619 return new ComposedTypeSpecifier (dimension, loc);
8622 public static ComposedTypeSpecifier CreateNullable (Location loc)
8624 return new ComposedTypeSpecifier (-1, loc);
8627 public static ComposedTypeSpecifier CreatePointer (Location loc)
8629 return new ComposedTypeSpecifier (-2, loc);
8632 public string GetSignatureForError ()
8637 ArrayContainer.GetPostfixSignature (Dimension);
8639 return Next != null ? s + Next.GetSignatureForError () : s;
8644 // This class is used to "construct" the type during a typecast
8645 // operation. Since the Type.GetType class in .NET can parse
8646 // the type specification, we just use this to construct the type
8647 // one bit at a time.
8649 public class ComposedCast : TypeExpr {
8650 FullNamedExpression left;
8651 ComposedTypeSpecifier spec;
8653 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
8656 throw new ArgumentNullException ("spec");
8660 this.loc = spec.Location;
8663 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
8665 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8670 eclass = ExprClass.Type;
8672 var single_spec = spec;
8674 if (single_spec.IsNullable) {
8675 lexpr = new Nullable.NullableType (lexpr, loc);
8676 lexpr = lexpr.ResolveAsTypeTerminal (ec, false);
8680 single_spec = single_spec.Next;
8681 } else if (single_spec.IsPointer) {
8682 if (!TypeManager.VerifyUnmanaged (ec.Compiler, type, loc))
8686 UnsafeError (ec.Compiler.Report, loc);
8689 type = PointerContainer.MakeType (type);
8690 single_spec = single_spec.Next;
8693 if (single_spec != null && single_spec.Dimension > 0) {
8694 if (TypeManager.IsSpecialType (type)) {
8695 ec.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
8696 } else if (type.IsStatic) {
8697 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
8698 ec.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8699 type.GetSignatureForError ());
8701 MakeArray (single_spec);
8708 void MakeArray (ComposedTypeSpecifier spec)
8710 if (spec.Next != null)
8711 MakeArray (spec.Next);
8713 type = ArrayContainer.MakeType (type, spec.Dimension);
8716 public override string GetSignatureForError ()
8718 return left.GetSignatureForError () + spec.GetSignatureForError ();
8722 public class FixedBufferPtr : Expression {
8725 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
8730 type = PointerContainer.MakeType (array_type);
8731 eclass = ExprClass.Value;
8734 public override Expression CreateExpressionTree (ResolveContext ec)
8736 Error_PointerInsideExpressionTree (ec);
8740 public override void Emit(EmitContext ec)
8745 protected override Expression DoResolve (ResolveContext ec)
8748 // We are born fully resolved
8756 // This class is used to represent the address of an array, used
8757 // only by the Fixed statement, this generates "&a [0]" construct
8758 // for fixed (char *pa = a)
8760 public class ArrayPtr : FixedBufferPtr {
8761 TypeSpec array_type;
8763 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
8764 base (array, array_type, l)
8766 this.array_type = array_type;
8769 public override void Emit (EmitContext ec)
8774 ec.Emit (OpCodes.Ldelema, array_type);
8779 // Encapsulates a conversion rules required for array indexes
8781 public class ArrayIndexCast : TypeCast
8783 public ArrayIndexCast (Expression expr)
8784 : base (expr, TypeManager.int32_type)
8786 if (expr.Type == TypeManager.int32_type)
8787 throw new ArgumentException ("unnecessary array index conversion");
8790 public override Expression CreateExpressionTree (ResolveContext ec)
8792 using (ec.Set (ResolveContext.Options.CheckedScope)) {
8793 return base.CreateExpressionTree (ec);
8797 public override void Emit (EmitContext ec)
8801 var expr_type = child.Type;
8803 if (expr_type == TypeManager.uint32_type)
8804 ec.Emit (OpCodes.Conv_U);
8805 else if (expr_type == TypeManager.int64_type)
8806 ec.Emit (OpCodes.Conv_Ovf_I);
8807 else if (expr_type == TypeManager.uint64_type)
8808 ec.Emit (OpCodes.Conv_Ovf_I_Un);
8810 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
8815 // Implements the `stackalloc' keyword
8817 public class StackAlloc : Expression {
8822 public StackAlloc (Expression type, Expression count, Location l)
8829 public override Expression CreateExpressionTree (ResolveContext ec)
8831 throw new NotSupportedException ("ET");
8834 protected override Expression DoResolve (ResolveContext ec)
8836 count = count.Resolve (ec);
8840 if (count.Type != TypeManager.uint32_type){
8841 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8846 Constant c = count as Constant;
8847 if (c != null && c.IsNegative) {
8848 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8851 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
8852 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
8855 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8861 if (!TypeManager.VerifyUnmanaged (ec.Compiler, otype, loc))
8864 type = PointerContainer.MakeType (otype);
8865 eclass = ExprClass.Value;
8870 public override void Emit (EmitContext ec)
8872 int size = GetTypeSize (otype);
8877 ec.Emit (OpCodes.Sizeof, otype);
8881 ec.Emit (OpCodes.Mul_Ovf_Un);
8882 ec.Emit (OpCodes.Localloc);
8885 protected override void CloneTo (CloneContext clonectx, Expression t)
8887 StackAlloc target = (StackAlloc) t;
8888 target.count = count.Clone (clonectx);
8889 target.t = t.Clone (clonectx);
8894 // An object initializer expression
8896 public class ElementInitializer : Assign
8898 public readonly string Name;
8900 public ElementInitializer (string name, Expression initializer, Location loc)
8901 : base (null, initializer, loc)
8906 protected override void CloneTo (CloneContext clonectx, Expression t)
8908 ElementInitializer target = (ElementInitializer) t;
8909 target.source = source.Clone (clonectx);
8912 public override Expression CreateExpressionTree (ResolveContext ec)
8914 Arguments args = new Arguments (2);
8915 FieldExpr fe = target as FieldExpr;
8917 args.Add (new Argument (fe.CreateTypeOfExpression ()));
8919 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
8921 args.Add (new Argument (source.CreateExpressionTree (ec)));
8922 return CreateExpressionFactoryCall (ec,
8923 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
8927 protected override Expression DoResolve (ResolveContext ec)
8930 return EmptyExpressionStatement.Instance;
8932 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
8933 Name, 0, MemberKind.Field | MemberKind.Property, BindingRestriction.AccessibleOnly | BindingRestriction.InstanceOnly, loc) as MemberExpr;
8939 me.InstanceExpression = ec.CurrentInitializerVariable;
8941 if (source is CollectionOrObjectInitializers) {
8942 Expression previous = ec.CurrentInitializerVariable;
8943 ec.CurrentInitializerVariable = target;
8944 source = source.Resolve (ec);
8945 ec.CurrentInitializerVariable = previous;
8949 eclass = source.eclass;
8954 return base.DoResolve (ec);
8957 protected override MemberExpr Error_MemberLookupFailed (ResolveContext ec, TypeSpec type, IList<MemberSpec> members)
8959 var member = members.First ();
8960 if (member.Kind != MemberKind.Property && member.Kind != MemberKind.Field)
8961 ec.Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
8962 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
8964 ec.Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
8965 TypeManager.GetFullNameSignature (member));
8970 public override void EmitStatement (EmitContext ec)
8972 if (source is CollectionOrObjectInitializers)
8975 base.EmitStatement (ec);
8980 // A collection initializer expression
8982 class CollectionElementInitializer : Invocation
8984 public class ElementInitializerArgument : Argument
8986 public ElementInitializerArgument (Expression e)
8992 sealed class AddMemberAccess : MemberAccess
8994 public AddMemberAccess (Expression expr, Location loc)
8995 : base (expr, "Add", loc)
8999 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9001 if (TypeManager.HasElementType (type))
9004 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9008 public CollectionElementInitializer (Expression argument)
9009 : base (null, new Arguments (1))
9011 base.arguments.Add (new ElementInitializerArgument (argument));
9012 this.loc = argument.Location;
9015 public CollectionElementInitializer (List<Expression> arguments, Location loc)
9016 : base (null, new Arguments (arguments.Count))
9018 foreach (Expression e in arguments)
9019 base.arguments.Add (new ElementInitializerArgument (e));
9024 public override Expression CreateExpressionTree (ResolveContext ec)
9026 Arguments args = new Arguments (2);
9027 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9029 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
9030 foreach (Argument a in arguments)
9031 expr_initializers.Add (a.CreateExpressionTree (ec));
9033 args.Add (new Argument (new ArrayCreation (
9034 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
9035 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9038 protected override void CloneTo (CloneContext clonectx, Expression t)
9040 CollectionElementInitializer target = (CollectionElementInitializer) t;
9041 if (arguments != null)
9042 target.arguments = arguments.Clone (clonectx);
9045 protected override Expression DoResolve (ResolveContext ec)
9047 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9049 return base.DoResolve (ec);
9054 // A block of object or collection initializers
9056 public class CollectionOrObjectInitializers : ExpressionStatement
9058 IList<Expression> initializers;
9059 bool is_collection_initialization;
9061 public static readonly CollectionOrObjectInitializers Empty =
9062 new CollectionOrObjectInitializers (Array.AsReadOnly (new Expression [0]), Location.Null);
9064 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
9066 this.initializers = initializers;
9070 public bool IsEmpty {
9072 return initializers.Count == 0;
9076 public bool IsCollectionInitializer {
9078 return is_collection_initialization;
9082 protected override void CloneTo (CloneContext clonectx, Expression target)
9084 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9086 t.initializers = new List<Expression> (initializers.Count);
9087 foreach (var e in initializers)
9088 t.initializers.Add (e.Clone (clonectx));
9091 public override Expression CreateExpressionTree (ResolveContext ec)
9093 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
9094 foreach (Expression e in initializers) {
9095 Expression expr = e.CreateExpressionTree (ec);
9097 expr_initializers.Add (expr);
9100 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
9103 protected override Expression DoResolve (ResolveContext ec)
9105 List<string> element_names = null;
9106 for (int i = 0; i < initializers.Count; ++i) {
9107 Expression initializer = initializers [i];
9108 ElementInitializer element_initializer = initializer as ElementInitializer;
9111 if (element_initializer != null) {
9112 element_names = new List<string> (initializers.Count);
9113 element_names.Add (element_initializer.Name);
9114 } else if (initializer is CompletingExpression){
9115 initializer.Resolve (ec);
9116 throw new InternalErrorException ("This line should never be reached");
9118 if (!ec.CurrentInitializerVariable.Type.ImplementsInterface (TypeManager.ienumerable_type)) {
9119 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9120 "object initializer because type `{1}' does not implement `{2}' interface",
9121 ec.CurrentInitializerVariable.GetSignatureForError (),
9122 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9123 TypeManager.CSharpName (TypeManager.ienumerable_type));
9126 is_collection_initialization = true;
9129 if (is_collection_initialization != (element_initializer == null)) {
9130 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9131 is_collection_initialization ? "collection initializer" : "object initializer");
9135 if (!is_collection_initialization) {
9136 if (element_names.Contains (element_initializer.Name)) {
9137 ec.Report.Error (1912, element_initializer.Location,
9138 "An object initializer includes more than one member `{0}' initialization",
9139 element_initializer.Name);
9141 element_names.Add (element_initializer.Name);
9146 Expression e = initializer.Resolve (ec);
9147 if (e == EmptyExpressionStatement.Instance)
9148 initializers.RemoveAt (i--);
9150 initializers [i] = e;
9153 type = ec.CurrentInitializerVariable.Type;
9154 if (is_collection_initialization) {
9155 if (TypeManager.HasElementType (type)) {
9156 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9157 TypeManager.CSharpName (type));
9161 eclass = ExprClass.Variable;
9165 public override void Emit (EmitContext ec)
9170 public override void EmitStatement (EmitContext ec)
9172 foreach (ExpressionStatement e in initializers)
9173 e.EmitStatement (ec);
9178 // New expression with element/object initializers
9180 public class NewInitialize : New
9183 // This class serves as a proxy for variable initializer target instances.
9184 // A real variable is assigned later when we resolve left side of an
9187 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9189 NewInitialize new_instance;
9191 public InitializerTargetExpression (NewInitialize newInstance)
9193 this.type = newInstance.type;
9194 this.loc = newInstance.loc;
9195 this.eclass = newInstance.eclass;
9196 this.new_instance = newInstance;
9199 public override Expression CreateExpressionTree (ResolveContext ec)
9201 // Should not be reached
9202 throw new NotSupportedException ("ET");
9205 protected override Expression DoResolve (ResolveContext ec)
9210 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9215 public override void Emit (EmitContext ec)
9217 Expression e = (Expression) new_instance.instance;
9221 #region IMemoryLocation Members
9223 public void AddressOf (EmitContext ec, AddressOp mode)
9225 new_instance.instance.AddressOf (ec, mode);
9231 CollectionOrObjectInitializers initializers;
9232 IMemoryLocation instance;
9234 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9235 : base (requested_type, arguments, l)
9237 this.initializers = initializers;
9240 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9242 instance = base.EmitAddressOf (ec, Mode);
9244 if (!initializers.IsEmpty)
9245 initializers.Emit (ec);
9250 protected override void CloneTo (CloneContext clonectx, Expression t)
9252 base.CloneTo (clonectx, t);
9254 NewInitialize target = (NewInitialize) t;
9255 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9258 public override Expression CreateExpressionTree (ResolveContext ec)
9260 Arguments args = new Arguments (2);
9261 args.Add (new Argument (base.CreateExpressionTree (ec)));
9262 if (!initializers.IsEmpty)
9263 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9265 return CreateExpressionFactoryCall (ec,
9266 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9270 protected override Expression DoResolve (ResolveContext ec)
9272 Expression e = base.DoResolve (ec);
9276 Expression previous = ec.CurrentInitializerVariable;
9277 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9278 initializers.Resolve (ec);
9279 ec.CurrentInitializerVariable = previous;
9283 public override bool Emit (EmitContext ec, IMemoryLocation target)
9285 bool left_on_stack = base.Emit (ec, target);
9287 if (initializers.IsEmpty)
9288 return left_on_stack;
9290 LocalTemporary temp = target as LocalTemporary;
9292 if (!left_on_stack) {
9293 VariableReference vr = target as VariableReference;
9295 // FIXME: This still does not work correctly for pre-set variables
9296 if (vr != null && vr.IsRef)
9297 target.AddressOf (ec, AddressOp.Load);
9299 ((Expression) target).Emit (ec);
9300 left_on_stack = true;
9303 temp = new LocalTemporary (type);
9310 initializers.Emit (ec);
9312 if (left_on_stack) {
9317 return left_on_stack;
9320 public override bool HasInitializer {
9322 return !initializers.IsEmpty;
9327 public class NewAnonymousType : New
9329 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
9331 List<AnonymousTypeParameter> parameters;
9332 readonly TypeContainer parent;
9333 AnonymousTypeClass anonymous_type;
9335 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
9336 : base (null, null, loc)
9338 this.parameters = parameters;
9339 this.parent = parent;
9342 protected override void CloneTo (CloneContext clonectx, Expression target)
9344 if (parameters == null)
9347 NewAnonymousType t = (NewAnonymousType) target;
9348 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
9349 foreach (AnonymousTypeParameter atp in parameters)
9350 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
9353 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
9355 AnonymousTypeClass type = parent.Module.Compiled.GetAnonymousType (parameters);
9359 type = AnonymousTypeClass.Create (ec.Compiler, parent, parameters, loc);
9365 type.ResolveTypeParameters ();
9368 if (ec.Report.Errors == 0)
9371 parent.Module.Compiled.AddAnonymousType (type);
9375 public override Expression CreateExpressionTree (ResolveContext ec)
9377 if (parameters == null)
9378 return base.CreateExpressionTree (ec);
9380 var init = new ArrayInitializer (parameters.Count, loc);
9381 foreach (Property p in anonymous_type.Properties)
9382 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
9384 var ctor_args = new ArrayInitializer (Arguments.Count, loc);
9385 foreach (Argument a in Arguments)
9386 ctor_args.Add (a.CreateExpressionTree (ec));
9388 Arguments args = new Arguments (3);
9389 args.Add (new Argument (method.CreateExpressionTree (ec)));
9390 args.Add (new Argument (new ArrayCreation (TypeManager.expression_type_expr, ctor_args, loc)));
9391 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
9393 return CreateExpressionFactoryCall (ec, "New", args);
9396 protected override Expression DoResolve (ResolveContext ec)
9398 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
9399 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9403 if (parameters == null) {
9404 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
9405 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
9406 return base.DoResolve (ec);
9410 Arguments = new Arguments (parameters.Count);
9411 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9412 for (int i = 0; i < parameters.Count; ++i) {
9413 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9419 Arguments.Add (new Argument (e));
9420 t_args [i] = new TypeExpression (e.Type, e.Location);
9426 anonymous_type = CreateAnonymousType (ec, parameters);
9427 if (anonymous_type == null)
9430 RequestedType = new GenericTypeExpr (anonymous_type.Definition, new TypeArguments (t_args), loc);
9431 return base.DoResolve (ec);
9435 public class AnonymousTypeParameter : ShimExpression
9437 public readonly string Name;
9439 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9440 : base (initializer)
9446 public AnonymousTypeParameter (Parameter parameter)
9447 : base (new SimpleName (parameter.Name, parameter.Location))
9449 this.Name = parameter.Name;
9450 this.loc = parameter.Location;
9453 public override bool Equals (object o)
9455 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9456 return other != null && Name == other.Name;
9459 public override int GetHashCode ()
9461 return Name.GetHashCode ();
9464 protected override Expression DoResolve (ResolveContext ec)
9466 Expression e = expr.Resolve (ec);
9470 if (e.eclass == ExprClass.MethodGroup) {
9471 Error_InvalidInitializer (ec, e.ExprClassName);
9476 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9477 type == InternalType.AnonymousMethod || type.IsPointer) {
9478 Error_InvalidInitializer (ec, e.GetSignatureForError ());
9485 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
9487 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",