* xbuild/Microsoft.Common.targets: For referenced projects,
[mcs.git] / mcs / expression.cs
blob25f141cc05457ed5d2cfd2f2a6b2d266325a107f
1 //
2 // expression.cs: Expression representation for the IL tree.
3 //
4 // Author:
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
7 //
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
11 #define USE_OLD
13 namespace Mono.CSharp {
14 using System;
15 using System.Collections;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Text;
20 #if NET_4_0
21 using SLE = System.Linq.Expressions;
22 #endif
25 // This is an user operator expression, automatically created during
26 // resolve phase
28 public class UserOperatorCall : Expression {
29 public delegate Expression ExpressionTreeExpression (ResolveContext ec, MethodGroupExpr mg);
31 protected readonly Arguments arguments;
32 protected readonly MethodGroupExpr mg;
33 readonly ExpressionTreeExpression expr_tree;
35 public UserOperatorCall (MethodGroupExpr mg, Arguments args, ExpressionTreeExpression expr_tree, Location loc)
37 this.mg = mg;
38 this.arguments = args;
39 this.expr_tree = expr_tree;
41 type = TypeManager.TypeToCoreType (((MethodInfo) mg).ReturnType);
42 eclass = ExprClass.Value;
43 this.loc = loc;
46 public override Expression CreateExpressionTree (ResolveContext ec)
48 if (expr_tree != null)
49 return expr_tree (ec, mg);
51 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
52 new NullLiteral (loc),
53 mg.CreateExpressionTree (ec));
55 return CreateExpressionFactoryCall (ec, "Call", args);
58 protected override void CloneTo (CloneContext context, Expression target)
60 // Nothing to clone
63 public override Expression DoResolve (ResolveContext ec)
66 // We are born fully resolved
68 return this;
71 public override void Emit (EmitContext ec)
73 mg.EmitCall (ec, arguments);
76 #if NET_4_0
77 public override SLE.Expression MakeExpression (BuilderContext ctx)
79 return SLE.Expression.Call ((MethodInfo) mg, Arguments.MakeExpression (arguments, ctx));
81 #endif
83 public MethodGroupExpr Method {
84 get { return mg; }
87 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
89 arguments.MutateHoistedGenericType (storey);
90 mg.MutateHoistedGenericType (storey);
94 public class ParenthesizedExpression : ShimExpression
96 public ParenthesizedExpression (Expression expr)
97 : base (expr)
99 loc = expr.Location;
102 public override Expression DoResolve (ResolveContext ec)
104 return expr.Resolve (ec);
107 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
109 return expr.DoResolveLValue (ec, right_side);
114 // Unary implements unary expressions.
116 public class Unary : Expression
118 public enum Operator : byte {
119 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
120 AddressOf, TOP
123 static Type [] [] predefined_operators;
125 public readonly Operator Oper;
126 public Expression Expr;
127 Expression enum_conversion;
129 public Unary (Operator op, Expression expr)
131 Oper = op;
132 Expr = expr;
133 loc = expr.Location;
136 // <summary>
137 // This routine will attempt to simplify the unary expression when the
138 // argument is a constant.
139 // </summary>
140 Constant TryReduceConstant (ResolveContext ec, Constant e)
142 if (e is EmptyConstantCast)
143 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
145 if (e is SideEffectConstant) {
146 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
147 return r == null ? null : new SideEffectConstant (r, e, r.Location);
150 Type expr_type = e.Type;
152 switch (Oper){
153 case Operator.UnaryPlus:
154 // Unary numeric promotions
155 if (expr_type == TypeManager.byte_type)
156 return new IntConstant (((ByteConstant)e).Value, e.Location);
157 if (expr_type == TypeManager.sbyte_type)
158 return new IntConstant (((SByteConstant)e).Value, e.Location);
159 if (expr_type == TypeManager.short_type)
160 return new IntConstant (((ShortConstant)e).Value, e.Location);
161 if (expr_type == TypeManager.ushort_type)
162 return new IntConstant (((UShortConstant)e).Value, e.Location);
163 if (expr_type == TypeManager.char_type)
164 return new IntConstant (((CharConstant)e).Value, e.Location);
166 // Predefined operators
167 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
168 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
169 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
170 expr_type == TypeManager.decimal_type) {
171 return e;
174 return null;
176 case Operator.UnaryNegation:
177 // Unary numeric promotions
178 if (expr_type == TypeManager.byte_type)
179 return new IntConstant (-((ByteConstant)e).Value, e.Location);
180 if (expr_type == TypeManager.sbyte_type)
181 return new IntConstant (-((SByteConstant)e).Value, e.Location);
182 if (expr_type == TypeManager.short_type)
183 return new IntConstant (-((ShortConstant)e).Value, e.Location);
184 if (expr_type == TypeManager.ushort_type)
185 return new IntConstant (-((UShortConstant)e).Value, e.Location);
186 if (expr_type == TypeManager.char_type)
187 return new IntConstant (-((CharConstant)e).Value, e.Location);
189 // Predefined operators
190 if (expr_type == TypeManager.int32_type) {
191 int value = ((IntConstant)e).Value;
192 if (value == int.MinValue) {
193 if (ec.ConstantCheckState) {
194 ConstantFold.Error_CompileTimeOverflow (ec, loc);
195 return null;
197 return e;
199 return new IntConstant (-value, e.Location);
201 if (expr_type == TypeManager.int64_type) {
202 long value = ((LongConstant)e).Value;
203 if (value == long.MinValue) {
204 if (ec.ConstantCheckState) {
205 ConstantFold.Error_CompileTimeOverflow (ec, loc);
206 return null;
208 return e;
210 return new LongConstant (-value, e.Location);
213 if (expr_type == TypeManager.uint32_type) {
214 UIntLiteral uil = e as UIntLiteral;
215 if (uil != null) {
216 if (uil.Value == 2147483648)
217 return new IntLiteral (int.MinValue, e.Location);
218 return new LongLiteral (-uil.Value, e.Location);
220 return new LongConstant (-((UIntConstant)e).Value, e.Location);
223 if (expr_type == TypeManager.uint64_type) {
224 ULongLiteral ull = e as ULongLiteral;
225 if (ull != null && ull.Value == 9223372036854775808)
226 return new LongLiteral (long.MinValue, e.Location);
227 return null;
230 if (expr_type == TypeManager.float_type) {
231 FloatLiteral fl = e as FloatLiteral;
232 // For better error reporting
233 if (fl != null)
234 return new FloatLiteral (-fl.Value, e.Location);
236 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
238 if (expr_type == TypeManager.double_type) {
239 DoubleLiteral dl = e as DoubleLiteral;
240 // For better error reporting
241 if (dl != null)
242 return new DoubleLiteral (-dl.Value, e.Location);
244 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
246 if (expr_type == TypeManager.decimal_type)
247 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
249 return null;
251 case Operator.LogicalNot:
252 if (expr_type != TypeManager.bool_type)
253 return null;
255 bool b = (bool)e.GetValue ();
256 return new BoolConstant (!b, e.Location);
258 case Operator.OnesComplement:
259 // Unary numeric promotions
260 if (expr_type == TypeManager.byte_type)
261 return new IntConstant (~((ByteConstant)e).Value, e.Location);
262 if (expr_type == TypeManager.sbyte_type)
263 return new IntConstant (~((SByteConstant)e).Value, e.Location);
264 if (expr_type == TypeManager.short_type)
265 return new IntConstant (~((ShortConstant)e).Value, e.Location);
266 if (expr_type == TypeManager.ushort_type)
267 return new IntConstant (~((UShortConstant)e).Value, e.Location);
268 if (expr_type == TypeManager.char_type)
269 return new IntConstant (~((CharConstant)e).Value, e.Location);
271 // Predefined operators
272 if (expr_type == TypeManager.int32_type)
273 return new IntConstant (~((IntConstant)e).Value, e.Location);
274 if (expr_type == TypeManager.uint32_type)
275 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
276 if (expr_type == TypeManager.int64_type)
277 return new LongConstant (~((LongConstant)e).Value, e.Location);
278 if (expr_type == TypeManager.uint64_type){
279 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
281 if (e is EnumConstant) {
282 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
283 if (e != null)
284 e = new EnumConstant (e, expr_type);
285 return e;
287 return null;
289 throw new Exception ("Can not constant fold: " + Oper.ToString());
292 protected Expression ResolveOperator (ResolveContext ec, Expression expr)
294 eclass = ExprClass.Value;
296 if (predefined_operators == null)
297 CreatePredefinedOperatorsTable ();
299 Type expr_type = expr.Type;
300 Expression best_expr;
303 // Primitive types first
305 if (TypeManager.IsPrimitiveType (expr_type)) {
306 best_expr = ResolvePrimitivePredefinedType (expr);
307 if (best_expr == null)
308 return null;
310 type = best_expr.Type;
311 Expr = best_expr;
312 return this;
316 // E operator ~(E x);
318 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
319 return ResolveEnumOperator (ec, expr);
321 return ResolveUserType (ec, expr);
324 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr)
326 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
327 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
328 if (best_expr == null)
329 return null;
331 Expr = best_expr;
332 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
333 type = expr.Type;
334 return EmptyCast.Create (this, type);
337 public override Expression CreateExpressionTree (ResolveContext ec)
339 return CreateExpressionTree (ec, null);
342 Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr user_op)
344 string method_name;
345 switch (Oper) {
346 case Operator.AddressOf:
347 Error_PointerInsideExpressionTree (ec);
348 return null;
349 case Operator.UnaryNegation:
350 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
351 method_name = "NegateChecked";
352 else
353 method_name = "Negate";
354 break;
355 case Operator.OnesComplement:
356 case Operator.LogicalNot:
357 method_name = "Not";
358 break;
359 case Operator.UnaryPlus:
360 method_name = "UnaryPlus";
361 break;
362 default:
363 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
366 Arguments args = new Arguments (2);
367 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
368 if (user_op != null)
369 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
370 return CreateExpressionFactoryCall (ec, method_name, args);
373 static void CreatePredefinedOperatorsTable ()
375 predefined_operators = new Type [(int) Operator.TOP] [];
378 // 7.6.1 Unary plus operator
380 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
381 TypeManager.int32_type, TypeManager.uint32_type,
382 TypeManager.int64_type, TypeManager.uint64_type,
383 TypeManager.float_type, TypeManager.double_type,
384 TypeManager.decimal_type
388 // 7.6.2 Unary minus operator
390 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
391 TypeManager.int32_type,
392 TypeManager.int64_type,
393 TypeManager.float_type, TypeManager.double_type,
394 TypeManager.decimal_type
398 // 7.6.3 Logical negation operator
400 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
401 TypeManager.bool_type
405 // 7.6.4 Bitwise complement operator
407 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
408 TypeManager.int32_type, TypeManager.uint32_type,
409 TypeManager.int64_type, TypeManager.uint64_type
414 // Unary numeric promotions
416 static Expression DoNumericPromotion (Operator op, Expression expr)
418 Type expr_type = expr.Type;
419 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
420 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
421 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
422 expr_type == TypeManager.char_type)
423 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
425 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
426 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
428 return expr;
431 public override Expression DoResolve (ResolveContext ec)
433 if (Oper == Operator.AddressOf) {
434 return ResolveAddressOf (ec);
437 Expr = Expr.Resolve (ec);
438 if (Expr == null)
439 return null;
441 if (TypeManager.IsDynamicType (Expr.Type)) {
442 Arguments args = new Arguments (1);
443 args.Add (new Argument (Expr));
444 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
447 if (TypeManager.IsNullableType (Expr.Type))
448 return new Nullable.LiftedUnaryOperator (Oper, Expr).Resolve (ec);
451 // Attempt to use a constant folding operation.
453 Constant cexpr = Expr as Constant;
454 if (cexpr != null) {
455 cexpr = TryReduceConstant (ec, cexpr);
456 if (cexpr != null)
457 return cexpr;
460 Expression expr = ResolveOperator (ec, Expr);
461 if (expr == null)
462 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
465 // Reduce unary operator on predefined types
467 if (expr == this && Oper == Operator.UnaryPlus)
468 return Expr;
470 return expr;
473 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
475 return null;
478 public override void Emit (EmitContext ec)
480 EmitOperator (ec, type);
483 protected void EmitOperator (EmitContext ec, Type type)
485 ILGenerator ig = ec.ig;
487 switch (Oper) {
488 case Operator.UnaryPlus:
489 Expr.Emit (ec);
490 break;
492 case Operator.UnaryNegation:
493 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
494 ig.Emit (OpCodes.Ldc_I4_0);
495 if (type == TypeManager.int64_type)
496 ig.Emit (OpCodes.Conv_U8);
497 Expr.Emit (ec);
498 ig.Emit (OpCodes.Sub_Ovf);
499 } else {
500 Expr.Emit (ec);
501 ig.Emit (OpCodes.Neg);
504 break;
506 case Operator.LogicalNot:
507 Expr.Emit (ec);
508 ig.Emit (OpCodes.Ldc_I4_0);
509 ig.Emit (OpCodes.Ceq);
510 break;
512 case Operator.OnesComplement:
513 Expr.Emit (ec);
514 ig.Emit (OpCodes.Not);
515 break;
517 case Operator.AddressOf:
518 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
519 break;
521 default:
522 throw new Exception ("This should not happen: Operator = "
523 + Oper.ToString ());
527 // Same trick as in Binary expression
529 if (enum_conversion != null)
530 enum_conversion.Emit (ec);
533 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
535 if (Oper == Operator.LogicalNot)
536 Expr.EmitBranchable (ec, target, !on_true);
537 else
538 base.EmitBranchable (ec, target, on_true);
541 public override void EmitSideEffect (EmitContext ec)
543 Expr.EmitSideEffect (ec);
546 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Location loc, string oper, Type t)
548 ec.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
549 oper, TypeManager.CSharpName (t));
553 // Converts operator to System.Linq.Expressions.ExpressionType enum name
555 string GetOperatorExpressionTypeName ()
557 switch (Oper) {
558 case Operator.OnesComplement:
559 return "OnesComplement";
560 case Operator.LogicalNot:
561 return "Not";
562 case Operator.UnaryNegation:
563 return "Negate";
564 case Operator.UnaryPlus:
565 return "UnaryPlus";
566 default:
567 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
571 static bool IsFloat (Type t)
573 return t == TypeManager.float_type || t == TypeManager.double_type;
577 // Returns a stringified representation of the Operator
579 public static string OperName (Operator oper)
581 switch (oper) {
582 case Operator.UnaryPlus:
583 return "+";
584 case Operator.UnaryNegation:
585 return "-";
586 case Operator.LogicalNot:
587 return "!";
588 case Operator.OnesComplement:
589 return "~";
590 case Operator.AddressOf:
591 return "&";
594 throw new NotImplementedException (oper.ToString ());
597 #if NET_4_0
598 public override SLE.Expression MakeExpression (BuilderContext ctx)
600 var expr = Expr.MakeExpression (ctx);
601 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
603 switch (Oper) {
604 case Operator.UnaryNegation:
605 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
606 case Operator.LogicalNot:
607 return SLE.Expression.Not (expr);
608 case Operator.OnesComplement:
609 return SLE.Expression.OnesComplement (expr);
610 default:
611 throw new NotImplementedException (Oper.ToString ());
614 #endif
616 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
618 type = storey.MutateType (type);
619 Expr.MutateHoistedGenericType (storey);
622 Expression ResolveAddressOf (ResolveContext ec)
624 if (!ec.IsUnsafe)
625 UnsafeError (ec, loc);
627 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
628 if (Expr == null || Expr.eclass != ExprClass.Variable) {
629 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
630 return null;
633 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
634 return null;
637 IVariableReference vr = Expr as IVariableReference;
638 bool is_fixed;
639 if (vr != null) {
640 VariableInfo vi = vr.VariableInfo;
641 if (vi != null) {
642 if (vi.LocalInfo != null)
643 vi.LocalInfo.Used = true;
646 // A variable is considered definitely assigned if you take its address.
648 vi.SetAssigned (ec);
651 is_fixed = vr.IsFixed;
652 vr.SetHasAddressTaken ();
654 if (vr.IsHoisted) {
655 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
657 } else {
658 IFixedExpression fe = Expr as IFixedExpression;
659 is_fixed = fe != null && fe.IsFixed;
662 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
663 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
666 type = TypeManager.GetPointerType (Expr.Type);
667 eclass = ExprClass.Value;
668 return this;
671 Expression ResolvePrimitivePredefinedType (Expression expr)
673 expr = DoNumericPromotion (Oper, expr);
674 Type expr_type = expr.Type;
675 Type[] predefined = predefined_operators [(int) Oper];
676 foreach (Type t in predefined) {
677 if (t == expr_type)
678 return expr;
680 return null;
684 // Perform user-operator overload resolution
686 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
688 CSharp.Operator.OpType op_type;
689 switch (Oper) {
690 case Operator.LogicalNot:
691 op_type = CSharp.Operator.OpType.LogicalNot; break;
692 case Operator.OnesComplement:
693 op_type = CSharp.Operator.OpType.OnesComplement; break;
694 case Operator.UnaryNegation:
695 op_type = CSharp.Operator.OpType.UnaryNegation; break;
696 case Operator.UnaryPlus:
697 op_type = CSharp.Operator.OpType.UnaryPlus; break;
698 default:
699 throw new InternalErrorException (Oper.ToString ());
702 string op_name = CSharp.Operator.GetMetadataName (op_type);
703 MethodGroupExpr user_op = MemberLookup (ec.Compiler, ec.CurrentType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
704 if (user_op == null)
705 return null;
707 Arguments args = new Arguments (1);
708 args.Add (new Argument (expr));
709 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
711 if (user_op == null)
712 return null;
714 Expr = args [0].Expr;
715 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
719 // Unary user type overload resolution
721 Expression ResolveUserType (ResolveContext ec, Expression expr)
723 Expression best_expr = ResolveUserOperator (ec, expr);
724 if (best_expr != null)
725 return best_expr;
727 Type[] predefined = predefined_operators [(int) Oper];
728 foreach (Type t in predefined) {
729 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
730 if (oper_expr == null)
731 continue;
734 // decimal type is predefined but has user-operators
736 if (oper_expr.Type == TypeManager.decimal_type)
737 oper_expr = ResolveUserType (ec, oper_expr);
738 else
739 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
741 if (oper_expr == null)
742 continue;
744 if (best_expr == null) {
745 best_expr = oper_expr;
746 continue;
749 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
750 if (result == 0) {
751 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
752 OperName (Oper), TypeManager.CSharpName (expr.Type));
753 break;
756 if (result == 2)
757 best_expr = oper_expr;
760 if (best_expr == null)
761 return null;
764 // HACK: Decimal user-operator is included in standard operators
766 if (best_expr.Type == TypeManager.decimal_type)
767 return best_expr;
769 Expr = best_expr;
770 type = best_expr.Type;
771 return this;
774 protected override void CloneTo (CloneContext clonectx, Expression t)
776 Unary target = (Unary) t;
778 target.Expr = Expr.Clone (clonectx);
783 // Unary operators are turned into Indirection expressions
784 // after semantic analysis (this is so we can take the address
785 // of an indirection).
787 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
788 Expression expr;
789 LocalTemporary temporary;
790 bool prepared;
792 public Indirection (Expression expr, Location l)
794 this.expr = expr;
795 loc = l;
798 public override Expression CreateExpressionTree (ResolveContext ec)
800 Error_PointerInsideExpressionTree (ec);
801 return null;
804 protected override void CloneTo (CloneContext clonectx, Expression t)
806 Indirection target = (Indirection) t;
807 target.expr = expr.Clone (clonectx);
810 public override void Emit (EmitContext ec)
812 if (!prepared)
813 expr.Emit (ec);
815 LoadFromPtr (ec.ig, Type);
818 public void Emit (EmitContext ec, bool leave_copy)
820 Emit (ec);
821 if (leave_copy) {
822 ec.ig.Emit (OpCodes.Dup);
823 temporary = new LocalTemporary (expr.Type);
824 temporary.Store (ec);
828 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
830 prepared = prepare_for_load;
832 expr.Emit (ec);
834 if (prepare_for_load)
835 ec.ig.Emit (OpCodes.Dup);
837 source.Emit (ec);
838 if (leave_copy) {
839 ec.ig.Emit (OpCodes.Dup);
840 temporary = new LocalTemporary (expr.Type);
841 temporary.Store (ec);
844 StoreFromPtr (ec.ig, type);
846 if (temporary != null) {
847 temporary.Emit (ec);
848 temporary.Release (ec);
852 public void AddressOf (EmitContext ec, AddressOp Mode)
854 expr.Emit (ec);
857 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
859 return DoResolve (ec);
862 public override Expression DoResolve (ResolveContext ec)
864 expr = expr.Resolve (ec);
865 if (expr == null)
866 return null;
868 if (!ec.IsUnsafe)
869 UnsafeError (ec, loc);
871 if (!expr.Type.IsPointer) {
872 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
873 return null;
876 if (expr.Type == TypeManager.void_ptr_type) {
877 ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
878 return null;
881 type = TypeManager.GetElementType (expr.Type);
882 eclass = ExprClass.Variable;
883 return this;
886 public bool IsFixed {
887 get { return true; }
890 public override string ToString ()
892 return "*(" + expr + ")";
896 /// <summary>
897 /// Unary Mutator expressions (pre and post ++ and --)
898 /// </summary>
900 /// <remarks>
901 /// UnaryMutator implements ++ and -- expressions. It derives from
902 /// ExpressionStatement becuase the pre/post increment/decrement
903 /// operators can be used in a statement context.
905 /// FIXME: Idea, we could split this up in two classes, one simpler
906 /// for the common case, and one with the extra fields for more complex
907 /// classes (indexers require temporary access; overloaded require method)
909 /// </remarks>
910 public class UnaryMutator : ExpressionStatement {
911 [Flags]
912 public enum Mode : byte {
913 IsIncrement = 0,
914 IsDecrement = 1,
915 IsPre = 0,
916 IsPost = 2,
918 PreIncrement = 0,
919 PreDecrement = IsDecrement,
920 PostIncrement = IsPost,
921 PostDecrement = IsPost | IsDecrement
924 Mode mode;
925 bool is_expr = false;
926 bool recurse = false;
928 Expression expr;
931 // This is expensive for the simplest case.
933 UserOperatorCall method;
935 public UnaryMutator (Mode m, Expression e)
937 mode = m;
938 loc = e.Location;
939 expr = e;
942 string OperName ()
944 return IsDecrement ?
945 Operator.GetName (Operator.OpType.Decrement) :
946 Operator.GetName (Operator.OpType.Increment);
949 /// <summary>
950 /// Returns whether an object of type `t' can be incremented
951 /// or decremented with add/sub (ie, basically whether we can
952 /// use pre-post incr-decr operations on it, but it is not a
953 /// System.Decimal, which we require operator overloading to catch)
954 /// </summary>
955 static bool IsIncrementableNumber (Type t)
957 return (t == TypeManager.sbyte_type) ||
958 (t == TypeManager.byte_type) ||
959 (t == TypeManager.short_type) ||
960 (t == TypeManager.ushort_type) ||
961 (t == TypeManager.int32_type) ||
962 (t == TypeManager.uint32_type) ||
963 (t == TypeManager.int64_type) ||
964 (t == TypeManager.uint64_type) ||
965 (t == TypeManager.char_type) ||
966 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
967 (t == TypeManager.float_type) ||
968 (t == TypeManager.double_type) ||
969 (t.IsPointer && t != TypeManager.void_ptr_type);
972 Expression ResolveOperator (ResolveContext ec)
974 type = expr.Type;
977 // The operand of the prefix/postfix increment decrement operators
978 // should be an expression that is classified as a variable,
979 // a property access or an indexer access
981 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
982 expr = expr.ResolveLValue (ec, expr);
983 } else {
984 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
988 // Step 1: Perform Operator Overload location
990 MethodGroupExpr mg;
991 string op_name;
993 if (IsDecrement)
994 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
995 else
996 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
998 mg = MemberLookup (ec.Compiler, ec.CurrentType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1000 if (mg != null) {
1001 Arguments args = new Arguments (1);
1002 args.Add (new Argument (expr));
1003 mg = mg.OverloadResolve (ec, ref args, false, loc);
1004 if (mg == null)
1005 return null;
1007 method = new UserOperatorCall (mg, args, null, loc);
1008 Convert.ImplicitConversionRequired (ec, method, type, loc);
1009 return this;
1012 if (!IsIncrementableNumber (type)) {
1013 ec.Report.Error (187, loc, "No such operator '" + OperName () + "' defined for type '" +
1014 TypeManager.CSharpName (type) + "'");
1015 return null;
1018 return this;
1021 public override Expression CreateExpressionTree (ResolveContext ec)
1023 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1026 public override Expression DoResolve (ResolveContext ec)
1028 expr = expr.Resolve (ec);
1030 if (expr == null)
1031 return null;
1033 if (TypeManager.IsDynamicType (expr.Type)) {
1034 Arguments args = new Arguments (1);
1035 args.Add (new Argument (expr));
1036 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
1039 eclass = ExprClass.Value;
1041 if (TypeManager.IsNullableType (expr.Type))
1042 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1044 return ResolveOperator (ec);
1048 // Loads the proper "1" into the stack based on the type, then it emits the
1049 // opcode for the operation requested
1051 void LoadOneAndEmitOp (EmitContext ec, Type t)
1054 // Measure if getting the typecode and using that is more/less efficient
1055 // that comparing types. t.GetTypeCode() is an internal call.
1057 ILGenerator ig = ec.ig;
1059 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1060 LongConstant.EmitLong (ig, 1);
1061 else if (t == TypeManager.double_type)
1062 ig.Emit (OpCodes.Ldc_R8, 1.0);
1063 else if (t == TypeManager.float_type)
1064 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1065 else if (t.IsPointer){
1066 Type et = TypeManager.GetElementType (t);
1067 int n = GetTypeSize (et);
1069 if (n == 0)
1070 ig.Emit (OpCodes.Sizeof, et);
1071 else {
1072 IntConstant.EmitInt (ig, n);
1073 ig.Emit (OpCodes.Conv_I);
1075 } else
1076 ig.Emit (OpCodes.Ldc_I4_1);
1079 // Now emit the operation
1082 Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1083 Binary.EmitOperatorOpcode (ec, op, t);
1085 if (t == TypeManager.sbyte_type){
1086 if (ec.HasSet (EmitContext.Options.CheckedScope))
1087 ig.Emit (OpCodes.Conv_Ovf_I1);
1088 else
1089 ig.Emit (OpCodes.Conv_I1);
1090 } else if (t == TypeManager.byte_type){
1091 if (ec.HasSet (EmitContext.Options.CheckedScope))
1092 ig.Emit (OpCodes.Conv_Ovf_U1);
1093 else
1094 ig.Emit (OpCodes.Conv_U1);
1095 } else if (t == TypeManager.short_type){
1096 if (ec.HasSet (EmitContext.Options.CheckedScope))
1097 ig.Emit (OpCodes.Conv_Ovf_I2);
1098 else
1099 ig.Emit (OpCodes.Conv_I2);
1100 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1101 if (ec.HasSet (EmitContext.Options.CheckedScope))
1102 ig.Emit (OpCodes.Conv_Ovf_U2);
1103 else
1104 ig.Emit (OpCodes.Conv_U2);
1109 void EmitCode (EmitContext ec, bool is_expr)
1111 recurse = true;
1112 this.is_expr = is_expr;
1113 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1116 public override void Emit (EmitContext ec)
1119 // We use recurse to allow ourselfs to be the source
1120 // of an assignment. This little hack prevents us from
1121 // having to allocate another expression
1123 if (recurse) {
1124 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1125 if (method == null)
1126 LoadOneAndEmitOp (ec, expr.Type);
1127 else
1128 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1129 recurse = false;
1130 return;
1133 EmitCode (ec, true);
1136 public override void EmitStatement (EmitContext ec)
1138 EmitCode (ec, false);
1142 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1144 string GetOperatorExpressionTypeName ()
1146 return IsDecrement ? "Decrement" : "Increment";
1149 bool IsDecrement {
1150 get { return (mode & Mode.IsDecrement) != 0; }
1153 #if NET_4_0
1154 public override SLE.Expression MakeExpression (BuilderContext ctx)
1156 if (method != null)
1157 return method.MakeExpression (ctx);
1159 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
1160 var one = SLE.Expression.Constant (1);
1161 var left = expr.MakeExpression (ctx);
1163 SLE.Expression binary;
1164 if (IsDecrement) {
1165 binary = is_checked ? SLE.Expression.SubtractChecked (left, one) : SLE.Expression.Subtract (left, one);
1166 } else {
1167 binary = is_checked ? SLE.Expression.AddChecked (left, one) : SLE.Expression.Add (left, one);
1170 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1171 binary = SLE.Expression.Convert (binary, target.Type);
1173 return SLE.Expression.Assign (target, binary);
1175 #endif
1177 protected override void CloneTo (CloneContext clonectx, Expression t)
1179 UnaryMutator target = (UnaryMutator) t;
1181 target.expr = expr.Clone (clonectx);
1185 /// <summary>
1186 /// Base class for the `Is' and `As' classes.
1187 /// </summary>
1189 /// <remarks>
1190 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1191 /// size.
1192 /// </remarks>
1193 public abstract class Probe : Expression {
1194 public Expression ProbeType;
1195 protected Expression expr;
1196 protected TypeExpr probe_type_expr;
1198 public Probe (Expression expr, Expression probe_type, Location l)
1200 ProbeType = probe_type;
1201 loc = l;
1202 this.expr = expr;
1205 public Expression Expr {
1206 get {
1207 return expr;
1211 public override Expression DoResolve (ResolveContext ec)
1213 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1214 if (probe_type_expr == null)
1215 return null;
1217 expr = expr.Resolve (ec);
1218 if (expr == null)
1219 return null;
1221 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1222 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1223 OperatorName);
1226 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1227 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1228 OperatorName);
1229 return null;
1232 if (expr.Type == InternalType.AnonymousMethod) {
1233 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1234 OperatorName);
1235 return null;
1238 return this;
1241 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1243 expr.MutateHoistedGenericType (storey);
1244 probe_type_expr.MutateHoistedGenericType (storey);
1247 protected abstract string OperatorName { get; }
1249 protected override void CloneTo (CloneContext clonectx, Expression t)
1251 Probe target = (Probe) t;
1253 target.expr = expr.Clone (clonectx);
1254 target.ProbeType = ProbeType.Clone (clonectx);
1259 /// <summary>
1260 /// Implementation of the `is' operator.
1261 /// </summary>
1262 public class Is : Probe {
1263 Nullable.Unwrap expr_unwrap;
1265 public Is (Expression expr, Expression probe_type, Location l)
1266 : base (expr, probe_type, l)
1270 public override Expression CreateExpressionTree (ResolveContext ec)
1272 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1273 expr.CreateExpressionTree (ec),
1274 new TypeOf (probe_type_expr, loc));
1276 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1279 public override void Emit (EmitContext ec)
1281 ILGenerator ig = ec.ig;
1282 if (expr_unwrap != null) {
1283 expr_unwrap.EmitCheck (ec);
1284 return;
1287 expr.Emit (ec);
1288 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1289 ig.Emit (OpCodes.Ldnull);
1290 ig.Emit (OpCodes.Cgt_Un);
1293 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1295 ILGenerator ig = ec.ig;
1296 if (expr_unwrap != null) {
1297 expr_unwrap.EmitCheck (ec);
1298 } else {
1299 expr.Emit (ec);
1300 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1302 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1305 Expression CreateConstantResult (ResolveContext ec, bool result)
1307 if (result)
1308 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1309 TypeManager.CSharpName (probe_type_expr.Type));
1310 else
1311 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1312 TypeManager.CSharpName (probe_type_expr.Type));
1314 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1317 public override Expression DoResolve (ResolveContext ec)
1319 if (base.DoResolve (ec) == null)
1320 return null;
1322 Type d = expr.Type;
1323 bool d_is_nullable = false;
1326 // If E is a method group or the null literal, or if the type of E is a reference
1327 // type or a nullable type and the value of E is null, the result is false
1329 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1330 return CreateConstantResult (ec, false);
1332 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1333 d = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (d) [0]);
1334 d_is_nullable = true;
1337 type = TypeManager.bool_type;
1338 eclass = ExprClass.Value;
1339 Type t = probe_type_expr.Type;
1340 bool t_is_nullable = false;
1341 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1342 t = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (t) [0]);
1343 t_is_nullable = true;
1346 if (TypeManager.IsStruct (t)) {
1347 if (d == t) {
1349 // D and T are the same value types but D can be null
1351 if (d_is_nullable && !t_is_nullable) {
1352 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1353 return this;
1357 // The result is true if D and T are the same value types
1359 return CreateConstantResult (ec, true);
1362 if (TypeManager.IsGenericParameter (d))
1363 return ResolveGenericParameter (ec, t, d);
1366 // An unboxing conversion exists
1368 if (Convert.ExplicitReferenceConversionExists (d, t))
1369 return this;
1370 } else {
1371 if (TypeManager.IsGenericParameter (t))
1372 return ResolveGenericParameter (ec, d, t);
1374 if (TypeManager.IsStruct (d)) {
1375 bool temp;
1376 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1377 return CreateConstantResult (ec, true);
1378 } else {
1379 if (TypeManager.IsGenericParameter (d))
1380 return ResolveGenericParameter (ec, t, d);
1382 if (TypeManager.ContainsGenericParameters (d))
1383 return this;
1385 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1386 Convert.ExplicitReferenceConversionExists (d, t)) {
1387 return this;
1392 return CreateConstantResult (ec, false);
1395 Expression ResolveGenericParameter (ResolveContext ec, Type d, Type t)
1397 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1398 if (constraints != null) {
1399 if (constraints.IsReferenceType && TypeManager.IsStruct (d))
1400 return CreateConstantResult (ec, false);
1403 if (TypeManager.IsGenericParameter (expr.Type)) {
1404 if (constraints != null && constraints.IsValueType && expr.Type == t)
1405 return CreateConstantResult (ec, true);
1407 expr = new BoxedCast (expr, d);
1410 return this;
1413 protected override string OperatorName {
1414 get { return "is"; }
1418 /// <summary>
1419 /// Implementation of the `as' operator.
1420 /// </summary>
1421 public class As : Probe {
1422 bool do_isinst;
1423 Expression resolved_type;
1425 public As (Expression expr, Expression probe_type, Location l)
1426 : base (expr, probe_type, l)
1430 public override Expression CreateExpressionTree (ResolveContext ec)
1432 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1433 expr.CreateExpressionTree (ec),
1434 new TypeOf (probe_type_expr, loc));
1436 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1439 public override void Emit (EmitContext ec)
1441 ILGenerator ig = ec.ig;
1443 expr.Emit (ec);
1445 if (do_isinst)
1446 ig.Emit (OpCodes.Isinst, type);
1448 if (TypeManager.IsGenericParameter (type) || TypeManager.IsNullableType (type))
1449 ig.Emit (OpCodes.Unbox_Any, type);
1452 public override Expression DoResolve (ResolveContext ec)
1454 // Because expr is modified
1455 if (eclass != ExprClass.Invalid)
1456 return this;
1458 if (resolved_type == null) {
1459 resolved_type = base.DoResolve (ec);
1461 if (resolved_type == null)
1462 return null;
1465 type = probe_type_expr.Type;
1466 eclass = ExprClass.Value;
1467 Type etype = expr.Type;
1469 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1470 if (TypeManager.IsGenericParameter (type)) {
1471 ec.Report.Error (413, loc,
1472 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1473 probe_type_expr.GetSignatureForError ());
1474 } else {
1475 ec.Report.Error (77, loc,
1476 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1477 TypeManager.CSharpName (type));
1479 return null;
1482 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1483 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1486 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1487 if (e != null){
1488 expr = e;
1489 do_isinst = false;
1490 return this;
1493 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1494 if (TypeManager.IsGenericParameter (etype))
1495 expr = new BoxedCast (expr, etype);
1497 do_isinst = true;
1498 return this;
1501 if (TypeManager.ContainsGenericParameters (etype) ||
1502 TypeManager.ContainsGenericParameters (type)) {
1503 expr = new BoxedCast (expr, etype);
1504 do_isinst = true;
1505 return this;
1508 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1509 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1511 return null;
1514 protected override string OperatorName {
1515 get { return "as"; }
1518 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1520 type = storey.MutateType (type);
1521 base.MutateHoistedGenericType (storey);
1524 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1526 return expr.GetAttributableValue (ec, value_type, out value);
1530 /// <summary>
1531 /// This represents a typecast in the source language.
1533 /// FIXME: Cast expressions have an unusual set of parsing
1534 /// rules, we need to figure those out.
1535 /// </summary>
1536 public class Cast : ShimExpression {
1537 Expression target_type;
1539 public Cast (Expression cast_type, Expression expr)
1540 : this (cast_type, expr, cast_type.Location)
1544 public Cast (Expression cast_type, Expression expr, Location loc)
1545 : base (expr)
1547 this.target_type = cast_type;
1548 this.loc = loc;
1551 public Expression TargetType {
1552 get { return target_type; }
1555 public override Expression DoResolve (ResolveContext ec)
1557 expr = expr.Resolve (ec);
1558 if (expr == null)
1559 return null;
1561 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1562 if (target == null)
1563 return null;
1565 type = target.Type;
1567 if (type.IsAbstract && type.IsSealed) {
1568 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1569 return null;
1572 eclass = ExprClass.Value;
1574 Constant c = expr as Constant;
1575 if (c != null) {
1576 c = c.TryReduce (ec, type, loc);
1577 if (c != null)
1578 return c;
1581 if (type.IsPointer && !ec.IsUnsafe) {
1582 UnsafeError (ec, loc);
1583 } else if (TypeManager.IsDynamicType (expr.Type)) {
1584 Arguments arg = new Arguments (1);
1585 arg.Add (new Argument (expr));
1586 return new DynamicConversion (type, true, arg, loc).Resolve (ec);
1589 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1590 return expr;
1593 protected override void CloneTo (CloneContext clonectx, Expression t)
1595 Cast target = (Cast) t;
1597 target.target_type = target_type.Clone (clonectx);
1598 target.expr = expr.Clone (clonectx);
1602 public class ImplicitCast : ShimExpression
1604 public ImplicitCast (Expression expr, Type target)
1605 : base (expr)
1607 this.loc = expr.Location;
1608 this.type = target;
1611 public override Expression DoResolve (ResolveContext ec)
1613 expr = expr.Resolve (ec);
1614 if (expr != null)
1615 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1617 return expr;
1622 // C# 2.0 Default value expression
1624 public class DefaultValueExpression : Expression
1626 sealed class DefaultValueNullLiteral : NullLiteral
1628 public DefaultValueNullLiteral (DefaultValueExpression expr)
1629 : base (expr.type, expr.loc)
1633 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type t, bool expl)
1635 Error_ValueCannotBeConvertedCore (ec, loc, t, expl);
1640 Expression expr;
1642 public DefaultValueExpression (Expression expr, Location loc)
1644 this.expr = expr;
1645 this.loc = loc;
1648 public override Expression CreateExpressionTree (ResolveContext ec)
1650 Arguments args = new Arguments (2);
1651 args.Add (new Argument (this));
1652 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1653 return CreateExpressionFactoryCall (ec, "Constant", args);
1656 public override Expression DoResolve (ResolveContext ec)
1658 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1659 if (texpr == null)
1660 return null;
1662 type = texpr.Type;
1664 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1665 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1668 if (type.IsPointer)
1669 return new NullLiteral (Location).ConvertImplicitly (type);
1671 if (TypeManager.IsReferenceType (type))
1672 return new DefaultValueNullLiteral (this);
1674 Constant c = New.Constantify (type);
1675 if (c != null)
1676 return c;
1678 eclass = ExprClass.Variable;
1679 return this;
1682 public override void Emit (EmitContext ec)
1684 LocalTemporary temp_storage = new LocalTemporary(type);
1686 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1687 ec.ig.Emit(OpCodes.Initobj, type);
1688 temp_storage.Emit(ec);
1691 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1693 type = storey.MutateType (type);
1696 protected override void CloneTo (CloneContext clonectx, Expression t)
1698 DefaultValueExpression target = (DefaultValueExpression) t;
1700 target.expr = expr.Clone (clonectx);
1704 /// <summary>
1705 /// Binary operators
1706 /// </summary>
1707 public class Binary : Expression, IDynamicBinder
1710 protected class PredefinedOperator {
1711 protected readonly Type left;
1712 protected readonly Type right;
1713 public readonly Operator OperatorsMask;
1714 public Type ReturnType;
1716 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1717 : this (ltype, rtype, op_mask, ltype)
1721 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1722 : this (type, type, op_mask, return_type)
1726 public PredefinedOperator (Type type, Operator op_mask)
1727 : this (type, type, op_mask, type)
1731 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1733 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1734 throw new InternalErrorException ("Only masked values can be used");
1736 this.left = ltype;
1737 this.right = rtype;
1738 this.OperatorsMask = op_mask;
1739 this.ReturnType = return_type;
1742 public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1744 b.type = ReturnType;
1746 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1747 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1750 // A user operators does not support multiple user conversions, but decimal type
1751 // is considered to be predefined type therefore we apply predefined operators rules
1752 // and then look for decimal user-operator implementation
1754 if (left == TypeManager.decimal_type)
1755 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1757 return b;
1760 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1763 // We are dealing with primitive types only
1765 return left == ltype && ltype == rtype;
1768 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1770 if (TypeManager.IsEqual (left, lexpr.Type) &&
1771 TypeManager.IsEqual (right, rexpr.Type))
1772 return true;
1774 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1775 Convert.ImplicitConversionExists (ec, rexpr, right);
1778 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1780 int result = 0;
1781 if (left != null && best_operator.left != null) {
1782 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1786 // When second arguments are same as the first one, the result is same
1788 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1789 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1792 if (result == 0 || result > 2)
1793 return null;
1795 return result == 1 ? best_operator : this;
1799 class PredefinedStringOperator : PredefinedOperator {
1800 public PredefinedStringOperator (Type type, Operator op_mask)
1801 : base (type, op_mask, type)
1803 ReturnType = TypeManager.string_type;
1806 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1807 : base (ltype, rtype, op_mask)
1809 ReturnType = TypeManager.string_type;
1812 public override Expression ConvertResult (ResolveContext ec, Binary b)
1815 // Use original expression for nullable arguments
1817 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1818 if (unwrap != null)
1819 b.left = unwrap.Original;
1821 unwrap = b.right as Nullable.Unwrap;
1822 if (unwrap != null)
1823 b.right = unwrap.Original;
1825 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1826 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1829 // Start a new concat expression using converted expression
1831 return new StringConcat (b.loc, b.left, b.right).Resolve (ec);
1835 class PredefinedShiftOperator : PredefinedOperator {
1836 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1837 base (ltype, TypeManager.int32_type, op_mask)
1841 public override Expression ConvertResult (ResolveContext ec, Binary b)
1843 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1845 Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, TypeManager.int32_type, b.right.Location);
1847 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1850 // b = b.left >> b.right & (0x1f|0x3f)
1852 b.right = new Binary (Operator.BitwiseAnd,
1853 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1856 // Expression tree representation does not use & mask
1858 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1859 b.type = ReturnType;
1860 return b;
1864 class PredefinedPointerOperator : PredefinedOperator {
1865 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1866 : base (ltype, rtype, op_mask)
1870 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1871 : base (ltype, rtype, op_mask, retType)
1875 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1876 : base (type, op_mask, return_type)
1880 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1882 if (left == null) {
1883 if (!lexpr.Type.IsPointer)
1884 return false;
1885 } else {
1886 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1887 return false;
1890 if (right == null) {
1891 if (!rexpr.Type.IsPointer)
1892 return false;
1893 } else {
1894 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1895 return false;
1898 return true;
1901 public override Expression ConvertResult (ResolveContext ec, Binary b)
1903 if (left != null) {
1904 b.left = EmptyCast.Create (b.left, left);
1905 } else if (right != null) {
1906 b.right = EmptyCast.Create (b.right, right);
1909 Type r_type = ReturnType;
1910 Expression left_arg, right_arg;
1911 if (r_type == null) {
1912 if (left == null) {
1913 left_arg = b.left;
1914 right_arg = b.right;
1915 r_type = b.left.Type;
1916 } else {
1917 left_arg = b.right;
1918 right_arg = b.left;
1919 r_type = b.right.Type;
1921 } else {
1922 left_arg = b.left;
1923 right_arg = b.right;
1926 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1930 [Flags]
1931 public enum Operator {
1932 Multiply = 0 | ArithmeticMask,
1933 Division = 1 | ArithmeticMask,
1934 Modulus = 2 | ArithmeticMask,
1935 Addition = 3 | ArithmeticMask | AdditionMask,
1936 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1938 LeftShift = 5 | ShiftMask,
1939 RightShift = 6 | ShiftMask,
1941 LessThan = 7 | ComparisonMask | RelationalMask,
1942 GreaterThan = 8 | ComparisonMask | RelationalMask,
1943 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1944 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1945 Equality = 11 | ComparisonMask | EqualityMask,
1946 Inequality = 12 | ComparisonMask | EqualityMask,
1948 BitwiseAnd = 13 | BitwiseMask,
1949 ExclusiveOr = 14 | BitwiseMask,
1950 BitwiseOr = 15 | BitwiseMask,
1952 LogicalAnd = 16 | LogicalMask,
1953 LogicalOr = 17 | LogicalMask,
1956 // Operator masks
1958 ValuesOnlyMask = ArithmeticMask - 1,
1959 ArithmeticMask = 1 << 5,
1960 ShiftMask = 1 << 6,
1961 ComparisonMask = 1 << 7,
1962 EqualityMask = 1 << 8,
1963 BitwiseMask = 1 << 9,
1964 LogicalMask = 1 << 10,
1965 AdditionMask = 1 << 11,
1966 SubtractionMask = 1 << 12,
1967 RelationalMask = 1 << 13
1970 readonly Operator oper;
1971 protected Expression left, right;
1972 readonly bool is_compound;
1973 Expression enum_conversion;
1975 static PredefinedOperator [] standard_operators;
1976 static PredefinedOperator [] pointer_operators;
1978 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1979 : this (oper, left, right)
1981 this.is_compound = isCompound;
1984 public Binary (Operator oper, Expression left, Expression right)
1986 this.oper = oper;
1987 this.left = left;
1988 this.right = right;
1989 this.loc = left.Location;
1992 public Operator Oper {
1993 get {
1994 return oper;
1998 /// <summary>
1999 /// Returns a stringified representation of the Operator
2000 /// </summary>
2001 string OperName (Operator oper)
2003 string s;
2004 switch (oper){
2005 case Operator.Multiply:
2006 s = "*";
2007 break;
2008 case Operator.Division:
2009 s = "/";
2010 break;
2011 case Operator.Modulus:
2012 s = "%";
2013 break;
2014 case Operator.Addition:
2015 s = "+";
2016 break;
2017 case Operator.Subtraction:
2018 s = "-";
2019 break;
2020 case Operator.LeftShift:
2021 s = "<<";
2022 break;
2023 case Operator.RightShift:
2024 s = ">>";
2025 break;
2026 case Operator.LessThan:
2027 s = "<";
2028 break;
2029 case Operator.GreaterThan:
2030 s = ">";
2031 break;
2032 case Operator.LessThanOrEqual:
2033 s = "<=";
2034 break;
2035 case Operator.GreaterThanOrEqual:
2036 s = ">=";
2037 break;
2038 case Operator.Equality:
2039 s = "==";
2040 break;
2041 case Operator.Inequality:
2042 s = "!=";
2043 break;
2044 case Operator.BitwiseAnd:
2045 s = "&";
2046 break;
2047 case Operator.BitwiseOr:
2048 s = "|";
2049 break;
2050 case Operator.ExclusiveOr:
2051 s = "^";
2052 break;
2053 case Operator.LogicalOr:
2054 s = "||";
2055 break;
2056 case Operator.LogicalAnd:
2057 s = "&&";
2058 break;
2059 default:
2060 s = oper.ToString ();
2061 break;
2064 if (is_compound)
2065 return s + "=";
2067 return s;
2070 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2072 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2075 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2077 string l, r;
2078 l = TypeManager.CSharpName (left.Type);
2079 r = TypeManager.CSharpName (right.Type);
2081 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2082 oper, l, r);
2085 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2087 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2091 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2093 string GetOperatorExpressionTypeName ()
2095 switch (oper) {
2096 case Operator.Addition:
2097 return is_compound ? "AddAssign" : "Add";
2098 case Operator.BitwiseAnd:
2099 return is_compound ? "AndAssign" : "And";
2100 case Operator.BitwiseOr:
2101 return is_compound ? "OrAssign" : "Or";
2102 case Operator.Division:
2103 return is_compound ? "DivideAssign" : "Divide";
2104 case Operator.ExclusiveOr:
2105 return is_compound ? "ExclusiveOrAssign" : "ExclusiveOr";
2106 case Operator.Equality:
2107 return "Equal";
2108 case Operator.GreaterThan:
2109 return "GreaterThan";
2110 case Operator.GreaterThanOrEqual:
2111 return "GreaterThanOrEqual";
2112 case Operator.Inequality:
2113 return "NotEqual";
2114 case Operator.LeftShift:
2115 return is_compound ? "LeftShiftAssign" : "LeftShift";
2116 case Operator.LessThan:
2117 return "LessThan";
2118 case Operator.LessThanOrEqual:
2119 return "LessThanOrEqual";
2120 case Operator.LogicalAnd:
2121 return "And";
2122 case Operator.LogicalOr:
2123 return "Or";
2124 case Operator.Modulus:
2125 return is_compound ? "ModuloAssign" : "Modulo";
2126 case Operator.Multiply:
2127 return is_compound ? "MultiplyAssign" : "Multiply";
2128 case Operator.RightShift:
2129 return is_compound ? "RightShiftAssign" : "RightShift";
2130 case Operator.Subtraction:
2131 return is_compound ? "SubtractAssign" : "Subtract";
2132 default:
2133 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2137 static string GetOperatorMetadataName (Operator op)
2139 CSharp.Operator.OpType op_type;
2140 switch (op) {
2141 case Operator.Addition:
2142 op_type = CSharp.Operator.OpType.Addition; break;
2143 case Operator.BitwiseAnd:
2144 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2145 case Operator.BitwiseOr:
2146 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2147 case Operator.Division:
2148 op_type = CSharp.Operator.OpType.Division; break;
2149 case Operator.Equality:
2150 op_type = CSharp.Operator.OpType.Equality; break;
2151 case Operator.ExclusiveOr:
2152 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2153 case Operator.GreaterThan:
2154 op_type = CSharp.Operator.OpType.GreaterThan; break;
2155 case Operator.GreaterThanOrEqual:
2156 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2157 case Operator.Inequality:
2158 op_type = CSharp.Operator.OpType.Inequality; break;
2159 case Operator.LeftShift:
2160 op_type = CSharp.Operator.OpType.LeftShift; break;
2161 case Operator.LessThan:
2162 op_type = CSharp.Operator.OpType.LessThan; break;
2163 case Operator.LessThanOrEqual:
2164 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2165 case Operator.Modulus:
2166 op_type = CSharp.Operator.OpType.Modulus; break;
2167 case Operator.Multiply:
2168 op_type = CSharp.Operator.OpType.Multiply; break;
2169 case Operator.RightShift:
2170 op_type = CSharp.Operator.OpType.RightShift; break;
2171 case Operator.Subtraction:
2172 op_type = CSharp.Operator.OpType.Subtraction; break;
2173 default:
2174 throw new InternalErrorException (op.ToString ());
2177 return CSharp.Operator.GetMetadataName (op_type);
2180 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2182 OpCode opcode;
2183 ILGenerator ig = ec.ig;
2185 switch (oper){
2186 case Operator.Multiply:
2187 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2188 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2189 opcode = OpCodes.Mul_Ovf;
2190 else if (!IsFloat (l))
2191 opcode = OpCodes.Mul_Ovf_Un;
2192 else
2193 opcode = OpCodes.Mul;
2194 } else
2195 opcode = OpCodes.Mul;
2197 break;
2199 case Operator.Division:
2200 if (IsUnsigned (l))
2201 opcode = OpCodes.Div_Un;
2202 else
2203 opcode = OpCodes.Div;
2204 break;
2206 case Operator.Modulus:
2207 if (IsUnsigned (l))
2208 opcode = OpCodes.Rem_Un;
2209 else
2210 opcode = OpCodes.Rem;
2211 break;
2213 case Operator.Addition:
2214 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2215 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2216 opcode = OpCodes.Add_Ovf;
2217 else if (!IsFloat (l))
2218 opcode = OpCodes.Add_Ovf_Un;
2219 else
2220 opcode = OpCodes.Add;
2221 } else
2222 opcode = OpCodes.Add;
2223 break;
2225 case Operator.Subtraction:
2226 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2227 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2228 opcode = OpCodes.Sub_Ovf;
2229 else if (!IsFloat (l))
2230 opcode = OpCodes.Sub_Ovf_Un;
2231 else
2232 opcode = OpCodes.Sub;
2233 } else
2234 opcode = OpCodes.Sub;
2235 break;
2237 case Operator.RightShift:
2238 if (IsUnsigned (l))
2239 opcode = OpCodes.Shr_Un;
2240 else
2241 opcode = OpCodes.Shr;
2242 break;
2244 case Operator.LeftShift:
2245 opcode = OpCodes.Shl;
2246 break;
2248 case Operator.Equality:
2249 opcode = OpCodes.Ceq;
2250 break;
2252 case Operator.Inequality:
2253 ig.Emit (OpCodes.Ceq);
2254 ig.Emit (OpCodes.Ldc_I4_0);
2256 opcode = OpCodes.Ceq;
2257 break;
2259 case Operator.LessThan:
2260 if (IsUnsigned (l))
2261 opcode = OpCodes.Clt_Un;
2262 else
2263 opcode = OpCodes.Clt;
2264 break;
2266 case Operator.GreaterThan:
2267 if (IsUnsigned (l))
2268 opcode = OpCodes.Cgt_Un;
2269 else
2270 opcode = OpCodes.Cgt;
2271 break;
2273 case Operator.LessThanOrEqual:
2274 if (IsUnsigned (l) || IsFloat (l))
2275 ig.Emit (OpCodes.Cgt_Un);
2276 else
2277 ig.Emit (OpCodes.Cgt);
2278 ig.Emit (OpCodes.Ldc_I4_0);
2280 opcode = OpCodes.Ceq;
2281 break;
2283 case Operator.GreaterThanOrEqual:
2284 if (IsUnsigned (l) || IsFloat (l))
2285 ig.Emit (OpCodes.Clt_Un);
2286 else
2287 ig.Emit (OpCodes.Clt);
2289 ig.Emit (OpCodes.Ldc_I4_0);
2291 opcode = OpCodes.Ceq;
2292 break;
2294 case Operator.BitwiseOr:
2295 opcode = OpCodes.Or;
2296 break;
2298 case Operator.BitwiseAnd:
2299 opcode = OpCodes.And;
2300 break;
2302 case Operator.ExclusiveOr:
2303 opcode = OpCodes.Xor;
2304 break;
2306 default:
2307 throw new InternalErrorException (oper.ToString ());
2310 ig.Emit (opcode);
2313 static bool IsUnsigned (Type t)
2315 if (t.IsPointer)
2316 return true;
2318 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2319 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2322 static bool IsFloat (Type t)
2324 return t == TypeManager.float_type || t == TypeManager.double_type;
2327 Expression ResolveOperator (ResolveContext ec)
2329 Type l = left.Type;
2330 Type r = right.Type;
2331 Expression expr;
2332 bool primitives_only = false;
2334 if (standard_operators == null)
2335 CreateStandardOperatorsTable ();
2338 // Handles predefined primitive types
2340 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2341 if ((oper & Operator.ShiftMask) == 0) {
2342 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2343 return null;
2345 primitives_only = true;
2347 } else {
2348 // Pointers
2349 if (l.IsPointer || r.IsPointer)
2350 return ResolveOperatorPointer (ec, l, r);
2352 // Enums
2353 bool lenum = TypeManager.IsEnumType (l);
2354 bool renum = TypeManager.IsEnumType (r);
2355 if (lenum || renum) {
2356 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2358 // TODO: Can this be ambiguous
2359 if (expr != null)
2360 return expr;
2363 // Delegates
2364 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2365 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2367 expr = ResolveOperatorDelegate (ec, l, r);
2369 // TODO: Can this be ambiguous
2370 if (expr != null)
2371 return expr;
2374 // User operators
2375 expr = ResolveUserOperator (ec, l, r);
2376 if (expr != null)
2377 return expr;
2379 // Predefined reference types equality
2380 if ((oper & Operator.EqualityMask) != 0) {
2381 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2382 if (expr != null)
2383 return expr;
2387 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2390 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2391 // if 'left' is not an enumeration constant, create one from the type of 'right'
2392 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2394 switch (oper) {
2395 case Operator.BitwiseOr:
2396 case Operator.BitwiseAnd:
2397 case Operator.ExclusiveOr:
2398 case Operator.Equality:
2399 case Operator.Inequality:
2400 case Operator.LessThan:
2401 case Operator.LessThanOrEqual:
2402 case Operator.GreaterThan:
2403 case Operator.GreaterThanOrEqual:
2404 if (TypeManager.IsEnumType (left.Type))
2405 return left;
2407 if (left.IsZeroInteger)
2408 return left.TryReduce (ec, right.Type, loc);
2410 break;
2412 case Operator.Addition:
2413 case Operator.Subtraction:
2414 return left;
2416 case Operator.Multiply:
2417 case Operator.Division:
2418 case Operator.Modulus:
2419 case Operator.LeftShift:
2420 case Operator.RightShift:
2421 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2422 break;
2423 return left;
2425 Error_OperatorCannotBeApplied (ec, this.left, this.right);
2426 return null;
2430 // The `|' operator used on types which were extended is dangerous
2432 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2434 OpcodeCast lcast = left as OpcodeCast;
2435 if (lcast != null) {
2436 if (IsUnsigned (lcast.UnderlyingType))
2437 lcast = null;
2440 OpcodeCast rcast = right as OpcodeCast;
2441 if (rcast != null) {
2442 if (IsUnsigned (rcast.UnderlyingType))
2443 rcast = null;
2446 if (lcast == null && rcast == null)
2447 return;
2449 // FIXME: consider constants
2451 ec.Report.Warning (675, 3, loc,
2452 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2453 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2456 static void CreatePointerOperatorsTable ()
2458 ArrayList temp = new ArrayList ();
2461 // Pointer arithmetic:
2463 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2464 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2465 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2466 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2468 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2469 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2470 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2471 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2474 // T* operator + (int y, T* x);
2475 // T* operator + (uint y, T *x);
2476 // T* operator + (long y, T *x);
2477 // T* operator + (ulong y, T *x);
2479 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2480 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2481 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2482 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2485 // long operator - (T* x, T *y)
2487 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2489 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2492 static void CreateStandardOperatorsTable ()
2494 ArrayList temp = new ArrayList ();
2495 Type bool_type = TypeManager.bool_type;
2497 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2498 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2499 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2500 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2501 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2502 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2503 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2505 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2506 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2507 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2508 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2509 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2510 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2511 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2513 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2515 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2516 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2517 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2519 temp.Add (new PredefinedOperator (bool_type,
2520 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2522 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2523 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2524 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2525 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2527 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2531 // Rules used during binary numeric promotion
2533 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2535 Expression temp;
2536 Type etype;
2538 Constant c = prim_expr as Constant;
2539 if (c != null) {
2540 temp = c.ConvertImplicitly (type);
2541 if (temp != null) {
2542 prim_expr = temp;
2543 return true;
2547 if (type == TypeManager.uint32_type) {
2548 etype = prim_expr.Type;
2549 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2550 type = TypeManager.int64_type;
2552 if (type != second_expr.Type) {
2553 c = second_expr as Constant;
2554 if (c != null)
2555 temp = c.ConvertImplicitly (type);
2556 else
2557 temp = Convert.ImplicitNumericConversion (second_expr, type);
2558 if (temp == null)
2559 return false;
2560 second_expr = temp;
2563 } else if (type == TypeManager.uint64_type) {
2565 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2567 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2568 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2569 return false;
2572 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2573 if (temp == null)
2574 return false;
2576 prim_expr = temp;
2577 return true;
2581 // 7.2.6.2 Binary numeric promotions
2583 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2585 Type ltype = left.Type;
2586 Type rtype = right.Type;
2587 Expression temp;
2589 foreach (Type t in ConstantFold.binary_promotions) {
2590 if (t == ltype)
2591 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2593 if (t == rtype)
2594 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2597 Type int32 = TypeManager.int32_type;
2598 if (ltype != int32) {
2599 Constant c = left as Constant;
2600 if (c != null)
2601 temp = c.ConvertImplicitly (int32);
2602 else
2603 temp = Convert.ImplicitNumericConversion (left, int32);
2605 if (temp == null)
2606 return false;
2607 left = temp;
2610 if (rtype != int32) {
2611 Constant c = right as Constant;
2612 if (c != null)
2613 temp = c.ConvertImplicitly (int32);
2614 else
2615 temp = Convert.ImplicitNumericConversion (right, int32);
2617 if (temp == null)
2618 return false;
2619 right = temp;
2622 return true;
2625 public override Expression DoResolve (ResolveContext ec)
2627 if (left == null)
2628 return null;
2630 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2631 left = ((ParenthesizedExpression) left).Expr;
2632 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2633 if (left == null)
2634 return null;
2636 if (left.eclass == ExprClass.Type) {
2637 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2638 return null;
2640 } else
2641 left = left.Resolve (ec);
2643 if (left == null)
2644 return null;
2646 Constant lc = left as Constant;
2648 if (lc != null && lc.Type == TypeManager.bool_type &&
2649 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2650 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2652 // FIXME: resolve right expression as unreachable
2653 // right.Resolve (ec);
2655 ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2656 return left;
2659 right = right.Resolve (ec);
2660 if (right == null)
2661 return null;
2663 eclass = ExprClass.Value;
2664 Constant rc = right as Constant;
2666 // The conversion rules are ignored in enum context but why
2667 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2668 lc = EnumLiftUp (ec, lc, rc, loc);
2669 if (lc != null)
2670 rc = EnumLiftUp (ec, rc, lc, loc);
2673 if (rc != null && lc != null) {
2674 int prev_e = ec.Report.Errors;
2675 Expression e = ConstantFold.BinaryFold (
2676 ec, oper, lc, rc, loc);
2677 if (e != null || ec.Report.Errors != prev_e)
2678 return e;
2679 } else if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) && !TypeManager.IsDynamicType (left.Type) &&
2680 ((lc != null && lc.IsDefaultValue && !(lc is NullLiteral)) || (rc != null && rc.IsDefaultValue && !(rc is NullLiteral)))) {
2682 if ((ResolveOperator (ec)) == null) {
2683 Error_OperatorCannotBeApplied (ec, left, right);
2684 return null;
2688 // The result is a constant with side-effect
2690 Constant side_effect = rc == null ?
2691 new SideEffectConstant (lc, right, loc) :
2692 new SideEffectConstant (rc, left, loc);
2694 return ReducedExpression.Create (side_effect, this);
2697 // Comparison warnings
2698 if ((oper & Operator.ComparisonMask) != 0) {
2699 if (left.Equals (right)) {
2700 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2702 CheckUselessComparison (ec, lc, right.Type);
2703 CheckUselessComparison (ec, rc, left.Type);
2706 if (TypeManager.IsDynamicType (left.Type) || TypeManager.IsDynamicType (right.Type)) {
2707 Arguments args = new Arguments (2);
2708 args.Add (new Argument (left));
2709 args.Add (new Argument (right));
2710 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
2713 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2714 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2715 (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
2716 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2717 (TypeManager.IsValueType (right.Type) && left is NullLiteral)))
2718 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2720 return DoResolveCore (ec, left, right);
2723 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
2725 Expression expr = ResolveOperator (ec);
2726 if (expr == null)
2727 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
2729 if (left == null || right == null)
2730 throw new InternalErrorException ("Invalid conversion");
2732 if (oper == Operator.BitwiseOr)
2733 CheckBitwiseOrOnSignExtended (ec);
2735 return expr;
2738 #if NET_4_0
2739 public override SLE.Expression MakeExpression (BuilderContext ctx)
2741 var le = left.MakeExpression (ctx);
2742 var re = right.MakeExpression (ctx);
2743 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
2745 switch (oper) {
2746 case Operator.Addition:
2747 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
2748 case Operator.BitwiseAnd:
2749 return SLE.Expression.And (le, re);
2750 case Operator.BitwiseOr:
2751 return SLE.Expression.Or (le, re);
2752 case Operator.Division:
2753 return SLE.Expression.Divide (le, re);
2754 case Operator.Equality:
2755 return SLE.Expression.Equal (le, re);
2756 case Operator.ExclusiveOr:
2757 return SLE.Expression.ExclusiveOr (le, re);
2758 case Operator.GreaterThan:
2759 return SLE.Expression.GreaterThan (le, re);
2760 case Operator.GreaterThanOrEqual:
2761 return SLE.Expression.GreaterThanOrEqual (le, re);
2762 case Operator.Inequality:
2763 return SLE.Expression.NotEqual (le, re);
2764 case Operator.LeftShift:
2765 return SLE.Expression.LeftShift (le, re);
2766 case Operator.LessThan:
2767 return SLE.Expression.LessThan (le, re);
2768 case Operator.LessThanOrEqual:
2769 return SLE.Expression.LessThanOrEqual (le, re);
2770 case Operator.LogicalAnd:
2771 return SLE.Expression.AndAlso (le, re);
2772 case Operator.LogicalOr:
2773 return SLE.Expression.OrElse (le, re);
2774 case Operator.Modulus:
2775 return SLE.Expression.Modulo (le, re);
2776 case Operator.Multiply:
2777 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
2778 case Operator.RightShift:
2779 return SLE.Expression.RightShift (le, re);
2780 case Operator.Subtraction:
2781 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
2782 default:
2783 throw new NotImplementedException (oper.ToString ());
2786 #endif
2788 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2790 left.MutateHoistedGenericType (storey);
2791 right.MutateHoistedGenericType (storey);
2795 // D operator + (D x, D y)
2796 // D operator - (D x, D y)
2797 // bool operator == (D x, D y)
2798 // bool operator != (D x, D y)
2800 Expression ResolveOperatorDelegate (ResolveContext ec, Type l, Type r)
2802 bool is_equality = (oper & Operator.EqualityMask) != 0;
2803 if (!TypeManager.IsEqual (l, r) && !TypeManager.IsVariantOf (r, l)) {
2804 Expression tmp;
2805 if (right.eclass == ExprClass.MethodGroup || (r == InternalType.AnonymousMethod && !is_equality)) {
2806 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2807 if (tmp == null)
2808 return null;
2809 right = tmp;
2810 r = right.Type;
2811 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod && !is_equality)) {
2812 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2813 if (tmp == null)
2814 return null;
2815 left = tmp;
2816 l = left.Type;
2817 } else {
2818 return null;
2823 // Resolve delegate equality as a user operator
2825 if (is_equality)
2826 return ResolveUserOperator (ec, l, r);
2828 MethodInfo method;
2829 Arguments args = new Arguments (2);
2830 args.Add (new Argument (left));
2831 args.Add (new Argument (right));
2833 if (oper == Operator.Addition) {
2834 if (TypeManager.delegate_combine_delegate_delegate == null) {
2835 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2836 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2839 method = TypeManager.delegate_combine_delegate_delegate;
2840 } else {
2841 if (TypeManager.delegate_remove_delegate_delegate == null) {
2842 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2843 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2846 method = TypeManager.delegate_remove_delegate_delegate;
2849 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2850 mg = mg.OverloadResolve (ec, ref args, false, loc);
2852 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2856 // Enumeration operators
2858 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2861 // bool operator == (E x, E y);
2862 // bool operator != (E x, E y);
2863 // bool operator < (E x, E y);
2864 // bool operator > (E x, E y);
2865 // bool operator <= (E x, E y);
2866 // bool operator >= (E x, E y);
2868 // E operator & (E x, E y);
2869 // E operator | (E x, E y);
2870 // E operator ^ (E x, E y);
2872 // U operator - (E e, E f)
2873 // E operator - (E e, U x)
2875 // E operator + (U x, E e)
2876 // E operator + (E e, U x)
2878 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2879 (oper == Operator.Subtraction && lenum) ||
2880 (oper == Operator.Addition && (lenum != renum || type != null)))) // type != null for lifted null
2881 return null;
2883 Expression ltemp = left;
2884 Expression rtemp = right;
2885 Type underlying_type;
2886 Expression expr;
2888 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2889 if (renum) {
2890 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2891 if (expr != null) {
2892 left = expr;
2893 ltype = expr.Type;
2895 } else if (lenum) {
2896 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2897 if (expr != null) {
2898 right = expr;
2899 rtype = expr.Type;
2904 if (TypeManager.IsEqual (ltype, rtype)) {
2905 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2907 if (left is Constant)
2908 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2909 else
2910 left = EmptyCast.Create (left, underlying_type);
2912 if (right is Constant)
2913 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2914 else
2915 right = EmptyCast.Create (right, underlying_type);
2916 } else if (lenum) {
2917 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2919 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2920 Constant c = right as Constant;
2921 if (c == null || !c.IsDefaultValue)
2922 return null;
2923 } else {
2924 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2925 return null;
2927 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2930 if (left is Constant)
2931 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2932 else
2933 left = EmptyCast.Create (left, underlying_type);
2935 } else if (renum) {
2936 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2938 if (oper != Operator.Addition) {
2939 Constant c = left as Constant;
2940 if (c == null || !c.IsDefaultValue)
2941 return null;
2942 } else {
2943 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2944 return null;
2946 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2949 if (right is Constant)
2950 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2951 else
2952 right = EmptyCast.Create (right, underlying_type);
2954 } else {
2955 return null;
2959 // C# specification uses explicit cast syntax which means binary promotion
2960 // should happen, however it seems that csc does not do that
2962 if (!DoBinaryOperatorPromotion (ec)) {
2963 left = ltemp;
2964 right = rtemp;
2965 return null;
2968 Type res_type = null;
2969 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2970 Type promoted_type = lenum ? left.Type : right.Type;
2971 enum_conversion = Convert.ExplicitNumericConversion (
2972 new EmptyExpression (promoted_type), underlying_type);
2974 if (oper == Operator.Subtraction && renum && lenum)
2975 res_type = underlying_type;
2976 else if (oper == Operator.Addition && renum)
2977 res_type = rtype;
2978 else
2979 res_type = ltype;
2982 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2983 if (!is_compound || expr == null)
2984 return expr;
2987 // Section: 7.16.2
2991 // If the return type of the selected operator is implicitly convertible to the type of x
2993 if (Convert.ImplicitConversionExists (ec, expr, ltype))
2994 return expr;
2997 // Otherwise, if the selected operator is a predefined operator, if the return type of the
2998 // selected operator is explicitly convertible to the type of x, and if y is implicitly
2999 // convertible to the type of x or the operator is a shift operator, then the operation
3000 // is evaluated as x = (T)(x op y), where T is the type of x
3002 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
3003 if (expr == null)
3004 return null;
3006 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
3007 return expr;
3009 return null;
3013 // 7.9.6 Reference type equality operators
3015 Binary ResolveOperatorEqualityRerefence (ResolveContext ec, Type l, Type r)
3018 // operator != (object a, object b)
3019 // operator == (object a, object b)
3022 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
3024 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
3025 return null;
3027 type = TypeManager.bool_type;
3028 GenericConstraints constraints;
3030 bool lgen = TypeManager.IsGenericParameter (l);
3032 if (TypeManager.IsEqual (l, r)) {
3033 if (lgen) {
3035 // Only allow to compare same reference type parameter
3037 if (TypeManager.IsReferenceType (l)) {
3038 left = new BoxedCast (left, TypeManager.object_type);
3039 right = new BoxedCast (right, TypeManager.object_type);
3040 return this;
3043 return null;
3046 if (l == InternalType.AnonymousMethod)
3047 return null;
3049 if (TypeManager.IsValueType (l))
3050 return null;
3052 return this;
3055 bool rgen = TypeManager.IsGenericParameter (r);
3058 // a, Both operands are reference-type values or the value null
3059 // b, One operand is a value of type T where T is a type-parameter and
3060 // the other operand is the value null. Furthermore T does not have the
3061 // value type constrain
3063 if (left is NullLiteral || right is NullLiteral) {
3064 if (lgen) {
3065 constraints = TypeManager.GetTypeParameterConstraints (l);
3066 if (constraints != null && constraints.HasValueTypeConstraint)
3067 return null;
3069 left = new BoxedCast (left, TypeManager.object_type);
3070 return this;
3073 if (rgen) {
3074 constraints = TypeManager.GetTypeParameterConstraints (r);
3075 if (constraints != null && constraints.HasValueTypeConstraint)
3076 return null;
3078 right = new BoxedCast (right, TypeManager.object_type);
3079 return this;
3084 // An interface is converted to the object before the
3085 // standard conversion is applied. It's not clear from the
3086 // standard but it looks like it works like that.
3088 if (lgen) {
3089 if (!TypeManager.IsReferenceType (l))
3090 return null;
3092 l = TypeManager.object_type;
3093 left = new BoxedCast (left, l);
3094 } else if (l.IsInterface) {
3095 l = TypeManager.object_type;
3096 } else if (TypeManager.IsStruct (l)) {
3097 return null;
3100 if (rgen) {
3101 if (!TypeManager.IsReferenceType (r))
3102 return null;
3104 r = TypeManager.object_type;
3105 right = new BoxedCast (right, r);
3106 } else if (r.IsInterface) {
3107 r = TypeManager.object_type;
3108 } else if (TypeManager.IsStruct (r)) {
3109 return null;
3113 const string ref_comparison = "Possible unintended reference comparison. " +
3114 "Consider casting the {0} side of the expression to `string' to compare the values";
3117 // A standard implicit conversion exists from the type of either
3118 // operand to the type of the other operand
3120 if (Convert.ImplicitReferenceConversionExists (left, r)) {
3121 if (l == TypeManager.string_type)
3122 ec.Report.Warning (253, 2, loc, ref_comparison, "right");
3124 return this;
3127 if (Convert.ImplicitReferenceConversionExists (right, l)) {
3128 if (r == TypeManager.string_type)
3129 ec.Report.Warning (252, 2, loc, ref_comparison, "left");
3131 return this;
3134 return null;
3138 Expression ResolveOperatorPointer (ResolveContext ec, Type l, Type r)
3141 // bool operator == (void* x, void* y);
3142 // bool operator != (void* x, void* y);
3143 // bool operator < (void* x, void* y);
3144 // bool operator > (void* x, void* y);
3145 // bool operator <= (void* x, void* y);
3146 // bool operator >= (void* x, void* y);
3148 if ((oper & Operator.ComparisonMask) != 0) {
3149 Expression temp;
3150 if (!l.IsPointer) {
3151 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3152 if (temp == null)
3153 return null;
3154 left = temp;
3157 if (!r.IsPointer) {
3158 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3159 if (temp == null)
3160 return null;
3161 right = temp;
3164 type = TypeManager.bool_type;
3165 return this;
3168 if (pointer_operators == null)
3169 CreatePointerOperatorsTable ();
3171 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
3175 // Build-in operators method overloading
3177 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
3179 PredefinedOperator best_operator = null;
3180 Type l = left.Type;
3181 Type r = right.Type;
3182 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3184 foreach (PredefinedOperator po in operators) {
3185 if ((po.OperatorsMask & oper_mask) == 0)
3186 continue;
3188 if (primitives_only) {
3189 if (!po.IsPrimitiveApplicable (l, r))
3190 continue;
3191 } else {
3192 if (!po.IsApplicable (ec, left, right))
3193 continue;
3196 if (best_operator == null) {
3197 best_operator = po;
3198 if (primitives_only)
3199 break;
3201 continue;
3204 best_operator = po.ResolveBetterOperator (ec, best_operator);
3206 if (best_operator == null) {
3207 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3208 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3210 best_operator = po;
3211 break;
3215 if (best_operator == null)
3216 return null;
3218 Expression expr = best_operator.ConvertResult (ec, this);
3219 if (enum_type == null)
3220 return expr;
3223 // HACK: required by enum_conversion
3225 expr.Type = enum_type;
3226 return EmptyCast.Create (expr, enum_type);
3230 // Performs user-operator overloading
3232 protected virtual Expression ResolveUserOperator (ResolveContext ec, Type l, Type r)
3234 Operator user_oper;
3235 if (oper == Operator.LogicalAnd)
3236 user_oper = Operator.BitwiseAnd;
3237 else if (oper == Operator.LogicalOr)
3238 user_oper = Operator.BitwiseOr;
3239 else
3240 user_oper = oper;
3242 string op = GetOperatorMetadataName (user_oper);
3244 MethodGroupExpr left_operators = MemberLookup (ec.Compiler, ec.CurrentType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3245 MethodGroupExpr right_operators = null;
3247 if (!TypeManager.IsEqual (r, l)) {
3248 right_operators = MemberLookup (ec.Compiler, ec.CurrentType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3249 if (right_operators == null && left_operators == null)
3250 return null;
3251 } else if (left_operators == null) {
3252 return null;
3255 Arguments args = new Arguments (2);
3256 Argument larg = new Argument (left);
3257 args.Add (larg);
3258 Argument rarg = new Argument (right);
3259 args.Add (rarg);
3261 MethodGroupExpr union;
3264 // User-defined operator implementations always take precedence
3265 // over predefined operator implementations
3267 if (left_operators != null && right_operators != null) {
3268 if (IsPredefinedUserOperator (l, user_oper)) {
3269 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3270 if (union == null)
3271 union = left_operators;
3272 } else if (IsPredefinedUserOperator (r, user_oper)) {
3273 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3274 if (union == null)
3275 union = right_operators;
3276 } else {
3277 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3279 } else if (left_operators != null) {
3280 union = left_operators;
3281 } else {
3282 union = right_operators;
3285 union = union.OverloadResolve (ec, ref args, true, loc);
3286 if (union == null)
3287 return null;
3289 Expression oper_expr;
3291 // TODO: CreateExpressionTree is allocated every time
3292 if (user_oper != oper) {
3293 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3294 oper == Operator.LogicalAnd, loc).Resolve (ec);
3295 } else {
3296 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3299 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3300 // and not invoke user operator
3302 if ((oper & Operator.EqualityMask) != 0) {
3303 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3304 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3305 type = TypeManager.bool_type;
3306 if (left is NullLiteral || right is NullLiteral)
3307 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3308 } else if (l != r) {
3309 MethodInfo mi = (MethodInfo) union;
3312 // Two System.Delegate(s) are never equal
3314 if (mi.DeclaringType == TypeManager.multicast_delegate_type)
3315 return null;
3320 left = larg.Expr;
3321 right = rarg.Expr;
3322 return oper_expr;
3325 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3327 return null;
3330 private void CheckUselessComparison (ResolveContext ec, Constant c, Type type)
3332 if (c == null || !IsTypeIntegral (type)
3333 || c is StringConstant
3334 || c is BoolConstant
3335 || c is FloatConstant
3336 || c is DoubleConstant
3337 || c is DecimalConstant
3339 return;
3341 long value = 0;
3343 if (c is ULongConstant) {
3344 ulong uvalue = ((ULongConstant) c).Value;
3345 if (uvalue > long.MaxValue) {
3346 if (type == TypeManager.byte_type ||
3347 type == TypeManager.sbyte_type ||
3348 type == TypeManager.short_type ||
3349 type == TypeManager.ushort_type ||
3350 type == TypeManager.int32_type ||
3351 type == TypeManager.uint32_type ||
3352 type == TypeManager.int64_type ||
3353 type == TypeManager.char_type)
3354 WarnUselessComparison (ec, type);
3355 return;
3357 value = (long) uvalue;
3359 else if (c is ByteConstant)
3360 value = ((ByteConstant) c).Value;
3361 else if (c is SByteConstant)
3362 value = ((SByteConstant) c).Value;
3363 else if (c is ShortConstant)
3364 value = ((ShortConstant) c).Value;
3365 else if (c is UShortConstant)
3366 value = ((UShortConstant) c).Value;
3367 else if (c is IntConstant)
3368 value = ((IntConstant) c).Value;
3369 else if (c is UIntConstant)
3370 value = ((UIntConstant) c).Value;
3371 else if (c is LongConstant)
3372 value = ((LongConstant) c).Value;
3373 else if (c is CharConstant)
3374 value = ((CharConstant)c).Value;
3376 if (value == 0)
3377 return;
3379 if (IsValueOutOfRange (value, type))
3380 WarnUselessComparison (ec, type);
3383 static bool IsValueOutOfRange (long value, Type type)
3385 if (IsTypeUnsigned (type) && value < 0)
3386 return true;
3387 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3388 type == TypeManager.byte_type && value >= 0x100 ||
3389 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3390 type == TypeManager.ushort_type && value >= 0x10000 ||
3391 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3392 type == TypeManager.uint32_type && value >= 0x100000000;
3395 static bool IsBuildInEqualityOperator (Type t)
3397 return t == TypeManager.object_type || t == TypeManager.string_type ||
3398 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3401 static bool IsPredefinedUserOperator (Type t, Operator op)
3404 // Some predefined types have user operators
3406 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3409 private static bool IsTypeIntegral (Type type)
3411 return type == TypeManager.uint64_type ||
3412 type == TypeManager.int64_type ||
3413 type == TypeManager.uint32_type ||
3414 type == TypeManager.int32_type ||
3415 type == TypeManager.ushort_type ||
3416 type == TypeManager.short_type ||
3417 type == TypeManager.sbyte_type ||
3418 type == TypeManager.byte_type ||
3419 type == TypeManager.char_type;
3422 private static bool IsTypeUnsigned (Type type)
3424 return type == TypeManager.uint64_type ||
3425 type == TypeManager.uint32_type ||
3426 type == TypeManager.ushort_type ||
3427 type == TypeManager.byte_type ||
3428 type == TypeManager.char_type;
3431 private void WarnUselessComparison (ResolveContext ec, Type type)
3433 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}'",
3434 TypeManager.CSharpName (type));
3437 /// <remarks>
3438 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3439 /// context of a conditional bool expression. This function will return
3440 /// false if it is was possible to use EmitBranchable, or true if it was.
3442 /// The expression's code is generated, and we will generate a branch to `target'
3443 /// if the resulting expression value is equal to isTrue
3444 /// </remarks>
3445 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3447 ILGenerator ig = ec.ig;
3450 // This is more complicated than it looks, but its just to avoid
3451 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3452 // but on top of that we want for == and != to use a special path
3453 // if we are comparing against null
3455 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3456 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3459 // put the constant on the rhs, for simplicity
3461 if (left is Constant) {
3462 Expression swap = right;
3463 right = left;
3464 left = swap;
3467 if (((Constant) right).IsZeroInteger) {
3468 left.EmitBranchable (ec, target, my_on_true);
3469 return;
3471 if (right.Type == TypeManager.bool_type) {
3472 // right is a boolean, and it's not 'false' => it is 'true'
3473 left.EmitBranchable (ec, target, !my_on_true);
3474 return;
3477 } else if (oper == Operator.LogicalAnd) {
3479 if (on_true) {
3480 Label tests_end = ig.DefineLabel ();
3482 left.EmitBranchable (ec, tests_end, false);
3483 right.EmitBranchable (ec, target, true);
3484 ig.MarkLabel (tests_end);
3485 } else {
3487 // This optimizes code like this
3488 // if (true && i > 4)
3490 if (!(left is Constant))
3491 left.EmitBranchable (ec, target, false);
3493 if (!(right is Constant))
3494 right.EmitBranchable (ec, target, false);
3497 return;
3499 } else if (oper == Operator.LogicalOr){
3500 if (on_true) {
3501 left.EmitBranchable (ec, target, true);
3502 right.EmitBranchable (ec, target, true);
3504 } else {
3505 Label tests_end = ig.DefineLabel ();
3506 left.EmitBranchable (ec, tests_end, true);
3507 right.EmitBranchable (ec, target, false);
3508 ig.MarkLabel (tests_end);
3511 return;
3513 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3514 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3515 oper == Operator.Equality || oper == Operator.Inequality)) {
3516 base.EmitBranchable (ec, target, on_true);
3517 return;
3520 left.Emit (ec);
3521 right.Emit (ec);
3523 Type t = left.Type;
3524 bool is_float = IsFloat (t);
3525 bool is_unsigned = is_float || IsUnsigned (t);
3527 switch (oper){
3528 case Operator.Equality:
3529 if (on_true)
3530 ig.Emit (OpCodes.Beq, target);
3531 else
3532 ig.Emit (OpCodes.Bne_Un, target);
3533 break;
3535 case Operator.Inequality:
3536 if (on_true)
3537 ig.Emit (OpCodes.Bne_Un, target);
3538 else
3539 ig.Emit (OpCodes.Beq, target);
3540 break;
3542 case Operator.LessThan:
3543 if (on_true)
3544 if (is_unsigned && !is_float)
3545 ig.Emit (OpCodes.Blt_Un, target);
3546 else
3547 ig.Emit (OpCodes.Blt, target);
3548 else
3549 if (is_unsigned)
3550 ig.Emit (OpCodes.Bge_Un, target);
3551 else
3552 ig.Emit (OpCodes.Bge, target);
3553 break;
3555 case Operator.GreaterThan:
3556 if (on_true)
3557 if (is_unsigned && !is_float)
3558 ig.Emit (OpCodes.Bgt_Un, target);
3559 else
3560 ig.Emit (OpCodes.Bgt, target);
3561 else
3562 if (is_unsigned)
3563 ig.Emit (OpCodes.Ble_Un, target);
3564 else
3565 ig.Emit (OpCodes.Ble, target);
3566 break;
3568 case Operator.LessThanOrEqual:
3569 if (on_true)
3570 if (is_unsigned && !is_float)
3571 ig.Emit (OpCodes.Ble_Un, target);
3572 else
3573 ig.Emit (OpCodes.Ble, target);
3574 else
3575 if (is_unsigned)
3576 ig.Emit (OpCodes.Bgt_Un, target);
3577 else
3578 ig.Emit (OpCodes.Bgt, target);
3579 break;
3582 case Operator.GreaterThanOrEqual:
3583 if (on_true)
3584 if (is_unsigned && !is_float)
3585 ig.Emit (OpCodes.Bge_Un, target);
3586 else
3587 ig.Emit (OpCodes.Bge, target);
3588 else
3589 if (is_unsigned)
3590 ig.Emit (OpCodes.Blt_Un, target);
3591 else
3592 ig.Emit (OpCodes.Blt, target);
3593 break;
3594 default:
3595 throw new InternalErrorException (oper.ToString ());
3599 public override void Emit (EmitContext ec)
3601 EmitOperator (ec, left.Type);
3604 protected virtual void EmitOperator (EmitContext ec, Type l)
3606 ILGenerator ig = ec.ig;
3609 // Handle short-circuit operators differently
3610 // than the rest
3612 if ((oper & Operator.LogicalMask) != 0) {
3613 Label load_result = ig.DefineLabel ();
3614 Label end = ig.DefineLabel ();
3616 bool is_or = oper == Operator.LogicalOr;
3617 left.EmitBranchable (ec, load_result, is_or);
3618 right.Emit (ec);
3619 ig.Emit (OpCodes.Br_S, end);
3621 ig.MarkLabel (load_result);
3622 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3623 ig.MarkLabel (end);
3624 return;
3627 left.Emit (ec);
3630 // Optimize zero-based operations
3632 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3634 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3635 Constant rc = right as Constant;
3636 if (rc != null && rc.IsDefaultValue) {
3637 return;
3641 right.Emit (ec);
3642 EmitOperatorOpcode (ec, oper, l);
3645 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3646 // expression because that would wrap lifted binary operation
3648 if (enum_conversion != null)
3649 enum_conversion.Emit (ec);
3652 public override void EmitSideEffect (EmitContext ec)
3654 if ((oper & Operator.LogicalMask) != 0 ||
3655 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3656 base.EmitSideEffect (ec);
3657 } else {
3658 left.EmitSideEffect (ec);
3659 right.EmitSideEffect (ec);
3663 protected override void CloneTo (CloneContext clonectx, Expression t)
3665 Binary target = (Binary) t;
3667 target.left = left.Clone (clonectx);
3668 target.right = right.Clone (clonectx);
3671 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3673 Arguments binder_args = new Arguments (4);
3675 MemberAccess sle = new MemberAccess (new MemberAccess (
3676 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3678 MemberAccess binder = DynamicExpressionStatement.GetBinderNamespace (loc);
3680 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3681 binder_args.Add (new Argument (new BoolLiteral (ec.HasSet (ResolveContext.Options.CheckedScope), loc)));
3683 bool member_access = left is DynamicMemberBinder || right is DynamicMemberBinder;
3684 binder_args.Add (new Argument (new BoolLiteral (member_access, loc)));
3685 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (), loc)));
3687 return new New (new MemberAccess (binder, "CSharpBinaryOperationBinder", loc), binder_args, loc);
3690 public override Expression CreateExpressionTree (ResolveContext ec)
3692 return CreateExpressionTree (ec, null);
3695 Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr method)
3697 string method_name;
3698 bool lift_arg = false;
3700 switch (oper) {
3701 case Operator.Addition:
3702 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3703 method_name = "AddChecked";
3704 else
3705 method_name = "Add";
3706 break;
3707 case Operator.BitwiseAnd:
3708 method_name = "And";
3709 break;
3710 case Operator.BitwiseOr:
3711 method_name = "Or";
3712 break;
3713 case Operator.Division:
3714 method_name = "Divide";
3715 break;
3716 case Operator.Equality:
3717 method_name = "Equal";
3718 lift_arg = true;
3719 break;
3720 case Operator.ExclusiveOr:
3721 method_name = "ExclusiveOr";
3722 break;
3723 case Operator.GreaterThan:
3724 method_name = "GreaterThan";
3725 lift_arg = true;
3726 break;
3727 case Operator.GreaterThanOrEqual:
3728 method_name = "GreaterThanOrEqual";
3729 lift_arg = true;
3730 break;
3731 case Operator.Inequality:
3732 method_name = "NotEqual";
3733 lift_arg = true;
3734 break;
3735 case Operator.LeftShift:
3736 method_name = "LeftShift";
3737 break;
3738 case Operator.LessThan:
3739 method_name = "LessThan";
3740 lift_arg = true;
3741 break;
3742 case Operator.LessThanOrEqual:
3743 method_name = "LessThanOrEqual";
3744 lift_arg = true;
3745 break;
3746 case Operator.LogicalAnd:
3747 method_name = "AndAlso";
3748 break;
3749 case Operator.LogicalOr:
3750 method_name = "OrElse";
3751 break;
3752 case Operator.Modulus:
3753 method_name = "Modulo";
3754 break;
3755 case Operator.Multiply:
3756 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3757 method_name = "MultiplyChecked";
3758 else
3759 method_name = "Multiply";
3760 break;
3761 case Operator.RightShift:
3762 method_name = "RightShift";
3763 break;
3764 case Operator.Subtraction:
3765 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3766 method_name = "SubtractChecked";
3767 else
3768 method_name = "Subtract";
3769 break;
3771 default:
3772 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3775 Arguments args = new Arguments (2);
3776 args.Add (new Argument (left.CreateExpressionTree (ec)));
3777 args.Add (new Argument (right.CreateExpressionTree (ec)));
3778 if (method != null) {
3779 if (lift_arg)
3780 args.Add (new Argument (new BoolConstant (false, loc)));
3782 args.Add (new Argument (method.CreateExpressionTree (ec)));
3785 return CreateExpressionFactoryCall (ec, method_name, args);
3790 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3791 // b, c, d... may be strings or objects.
3793 public class StringConcat : Expression {
3794 Arguments arguments;
3796 public StringConcat (Location loc, Expression left, Expression right)
3798 this.loc = loc;
3799 type = TypeManager.string_type;
3800 eclass = ExprClass.Value;
3802 arguments = new Arguments (2);
3803 Append (left);
3804 Append (right);
3807 public override Expression CreateExpressionTree (ResolveContext ec)
3809 Argument arg = arguments [0];
3810 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
3814 // Creates nested calls tree from an array of arguments used for IL emit
3816 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
3818 Arguments concat_args = new Arguments (2);
3819 Arguments add_args = new Arguments (3);
3821 concat_args.Add (left);
3822 add_args.Add (new Argument (left_etree));
3824 concat_args.Add (arguments [pos]);
3825 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
3827 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3828 if (method == null)
3829 return null;
3831 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3832 if (method == null)
3833 return null;
3835 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3837 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
3838 if (++pos == arguments.Count)
3839 return expr;
3841 left = new Argument (new EmptyExpression (((MethodInfo)method).ReturnType));
3842 return CreateExpressionAddCall (ec, left, expr, pos);
3845 public override Expression DoResolve (ResolveContext ec)
3847 return this;
3850 public void Append (Expression operand)
3853 // Constant folding
3855 StringConstant sc = operand as StringConstant;
3856 if (sc != null) {
3857 if (arguments.Count != 0) {
3858 Argument last_argument = arguments [arguments.Count - 1];
3859 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3860 if (last_expr_constant != null) {
3861 last_argument.Expr = new StringConstant (
3862 last_expr_constant.Value + sc.Value, sc.Location);
3863 return;
3866 } else {
3868 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3870 StringConcat concat_oper = operand as StringConcat;
3871 if (concat_oper != null) {
3872 arguments.AddRange (concat_oper.arguments);
3873 return;
3877 arguments.Add (new Argument (operand));
3880 Expression CreateConcatMemberExpression ()
3882 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3885 public override void Emit (EmitContext ec)
3887 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3888 concat = concat.Resolve (new ResolveContext (ec.MemberContext));
3889 if (concat != null)
3890 concat.Emit (ec);
3893 #if NET_4_0
3894 public override SLE.Expression MakeExpression (BuilderContext ctx)
3896 if (arguments.Count != 2)
3897 throw new NotImplementedException ("arguments.Count != 2");
3899 var concat = TypeManager.string_type.GetMethod ("Concat", new[] { typeof (object), typeof (object) });
3900 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
3902 #endif
3904 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3906 arguments.MutateHoistedGenericType (storey);
3911 // User-defined conditional logical operator
3913 public class ConditionalLogicalOperator : UserOperatorCall {
3914 readonly bool is_and;
3915 Expression oper;
3917 public ConditionalLogicalOperator (MethodGroupExpr oper_method, Arguments arguments,
3918 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3919 : base (oper_method, arguments, expr_tree, loc)
3921 this.is_and = is_and;
3924 public override Expression DoResolve (ResolveContext ec)
3926 MethodInfo method = (MethodInfo)mg;
3927 type = TypeManager.TypeToCoreType (method.ReturnType);
3928 AParametersCollection pd = TypeManager.GetParameterData (method);
3929 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3930 ec.Report.Error (217, loc,
3931 "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",
3932 TypeManager.CSharpSignature (method));
3933 return null;
3936 Expression left_dup = new EmptyExpression (type);
3937 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3938 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3939 if (op_true == null || op_false == null) {
3940 ec.Report.Error (218, loc,
3941 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3942 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3943 return null;
3946 oper = is_and ? op_false : op_true;
3947 eclass = ExprClass.Value;
3948 return this;
3951 public override void Emit (EmitContext ec)
3953 ILGenerator ig = ec.ig;
3954 Label end_target = ig.DefineLabel ();
3957 // Emit and duplicate left argument
3959 arguments [0].Expr.Emit (ec);
3960 ig.Emit (OpCodes.Dup);
3961 arguments.RemoveAt (0);
3963 oper.EmitBranchable (ec, end_target, true);
3964 base.Emit (ec);
3965 ig.MarkLabel (end_target);
3969 public class PointerArithmetic : Expression {
3970 Expression left, right;
3971 Binary.Operator op;
3974 // We assume that `l' is always a pointer
3976 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3978 type = t;
3979 this.loc = loc;
3980 left = l;
3981 right = r;
3982 this.op = op;
3985 public override Expression CreateExpressionTree (ResolveContext ec)
3987 Error_PointerInsideExpressionTree (ec);
3988 return null;
3991 public override Expression DoResolve (ResolveContext ec)
3993 eclass = ExprClass.Variable;
3995 if (left.Type == TypeManager.void_ptr_type) {
3996 ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
3997 return null;
4000 return this;
4003 public override void Emit (EmitContext ec)
4005 Type op_type = left.Type;
4006 ILGenerator ig = ec.ig;
4008 // It must be either array or fixed buffer
4009 Type element;
4010 if (TypeManager.HasElementType (op_type)) {
4011 element = TypeManager.GetElementType (op_type);
4012 } else {
4013 FieldExpr fe = left as FieldExpr;
4014 if (fe != null)
4015 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
4016 else
4017 element = op_type;
4020 int size = GetTypeSize (element);
4021 Type rtype = right.Type;
4023 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4025 // handle (pointer - pointer)
4027 left.Emit (ec);
4028 right.Emit (ec);
4029 ig.Emit (OpCodes.Sub);
4031 if (size != 1){
4032 if (size == 0)
4033 ig.Emit (OpCodes.Sizeof, element);
4034 else
4035 IntLiteral.EmitInt (ig, size);
4036 ig.Emit (OpCodes.Div);
4038 ig.Emit (OpCodes.Conv_I8);
4039 } else {
4041 // handle + and - on (pointer op int)
4043 Constant left_const = left as Constant;
4044 if (left_const != null) {
4046 // Optimize ((T*)null) pointer operations
4048 if (left_const.IsDefaultValue) {
4049 left = EmptyExpression.Null;
4050 } else {
4051 left_const = null;
4055 left.Emit (ec);
4057 Constant right_const = right as Constant;
4058 if (right_const != null) {
4060 // Optimize 0-based arithmetic
4062 if (right_const.IsDefaultValue)
4063 return;
4065 if (size != 0) {
4066 // TODO: Should be the checks resolve context sensitive?
4067 ResolveContext rc = new ResolveContext (ec.MemberContext);
4068 right = ConstantFold.BinaryFold (rc, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
4069 if (right == null)
4070 return;
4071 } else {
4072 ig.Emit (OpCodes.Sizeof, element);
4073 right = EmptyExpression.Null;
4077 right.Emit (ec);
4078 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
4079 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
4080 ig.Emit (OpCodes.Conv_I);
4081 } else if (rtype == TypeManager.uint32_type) {
4082 ig.Emit (OpCodes.Conv_U);
4085 if (right_const == null && size != 1){
4086 if (size == 0)
4087 ig.Emit (OpCodes.Sizeof, element);
4088 else
4089 IntLiteral.EmitInt (ig, size);
4090 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
4091 ig.Emit (OpCodes.Conv_I8);
4093 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4096 if (left_const == null) {
4097 if (rtype == TypeManager.int64_type)
4098 ig.Emit (OpCodes.Conv_I);
4099 else if (rtype == TypeManager.uint64_type)
4100 ig.Emit (OpCodes.Conv_U);
4102 Binary.EmitOperatorOpcode (ec, op, op_type);
4109 // A boolean-expression is an expression that yields a result
4110 // of type bool
4112 public class BooleanExpression : Expression
4114 Expression expr;
4116 public BooleanExpression (Expression expr)
4118 this.expr = expr;
4119 this.loc = expr.Location;
4122 protected override void CloneTo (CloneContext clonectx, Expression t)
4124 BooleanExpression target = (BooleanExpression) t;
4125 target.expr = expr.Clone (clonectx);
4128 public override Expression CreateExpressionTree (ResolveContext ec)
4130 // TODO: We should emit IsTrue (v4) instead of direct user operator
4131 // call but that would break csc compatibility
4132 throw new NotSupportedException ();
4135 public override Expression DoResolve (ResolveContext ec)
4137 // A boolean-expression is required to be of a type
4138 // that can be implicitly converted to bool or of
4139 // a type that implements operator true
4141 expr = expr.Resolve (ec);
4142 if (expr == null)
4143 return null;
4145 Assign ass = expr as Assign;
4146 if (ass != null && ass.Source is Constant) {
4147 ec.Report.Warning (665, 3, expr.Location,
4148 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4151 if (expr.Type == TypeManager.bool_type)
4152 return expr;
4154 if (TypeManager.IsDynamicType (expr.Type)) {
4155 Arguments args = new Arguments (1);
4156 args.Add (new Argument (expr));
4157 return new DynamicUnaryConversion ("IsTrue", args, loc).Resolve (ec);
4160 type = TypeManager.bool_type;
4161 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4162 if (converted != null)
4163 return converted;
4166 // If no implicit conversion to bool exists, try using `operator true'
4168 converted = GetOperatorTrue (ec, expr, loc);
4169 if (converted == null) {
4170 expr.Error_ValueCannotBeConverted (ec, loc, type, false);
4171 return null;
4174 return converted;
4177 public override void Emit (EmitContext ec)
4179 throw new InternalErrorException ("Should not be reached");
4183 /// <summary>
4184 /// Implements the ternary conditional operator (?:)
4185 /// </summary>
4186 public class Conditional : Expression {
4187 Expression expr, true_expr, false_expr;
4189 public Conditional (BooleanExpression expr, Expression true_expr, Expression false_expr)
4191 this.expr = expr;
4192 this.true_expr = true_expr;
4193 this.false_expr = false_expr;
4194 this.loc = expr.Location;
4197 public Expression Expr {
4198 get {
4199 return expr;
4203 public Expression TrueExpr {
4204 get {
4205 return true_expr;
4209 public Expression FalseExpr {
4210 get {
4211 return false_expr;
4215 public override Expression CreateExpressionTree (ResolveContext ec)
4217 Arguments args = new Arguments (3);
4218 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4219 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4220 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4221 return CreateExpressionFactoryCall (ec, "Condition", args);
4224 public override Expression DoResolve (ResolveContext ec)
4226 expr = expr.Resolve (ec);
4227 true_expr = true_expr.Resolve (ec);
4228 false_expr = false_expr.Resolve (ec);
4230 if (true_expr == null || false_expr == null || expr == null)
4231 return null;
4233 eclass = ExprClass.Value;
4234 Type true_type = true_expr.Type;
4235 Type false_type = false_expr.Type;
4236 type = true_type;
4239 // First, if an implicit conversion exists from true_expr
4240 // to false_expr, then the result type is of type false_expr.Type
4242 if (!TypeManager.IsEqual (true_type, false_type)) {
4243 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4244 if (conv != null) {
4246 // Check if both can convert implicitl to each other's type
4248 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
4249 ec.Report.Error (172, loc,
4250 "Can not compute type of conditional expression " +
4251 "as `" + TypeManager.CSharpName (true_expr.Type) +
4252 "' and `" + TypeManager.CSharpName (false_expr.Type) +
4253 "' convert implicitly to each other");
4254 return null;
4256 type = false_type;
4257 true_expr = conv;
4258 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4259 false_expr = conv;
4260 } else {
4261 ec.Report.Error (173, loc,
4262 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4263 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
4264 return null;
4268 // Dead code optimalization
4269 Constant c = expr as Constant;
4270 if (c != null){
4271 bool is_false = c.IsDefaultValue;
4272 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
4273 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
4276 return this;
4279 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4281 expr.MutateHoistedGenericType (storey);
4282 true_expr.MutateHoistedGenericType (storey);
4283 false_expr.MutateHoistedGenericType (storey);
4284 type = storey.MutateType (type);
4287 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
4289 return null;
4292 public override void Emit (EmitContext ec)
4294 ILGenerator ig = ec.ig;
4295 Label false_target = ig.DefineLabel ();
4296 Label end_target = ig.DefineLabel ();
4298 expr.EmitBranchable (ec, false_target, false);
4299 true_expr.Emit (ec);
4301 if (type.IsInterface) {
4302 LocalBuilder temp = ec.GetTemporaryLocal (type);
4303 ig.Emit (OpCodes.Stloc, temp);
4304 ig.Emit (OpCodes.Ldloc, temp);
4305 ec.FreeTemporaryLocal (temp, type);
4308 ig.Emit (OpCodes.Br, end_target);
4309 ig.MarkLabel (false_target);
4310 false_expr.Emit (ec);
4311 ig.MarkLabel (end_target);
4314 protected override void CloneTo (CloneContext clonectx, Expression t)
4316 Conditional target = (Conditional) t;
4318 target.expr = expr.Clone (clonectx);
4319 target.true_expr = true_expr.Clone (clonectx);
4320 target.false_expr = false_expr.Clone (clonectx);
4324 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4325 LocalTemporary temp;
4327 #region Abstract
4328 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4329 public abstract bool IsFixed { get; }
4330 public abstract bool IsRef { get; }
4331 public abstract string Name { get; }
4332 public abstract void SetHasAddressTaken ();
4335 // Variable IL data, it has to be protected to encapsulate hoisted variables
4337 protected abstract ILocalVariable Variable { get; }
4340 // Variable flow-analysis data
4342 public abstract VariableInfo VariableInfo { get; }
4343 #endregion
4345 public void AddressOf (EmitContext ec, AddressOp mode)
4347 HoistedVariable hv = GetHoistedVariable (ec);
4348 if (hv != null) {
4349 hv.AddressOf (ec, mode);
4350 return;
4353 Variable.EmitAddressOf (ec);
4356 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4358 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4361 public HoistedVariable GetHoistedVariable (EmitContext ec)
4363 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4366 public override void Emit (EmitContext ec)
4368 Emit (ec, false);
4371 public override void EmitSideEffect (EmitContext ec)
4373 // do nothing
4377 // This method is used by parameters that are references, that are
4378 // being passed as references: we only want to pass the pointer (that
4379 // is already stored in the parameter, not the address of the pointer,
4380 // and not the value of the variable).
4382 public void EmitLoad (EmitContext ec)
4384 Variable.Emit (ec);
4387 public void Emit (EmitContext ec, bool leave_copy)
4389 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4391 HoistedVariable hv = GetHoistedVariable (ec);
4392 if (hv != null) {
4393 hv.Emit (ec, leave_copy);
4394 return;
4397 EmitLoad (ec);
4399 if (IsRef) {
4401 // If we are a reference, we loaded on the stack a pointer
4402 // Now lets load the real value
4404 LoadFromPtr (ec.ig, type);
4407 if (leave_copy) {
4408 ec.ig.Emit (OpCodes.Dup);
4410 if (IsRef) {
4411 temp = new LocalTemporary (Type);
4412 temp.Store (ec);
4417 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4418 bool prepare_for_load)
4420 HoistedVariable hv = GetHoistedVariable (ec);
4421 if (hv != null) {
4422 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4423 return;
4426 New n_source = source as New;
4427 if (n_source != null) {
4428 if (!n_source.Emit (ec, this)) {
4429 if (leave_copy)
4430 EmitLoad (ec);
4431 return;
4433 } else {
4434 if (IsRef)
4435 EmitLoad (ec);
4437 source.Emit (ec);
4440 if (leave_copy) {
4441 ec.ig.Emit (OpCodes.Dup);
4442 if (IsRef) {
4443 temp = new LocalTemporary (Type);
4444 temp.Store (ec);
4448 if (IsRef)
4449 StoreFromPtr (ec.ig, type);
4450 else
4451 Variable.EmitAssign (ec);
4453 if (temp != null) {
4454 temp.Emit (ec);
4455 temp.Release (ec);
4459 public bool IsHoisted {
4460 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4463 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4465 type = storey.MutateType (type);
4469 /// <summary>
4470 /// Local variables
4471 /// </summary>
4472 public class LocalVariableReference : VariableReference {
4473 readonly string name;
4474 public Block Block;
4475 public LocalInfo local_info;
4476 bool is_readonly;
4477 bool resolved; // TODO: merge with eclass
4479 public LocalVariableReference (Block block, string name, Location l)
4481 Block = block;
4482 this.name = name;
4483 loc = l;
4487 // Setting `is_readonly' to false will allow you to create a writable
4488 // reference to a read-only variable. This is used by foreach and using.
4490 public LocalVariableReference (Block block, string name, Location l,
4491 LocalInfo local_info, bool is_readonly)
4492 : this (block, name, l)
4494 this.local_info = local_info;
4495 this.is_readonly = is_readonly;
4498 public override VariableInfo VariableInfo {
4499 get { return local_info.VariableInfo; }
4502 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4504 return local_info.HoistedVariableReference;
4508 // A local variable is always fixed
4510 public override bool IsFixed {
4511 get { return true; }
4514 public override bool IsRef {
4515 get { return false; }
4518 public bool IsReadOnly {
4519 get { return is_readonly; }
4522 public override string Name {
4523 get { return name; }
4526 public bool VerifyAssigned (ResolveContext ec)
4528 VariableInfo variable_info = local_info.VariableInfo;
4529 return variable_info == null || variable_info.IsAssigned (ec, loc);
4532 void ResolveLocalInfo ()
4534 if (local_info == null) {
4535 local_info = Block.GetLocalInfo (Name);
4536 type = local_info.VariableType;
4537 is_readonly = local_info.ReadOnly;
4541 public override void SetHasAddressTaken ()
4543 local_info.AddressTaken = true;
4546 public override Expression CreateExpressionTree (ResolveContext ec)
4548 HoistedVariable hv = GetHoistedVariable (ec);
4549 if (hv != null)
4550 return hv.CreateExpressionTree (ec);
4552 Arguments arg = new Arguments (1);
4553 arg.Add (new Argument (this));
4554 return CreateExpressionFactoryCall (ec, "Constant", arg);
4557 Expression DoResolveBase (ResolveContext ec)
4559 type = local_info.VariableType;
4561 Expression e = Block.GetConstantExpression (Name);
4562 if (e != null)
4563 return e.Resolve (ec);
4565 VerifyAssigned (ec);
4568 // If we are referencing a variable from the external block
4569 // flag it for capturing
4571 if (ec.MustCaptureVariable (local_info)) {
4572 if (local_info.AddressTaken)
4573 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4575 if (ec.IsVariableCapturingRequired) {
4576 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4577 storey.CaptureLocalVariable (ec, local_info);
4581 resolved |= ec.DoFlowAnalysis;
4582 eclass = ExprClass.Variable;
4583 return this;
4586 public override Expression DoResolve (ResolveContext ec)
4588 if (resolved)
4589 return this;
4591 ResolveLocalInfo ();
4592 local_info.Used = true;
4594 if (type == null && local_info.Type is VarExpr) {
4595 local_info.VariableType = TypeManager.object_type;
4596 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
4597 return null;
4600 return DoResolveBase (ec);
4603 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4605 ResolveLocalInfo ();
4607 // is out param
4608 if (right_side == EmptyExpression.OutAccess)
4609 local_info.Used = true;
4611 // Infer implicitly typed local variable
4612 if (type == null) {
4613 VarExpr ve = local_info.Type as VarExpr;
4614 if (ve != null) {
4615 if (!ve.InferType (ec, right_side))
4616 return null;
4617 type = local_info.VariableType = ve.Type;
4621 if (is_readonly) {
4622 int code;
4623 string msg;
4624 if (right_side == EmptyExpression.OutAccess) {
4625 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4626 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4627 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4628 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4629 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4630 } else if (right_side == EmptyExpression.UnaryAddress) {
4631 code = 459; msg = "Cannot take the address of {1} `{0}'";
4632 } else {
4633 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4635 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4636 } else if (VariableInfo != null) {
4637 VariableInfo.SetAssigned (ec);
4640 return DoResolveBase (ec);
4643 public override int GetHashCode ()
4645 return Name.GetHashCode ();
4648 public override bool Equals (object obj)
4650 LocalVariableReference lvr = obj as LocalVariableReference;
4651 if (lvr == null)
4652 return false;
4654 return Name == lvr.Name && Block == lvr.Block;
4657 protected override ILocalVariable Variable {
4658 get { return local_info; }
4661 public override string ToString ()
4663 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4666 protected override void CloneTo (CloneContext clonectx, Expression t)
4668 LocalVariableReference target = (LocalVariableReference) t;
4670 target.Block = clonectx.LookupBlock (Block);
4671 if (local_info != null)
4672 target.local_info = clonectx.LookupVariable (local_info);
4676 /// <summary>
4677 /// This represents a reference to a parameter in the intermediate
4678 /// representation.
4679 /// </summary>
4680 public class ParameterReference : VariableReference {
4681 readonly ToplevelParameterInfo pi;
4683 public ParameterReference (ToplevelParameterInfo pi, Location loc)
4685 this.pi = pi;
4686 this.loc = loc;
4689 public override bool IsRef {
4690 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4693 bool HasOutModifier {
4694 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4697 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4699 return pi.Parameter.HoistedVariableReference;
4703 // A ref or out parameter is classified as a moveable variable, even
4704 // if the argument given for the parameter is a fixed variable
4706 public override bool IsFixed {
4707 get { return !IsRef; }
4710 public override string Name {
4711 get { return Parameter.Name; }
4714 public Parameter Parameter {
4715 get { return pi.Parameter; }
4718 public override VariableInfo VariableInfo {
4719 get { return pi.VariableInfo; }
4722 protected override ILocalVariable Variable {
4723 get { return Parameter; }
4726 public bool IsAssigned (ResolveContext ec, Location loc)
4728 // HACK: Variables are not captured in probing mode
4729 if (ec.IsInProbingMode)
4730 return true;
4732 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4733 return true;
4735 ec.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4736 return false;
4739 public override void SetHasAddressTaken ()
4741 Parameter.HasAddressTaken = true;
4744 void SetAssigned (ResolveContext ec)
4746 if (HasOutModifier && ec.DoFlowAnalysis)
4747 ec.CurrentBranching.SetAssigned (VariableInfo);
4750 bool DoResolveBase (ResolveContext ec)
4752 type = pi.ParameterType;
4753 eclass = ExprClass.Variable;
4755 AnonymousExpression am = ec.CurrentAnonymousMethod;
4756 if (am == null)
4757 return true;
4759 Block b = ec.CurrentBlock;
4760 while (b != null) {
4761 IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
4762 for (int i = 0; i < p.Length; ++i) {
4763 if (p [i] != Parameter)
4764 continue;
4767 // Skip closest anonymous method parameters
4769 if (b == ec.CurrentBlock && !am.IsIterator)
4770 return true;
4772 if (IsRef) {
4773 ec.Report.Error (1628, loc,
4774 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4775 Name, am.ContainerType);
4778 b = null;
4779 break;
4782 if (b != null)
4783 b = b.Toplevel.Parent;
4786 if (pi.Parameter.HasAddressTaken)
4787 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4789 if (ec.IsVariableCapturingRequired) {
4790 AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
4791 storey.CaptureParameter (ec, this);
4794 return true;
4797 public override int GetHashCode ()
4799 return Name.GetHashCode ();
4802 public override bool Equals (object obj)
4804 ParameterReference pr = obj as ParameterReference;
4805 if (pr == null)
4806 return false;
4808 return Name == pr.Name;
4811 protected override void CloneTo (CloneContext clonectx, Expression target)
4813 // Nothing to clone
4816 public override Expression CreateExpressionTree (ResolveContext ec)
4818 HoistedVariable hv = GetHoistedVariable (ec);
4819 if (hv != null)
4820 return hv.CreateExpressionTree (ec);
4822 return Parameter.ExpressionTreeVariableReference ();
4826 // Notice that for ref/out parameters, the type exposed is not the
4827 // same type exposed externally.
4829 // for "ref int a":
4830 // externally we expose "int&"
4831 // here we expose "int".
4833 // We record this in "is_ref". This means that the type system can treat
4834 // the type as it is expected, but when we generate the code, we generate
4835 // the alternate kind of code.
4837 public override Expression DoResolve (ResolveContext ec)
4839 if (!DoResolveBase (ec))
4840 return null;
4842 // HACK: Variables are not captured in probing mode
4843 if (ec.IsInProbingMode)
4844 return this;
4846 if (HasOutModifier && ec.DoFlowAnalysis &&
4847 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4848 return null;
4850 return this;
4853 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4855 if (!DoResolveBase (ec))
4856 return null;
4858 // HACK: parameters are not captured when probing is on
4859 if (!ec.IsInProbingMode)
4860 SetAssigned (ec);
4862 return this;
4865 static public void EmitLdArg (ILGenerator ig, int x)
4867 switch (x) {
4868 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4869 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4870 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4871 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4872 default:
4873 if (x > byte.MaxValue)
4874 ig.Emit (OpCodes.Ldarg, x);
4875 else
4876 ig.Emit (OpCodes.Ldarg_S, (byte) x);
4877 break;
4882 /// <summary>
4883 /// Invocation of methods or delegates.
4884 /// </summary>
4885 public class Invocation : ExpressionStatement
4887 protected Arguments arguments;
4888 protected Expression expr;
4889 protected MethodGroupExpr mg;
4890 bool arguments_resolved;
4893 // arguments is an ArrayList, but we do not want to typecast,
4894 // as it might be null.
4896 public Invocation (Expression expr, Arguments arguments)
4898 SimpleName sn = expr as SimpleName;
4899 if (sn != null)
4900 this.expr = sn.GetMethodGroup ();
4901 else
4902 this.expr = expr;
4904 this.arguments = arguments;
4905 if (expr != null)
4906 loc = expr.Location;
4909 public Invocation (Expression expr, Arguments arguments, bool arguments_resolved)
4910 : this (expr, arguments)
4912 this.arguments_resolved = arguments_resolved;
4915 public override Expression CreateExpressionTree (ResolveContext ec)
4917 Arguments args;
4920 // Special conversion for nested expression trees
4922 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4923 args = new Arguments (1);
4924 args.Add (new Argument (this));
4925 return CreateExpressionFactoryCall (ec, "Quote", args);
4928 Expression instance = mg.IsInstance ?
4929 mg.InstanceExpression.CreateExpressionTree (ec) :
4930 new NullLiteral (loc);
4932 args = Arguments.CreateForExpressionTree (ec, arguments,
4933 instance,
4934 mg.CreateExpressionTree (ec));
4936 if (mg.IsBase)
4937 MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
4939 return CreateExpressionFactoryCall (ec, "Call", args);
4942 public override Expression DoResolve (ResolveContext ec)
4944 // Don't resolve already resolved expression
4945 if (eclass != ExprClass.Invalid)
4946 return this;
4948 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4949 if (expr_resolved == null)
4950 return null;
4953 // Next, evaluate all the expressions in the argument list
4955 bool dynamic_arg = false;
4956 if (arguments != null && !arguments_resolved)
4957 arguments.Resolve (ec, out dynamic_arg);
4959 Type expr_type = expr_resolved.Type;
4960 mg = expr_resolved as MethodGroupExpr;
4962 if (dynamic_arg || TypeManager.IsDynamicType (expr_type)) {
4963 Arguments args;
4964 DynamicMemberBinder dmb = expr_resolved as DynamicMemberBinder;
4965 if (dmb != null) {
4966 args = dmb.Arguments;
4967 if (arguments != null)
4968 args.AddRange (arguments);
4969 } else if (mg == null) {
4970 if (arguments == null)
4971 args = new Arguments (1);
4972 else
4973 args = arguments;
4975 args.Insert (0, new Argument (expr_resolved));
4976 expr = null;
4977 } else {
4978 if (mg.IsBase) {
4979 ec.Report.Error (1971, loc,
4980 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
4981 mg.Name);
4982 return null;
4985 args = arguments;
4987 if (mg.IsStatic != mg.IsInstance) {
4988 if (args == null)
4989 args = new Arguments (1);
4991 if (mg.IsStatic) {
4992 args.Insert (0, new Argument (new TypeOf (new TypeExpression (mg.DeclaringType, loc), loc).Resolve (ec), Argument.AType.DynamicStatic));
4993 } else {
4994 MemberAccess ma = expr as MemberAccess;
4995 if (ma != null)
4996 args.Insert (0, new Argument (ma.Left.Resolve (ec)));
4997 else
4998 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5003 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5006 if (mg == null) {
5007 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
5008 return (new DelegateInvocation (
5009 expr_resolved, arguments, loc)).Resolve (ec);
5012 MemberExpr me = expr_resolved as MemberExpr;
5013 if (me == null) {
5014 expr_resolved.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5015 return null;
5018 mg = ec.LookupExtensionMethod (me.Type, me.Name, loc);
5019 if (mg == null) {
5020 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
5021 expr_resolved.GetSignatureForError ());
5022 return null;
5025 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
5028 mg = DoResolveOverload (ec);
5029 if (mg == null)
5030 return null;
5032 MethodInfo method = (MethodInfo)mg;
5033 if (method != null) {
5034 type = TypeManager.TypeToCoreType (method.ReturnType);
5036 // TODO: this is a copy of mg.ResolveMemberAccess method
5037 Expression iexpr = mg.InstanceExpression;
5038 if (method.IsStatic) {
5039 if (iexpr == null ||
5040 iexpr is This || iexpr is EmptyExpression ||
5041 mg.IdenticalTypeName) {
5042 mg.InstanceExpression = null;
5043 } else {
5044 MemberExpr.error176 (ec, loc, mg.GetSignatureForError ());
5045 return null;
5047 } else {
5048 if (iexpr == null || iexpr == EmptyExpression.Null) {
5049 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
5054 if (type.IsPointer){
5055 if (!ec.IsUnsafe){
5056 UnsafeError (ec, loc);
5057 return null;
5062 // Only base will allow this invocation to happen.
5064 if (mg.IsBase && method.IsAbstract){
5065 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature (method));
5066 return null;
5069 if (arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
5070 if (mg.IsBase)
5071 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5072 else
5073 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5074 return null;
5077 IsSpecialMethodInvocation (ec, method, loc);
5079 if (mg.InstanceExpression != null)
5080 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
5082 eclass = ExprClass.Value;
5083 return this;
5086 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5088 return mg.OverloadResolve (ec, ref arguments, false, loc);
5091 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodBase method, Location loc)
5093 if (!TypeManager.IsSpecialMethod (method))
5094 return false;
5096 ec.Report.SymbolRelatedToPreviousError (method);
5097 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5098 TypeManager.CSharpSignature (method, true));
5100 return true;
5103 static Type[] GetVarargsTypes (MethodBase mb, Arguments arguments)
5105 AParametersCollection pd = TypeManager.GetParameterData (mb);
5107 Argument a = arguments [pd.Count - 1];
5108 Arglist list = (Arglist) a.Expr;
5110 return list.ArgumentTypes;
5113 /// <summary>
5114 /// This checks the ConditionalAttribute on the method
5115 /// </summary>
5116 public static bool IsMethodExcluded (MethodBase method, Location loc)
5118 if (method.IsConstructor)
5119 return false;
5121 method = TypeManager.DropGenericMethodArguments (method);
5122 if (method.DeclaringType.Module == RootContext.ToplevelTypes.Builder) {
5123 IMethodData md = TypeManager.GetMethod (method);
5124 if (md != null)
5125 return md.IsExcluded ();
5127 // For some methods (generated by delegate class) GetMethod returns null
5128 // because they are not included in builder_to_method table
5129 return false;
5132 return AttributeTester.IsConditionalMethodExcluded (method, loc);
5135 /// <remarks>
5136 /// is_base tells whether we want to force the use of the `call'
5137 /// opcode instead of using callvirt. Call is required to call
5138 /// a specific method, while callvirt will always use the most
5139 /// recent method in the vtable.
5141 /// is_static tells whether this is an invocation on a static method
5143 /// instance_expr is an expression that represents the instance
5144 /// it must be non-null if is_static is false.
5146 /// method is the method to invoke.
5148 /// Arguments is the list of arguments to pass to the method or constructor.
5149 /// </remarks>
5150 public static void EmitCall (EmitContext ec, bool is_base,
5151 Expression instance_expr,
5152 MethodBase method, Arguments Arguments, Location loc)
5154 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
5157 // `dup_args' leaves an extra copy of the arguments on the stack
5158 // `omit_args' does not leave any arguments at all.
5159 // So, basically, you could make one call with `dup_args' set to true,
5160 // and then another with `omit_args' set to true, and the two calls
5161 // would have the same set of arguments. However, each argument would
5162 // only have been evaluated once.
5163 public static void EmitCall (EmitContext ec, bool is_base,
5164 Expression instance_expr,
5165 MethodBase method, Arguments Arguments, Location loc,
5166 bool dup_args, bool omit_args)
5168 ILGenerator ig = ec.ig;
5169 bool struct_call = false;
5170 bool this_call = false;
5171 LocalTemporary this_arg = null;
5173 Type decl_type = method.DeclaringType;
5175 if (IsMethodExcluded (method, loc))
5176 return;
5178 bool is_static = method.IsStatic;
5179 if (!is_static){
5180 this_call = instance_expr is This;
5181 if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type))
5182 struct_call = true;
5185 // If this is ourselves, push "this"
5187 if (!omit_args) {
5188 Type t = null;
5189 Type iexpr_type = instance_expr.Type;
5192 // Push the instance expression
5194 if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
5196 // Special case: calls to a function declared in a
5197 // reference-type with a value-type argument need
5198 // to have their value boxed.
5199 if (TypeManager.IsStruct (decl_type) ||
5200 TypeManager.IsGenericParameter (iexpr_type)) {
5202 // If the expression implements IMemoryLocation, then
5203 // we can optimize and use AddressOf on the
5204 // return.
5206 // If not we have to use some temporary storage for
5207 // it.
5208 if (instance_expr is IMemoryLocation) {
5209 ((IMemoryLocation)instance_expr).
5210 AddressOf (ec, AddressOp.LoadStore);
5211 } else {
5212 LocalTemporary temp = new LocalTemporary (iexpr_type);
5213 instance_expr.Emit (ec);
5214 temp.Store (ec);
5215 temp.AddressOf (ec, AddressOp.Load);
5218 // avoid the overhead of doing this all the time.
5219 if (dup_args)
5220 t = TypeManager.GetReferenceType (iexpr_type);
5221 } else {
5222 instance_expr.Emit (ec);
5224 // FIXME: should use instance_expr is IMemoryLocation + constraint.
5225 // to help JIT to produce better code
5226 ig.Emit (OpCodes.Box, instance_expr.Type);
5227 t = TypeManager.object_type;
5229 } else {
5230 instance_expr.Emit (ec);
5231 t = instance_expr.Type;
5234 if (dup_args) {
5235 ig.Emit (OpCodes.Dup);
5236 if (Arguments != null && Arguments.Count != 0) {
5237 this_arg = new LocalTemporary (t);
5238 this_arg.Store (ec);
5244 if (!omit_args && Arguments != null)
5245 Arguments.Emit (ec, dup_args, this_arg);
5247 OpCode call_op;
5248 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
5249 call_op = OpCodes.Call;
5250 } else {
5251 call_op = OpCodes.Callvirt;
5253 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5254 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5257 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5258 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5259 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5260 return;
5264 // If you have:
5265 // this.DoFoo ();
5266 // and DoFoo is not virtual, you can omit the callvirt,
5267 // because you don't need the null checking behavior.
5269 if (method is MethodInfo)
5270 ig.Emit (call_op, (MethodInfo) method);
5271 else
5272 ig.Emit (call_op, (ConstructorInfo) method);
5275 public override void Emit (EmitContext ec)
5277 mg.EmitCall (ec, arguments);
5280 public override void EmitStatement (EmitContext ec)
5282 Emit (ec);
5285 // Pop the return value if there is one
5287 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5288 ec.ig.Emit (OpCodes.Pop);
5291 protected override void CloneTo (CloneContext clonectx, Expression t)
5293 Invocation target = (Invocation) t;
5295 if (arguments != null)
5296 target.arguments = arguments.Clone (clonectx);
5298 target.expr = expr.Clone (clonectx);
5301 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5303 mg.MutateHoistedGenericType (storey);
5304 type = storey.MutateType (type);
5305 if (arguments != null) {
5306 arguments.MutateHoistedGenericType (storey);
5312 // It's either a cast or delegate invocation
5314 public class InvocationOrCast : ExpressionStatement
5316 Expression expr;
5317 Expression argument;
5319 public InvocationOrCast (Expression expr, Expression argument)
5321 this.expr = expr;
5322 this.argument = argument;
5323 this.loc = expr.Location;
5326 public override Expression CreateExpressionTree (ResolveContext ec)
5328 throw new NotSupportedException ("ET");
5331 public override Expression DoResolve (ResolveContext ec)
5333 Expression e = ResolveCore (ec);
5334 if (e == null)
5335 return null;
5337 return e.Resolve (ec);
5340 Expression ResolveCore (EmitContext ec)
5343 // First try to resolve it as a cast.
5345 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5346 if (te != null) {
5347 return new Cast (te, argument, loc);
5351 // This can either be a type or a delegate invocation.
5352 // Let's just resolve it and see what we'll get.
5354 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5355 if (expr == null)
5356 return null;
5359 // Ok, so it's a Cast.
5361 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5362 return new Cast (expr, argument, loc);
5365 if (expr.eclass == ExprClass.Namespace) {
5366 expr.Error_UnexpectedKind (null, "type", loc);
5367 return null;
5371 // It's a delegate invocation.
5373 if (!TypeManager.IsDelegateType (expr.Type)) {
5374 Error (149, "Method name expected");
5375 return null;
5378 ArrayList args = new ArrayList (1);
5379 args.Add (new Argument (argument, Argument.AType.Expression));
5380 return new DelegateInvocation (expr, args, loc);
5383 public override ExpressionStatement ResolveStatement (EmitContext ec)
5385 Expression e = ResolveCore (ec);
5386 if (e == null)
5387 return null;
5389 ExpressionStatement s = e as ExpressionStatement;
5390 if (s == null) {
5391 Error_InvalidExpressionStatement ();
5392 return null;
5395 return s.ResolveStatement (ec);
5398 public override void Emit (EmitContext ec)
5400 throw new Exception ("Cannot happen");
5403 public override void EmitStatement (EmitContext ec)
5405 throw new Exception ("Cannot happen");
5408 protected override void CloneTo (CloneContext clonectx, Expression t)
5410 InvocationOrCast target = (InvocationOrCast) t;
5412 target.expr = expr.Clone (clonectx);
5413 target.argument = argument.Clone (clonectx);
5418 /// <summary>
5419 /// Implements the new expression
5420 /// </summary>
5421 public class New : ExpressionStatement, IMemoryLocation {
5422 Arguments Arguments;
5425 // During bootstrap, it contains the RequestedType,
5426 // but if `type' is not null, it *might* contain a NewDelegate
5427 // (because of field multi-initialization)
5429 Expression RequestedType;
5431 MethodGroupExpr method;
5433 bool is_type_parameter;
5435 public New (Expression requested_type, Arguments arguments, Location l)
5437 RequestedType = requested_type;
5438 Arguments = arguments;
5439 loc = l;
5442 /// <summary>
5443 /// Converts complex core type syntax like 'new int ()' to simple constant
5444 /// </summary>
5445 public static Constant Constantify (Type t)
5447 if (t == TypeManager.int32_type)
5448 return new IntConstant (0, Location.Null);
5449 if (t == TypeManager.uint32_type)
5450 return new UIntConstant (0, Location.Null);
5451 if (t == TypeManager.int64_type)
5452 return new LongConstant (0, Location.Null);
5453 if (t == TypeManager.uint64_type)
5454 return new ULongConstant (0, Location.Null);
5455 if (t == TypeManager.float_type)
5456 return new FloatConstant (0, Location.Null);
5457 if (t == TypeManager.double_type)
5458 return new DoubleConstant (0, Location.Null);
5459 if (t == TypeManager.short_type)
5460 return new ShortConstant (0, Location.Null);
5461 if (t == TypeManager.ushort_type)
5462 return new UShortConstant (0, Location.Null);
5463 if (t == TypeManager.sbyte_type)
5464 return new SByteConstant (0, Location.Null);
5465 if (t == TypeManager.byte_type)
5466 return new ByteConstant (0, Location.Null);
5467 if (t == TypeManager.char_type)
5468 return new CharConstant ('\0', Location.Null);
5469 if (t == TypeManager.bool_type)
5470 return new BoolConstant (false, Location.Null);
5471 if (t == TypeManager.decimal_type)
5472 return new DecimalConstant (0, Location.Null);
5473 if (TypeManager.IsEnumType (t))
5474 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5475 if (TypeManager.IsNullableType (t))
5476 return Nullable.LiftedNull.Create (t, Location.Null);
5478 return null;
5482 // Checks whether the type is an interface that has the
5483 // [ComImport, CoClass] attributes and must be treated
5484 // specially
5486 public Expression CheckComImport (ResolveContext ec)
5488 if (!type.IsInterface)
5489 return null;
5492 // Turn the call into:
5493 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5495 Type real_class = AttributeTester.GetCoClassAttribute (type);
5496 if (real_class == null)
5497 return null;
5499 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5500 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5501 return cast.Resolve (ec);
5504 public override Expression CreateExpressionTree (ResolveContext ec)
5506 Arguments args;
5507 if (method == null) {
5508 args = new Arguments (1);
5509 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5510 } else {
5511 args = Arguments.CreateForExpressionTree (ec, Arguments,
5512 method.CreateExpressionTree (ec));
5515 return CreateExpressionFactoryCall (ec, "New", args);
5518 public override Expression DoResolve (ResolveContext ec)
5521 // The New DoResolve might be called twice when initializing field
5522 // expressions (see EmitFieldInitializers, the call to
5523 // GetInitializerExpression will perform a resolve on the expression,
5524 // and later the assign will trigger another resolution
5526 // This leads to bugs (#37014)
5528 if (type != null){
5529 if (RequestedType is NewDelegate)
5530 return RequestedType;
5531 return this;
5534 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5535 if (texpr == null)
5536 return null;
5538 type = texpr.Type;
5540 if (type.IsPointer) {
5541 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5542 TypeManager.CSharpName (type));
5543 return null;
5546 if (Arguments == null) {
5547 Constant c = Constantify (type);
5548 if (c != null)
5549 return ReducedExpression.Create (c, this);
5552 if (TypeManager.IsDelegateType (type)) {
5553 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5556 if (TypeManager.IsGenericParameter (type)) {
5557 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5559 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5560 ec.Report.Error (304, loc,
5561 "Cannot create an instance of the variable type '{0}' because it doesn't have the new() constraint",
5562 TypeManager.CSharpName (type));
5563 return null;
5566 if ((Arguments != null) && (Arguments.Count != 0)) {
5567 ec.Report.Error (417, loc,
5568 "`{0}': cannot provide arguments when creating an instance of a variable type",
5569 TypeManager.CSharpName (type));
5570 return null;
5573 if (TypeManager.activator_create_instance == null) {
5574 Type activator_type = TypeManager.CoreLookupType (ec.Compiler, "System", "Activator", Kind.Class, true);
5575 if (activator_type != null) {
5576 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5577 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5581 is_type_parameter = true;
5582 eclass = ExprClass.Value;
5583 return this;
5586 if (type.IsAbstract && type.IsSealed) {
5587 ec.Report.SymbolRelatedToPreviousError (type);
5588 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5589 return null;
5592 if (type.IsInterface || type.IsAbstract){
5593 if (!TypeManager.IsGenericType (type)) {
5594 RequestedType = CheckComImport (ec);
5595 if (RequestedType != null)
5596 return RequestedType;
5599 ec.Report.SymbolRelatedToPreviousError (type);
5600 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5601 return null;
5604 bool is_struct = TypeManager.IsStruct (type);
5605 eclass = ExprClass.Value;
5608 // SRE returns a match for .ctor () on structs (the object constructor),
5609 // so we have to manually ignore it.
5611 if (is_struct && Arguments == null)
5612 return this;
5614 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5615 Expression ml = MemberLookupFinal (ec, type, type, ConstructorInfo.ConstructorName,
5616 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5618 if (Arguments != null) {
5619 bool dynamic;
5620 Arguments.Resolve (ec, out dynamic);
5622 if (dynamic) {
5623 Arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec)));
5624 return new DynamicInvocation (new SimpleName (ConstructorInfo.ConstructorName, loc), Arguments, type, loc).Resolve (ec);
5628 if (ml == null)
5629 return null;
5631 method = ml as MethodGroupExpr;
5632 if (method == null) {
5633 ml.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5634 return null;
5637 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5638 if (method == null)
5639 return null;
5641 return this;
5644 bool DoEmitTypeParameter (EmitContext ec)
5646 ILGenerator ig = ec.ig;
5648 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5649 new Type [] { type });
5651 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5652 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5653 ig.Emit (OpCodes.Call, ci);
5654 return true;
5657 // Allow DoEmit() to be called multiple times.
5658 // We need to create a new LocalTemporary each time since
5659 // you can't share LocalBuilders among ILGeneators.
5660 LocalTemporary temp = new LocalTemporary (type);
5662 Label label_activator = ig.DefineLabel ();
5663 Label label_end = ig.DefineLabel ();
5665 temp.AddressOf (ec, AddressOp.Store);
5666 ig.Emit (OpCodes.Initobj, type);
5668 temp.Emit (ec);
5669 ig.Emit (OpCodes.Box, type);
5670 ig.Emit (OpCodes.Brfalse, label_activator);
5672 temp.AddressOf (ec, AddressOp.Store);
5673 ig.Emit (OpCodes.Initobj, type);
5674 temp.Emit (ec);
5675 ig.Emit (OpCodes.Br_S, label_end);
5677 ig.MarkLabel (label_activator);
5679 ig.Emit (OpCodes.Call, ci);
5680 ig.MarkLabel (label_end);
5681 return true;
5685 // This Emit can be invoked in two contexts:
5686 // * As a mechanism that will leave a value on the stack (new object)
5687 // * As one that wont (init struct)
5689 // If we are dealing with a ValueType, we have a few
5690 // situations to deal with:
5692 // * The target is a ValueType, and we have been provided
5693 // the instance (this is easy, we are being assigned).
5695 // * The target of New is being passed as an argument,
5696 // to a boxing operation or a function that takes a
5697 // ValueType.
5699 // In this case, we need to create a temporary variable
5700 // that is the argument of New.
5702 // Returns whether a value is left on the stack
5704 // *** Implementation note ***
5706 // To benefit from this optimization, each assignable expression
5707 // has to manually cast to New and call this Emit.
5709 // TODO: It's worth to implement it for arrays and fields
5711 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5713 bool is_value_type = TypeManager.IsValueType (type);
5714 ILGenerator ig = ec.ig;
5715 VariableReference vr = target as VariableReference;
5717 if (target != null && is_value_type && (vr != null || method == null)) {
5718 target.AddressOf (ec, AddressOp.Store);
5719 } else if (vr != null && vr.IsRef) {
5720 vr.EmitLoad (ec);
5723 if (Arguments != null)
5724 Arguments.Emit (ec);
5726 if (is_value_type) {
5727 if (method == null) {
5728 ig.Emit (OpCodes.Initobj, type);
5729 return false;
5732 if (vr != null) {
5733 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5734 return false;
5738 if (is_type_parameter)
5739 return DoEmitTypeParameter (ec);
5741 ConstructorInfo ci = (ConstructorInfo) method;
5742 #if MS_COMPATIBLE
5743 if (TypeManager.IsGenericType (type) && type.IsGenericTypeDefinition)
5744 ci = TypeBuilder.GetConstructor (type, ci);
5745 #endif
5747 ig.Emit (OpCodes.Newobj, ci);
5748 return true;
5751 public override void Emit (EmitContext ec)
5753 LocalTemporary v = null;
5754 if (method == null && TypeManager.IsValueType (type)) {
5755 // TODO: Use temporary variable from pool
5756 v = new LocalTemporary (type);
5759 if (!Emit (ec, v))
5760 v.Emit (ec);
5763 public override void EmitStatement (EmitContext ec)
5765 LocalTemporary v = null;
5766 if (method == null && TypeManager.IsValueType (type)) {
5767 // TODO: Use temporary variable from pool
5768 v = new LocalTemporary (type);
5771 if (Emit (ec, v))
5772 ec.ig.Emit (OpCodes.Pop);
5775 public bool IsDefaultValueType {
5776 get {
5777 return TypeManager.IsValueType (type) && !HasInitializer && Arguments == null;
5781 public virtual bool HasInitializer {
5782 get {
5783 return false;
5787 public void AddressOf (EmitContext ec, AddressOp mode)
5789 EmitAddressOf (ec, mode);
5792 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5794 LocalTemporary value_target = new LocalTemporary (type);
5796 if (is_type_parameter) {
5797 DoEmitTypeParameter (ec);
5798 value_target.Store (ec);
5799 value_target.AddressOf (ec, mode);
5800 return value_target;
5803 if (!TypeManager.IsStruct (type)){
5805 // We throw an exception. So far, I believe we only need to support
5806 // value types:
5807 // foreach (int j in new StructType ())
5808 // see bug 42390
5810 throw new Exception ("AddressOf should not be used for classes");
5813 value_target.AddressOf (ec, AddressOp.Store);
5815 if (method == null) {
5816 ec.ig.Emit (OpCodes.Initobj, type);
5817 } else {
5818 if (Arguments != null)
5819 Arguments.Emit (ec);
5821 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5824 value_target.AddressOf (ec, mode);
5825 return value_target;
5828 protected override void CloneTo (CloneContext clonectx, Expression t)
5830 New target = (New) t;
5832 target.RequestedType = RequestedType.Clone (clonectx);
5833 if (Arguments != null){
5834 target.Arguments = Arguments.Clone (clonectx);
5838 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5840 if (method != null) {
5841 method.MutateHoistedGenericType (storey);
5842 if (Arguments != null) {
5843 Arguments.MutateHoistedGenericType (storey);
5847 type = storey.MutateType (type);
5851 /// <summary>
5852 /// 14.5.10.2: Represents an array creation expression.
5853 /// </summary>
5855 /// <remarks>
5856 /// There are two possible scenarios here: one is an array creation
5857 /// expression that specifies the dimensions and optionally the
5858 /// initialization data and the other which does not need dimensions
5859 /// specified but where initialization data is mandatory.
5860 /// </remarks>
5861 public class ArrayCreation : Expression {
5862 FullNamedExpression requested_base_type;
5863 ArrayList initializers;
5866 // The list of Argument types.
5867 // This is used to construct the `newarray' or constructor signature
5869 protected ArrayList arguments;
5871 protected Type array_element_type;
5872 bool expect_initializers = false;
5873 int num_arguments = 0;
5874 protected int dimensions;
5875 protected readonly string rank;
5877 protected ArrayList array_data;
5879 IDictionary bounds;
5881 // The number of constants in array initializers
5882 int const_initializers_count;
5883 bool only_constant_initializers;
5885 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5887 this.requested_base_type = requested_base_type;
5888 this.initializers = initializers;
5889 this.rank = rank;
5890 loc = l;
5892 arguments = new ArrayList (exprs.Count);
5894 foreach (Expression e in exprs) {
5895 arguments.Add (e);
5896 num_arguments++;
5900 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5902 this.requested_base_type = requested_base_type;
5903 this.initializers = initializers;
5904 this.rank = rank;
5905 loc = l;
5907 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5909 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5911 //dimensions = tmp.Length - 1;
5912 expect_initializers = true;
5915 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
5917 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
5920 bool CheckIndices (ResolveContext ec, ArrayList probe, int idx, bool specified_dims, int child_bounds)
5922 if (specified_dims) {
5923 Expression a = (Expression) arguments [idx];
5924 a = a.Resolve (ec);
5925 if (a == null)
5926 return false;
5928 Constant c = a as Constant;
5929 if (c != null) {
5930 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Location);
5933 if (c == null) {
5934 ec.Report.Error (150, a.Location, "A constant value is expected");
5935 return false;
5938 int value = (int) c.GetValue ();
5940 if (value != probe.Count) {
5941 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value);
5942 return false;
5945 bounds [idx] = value;
5948 only_constant_initializers = true;
5949 for (int i = 0; i < probe.Count; ++i) {
5950 object o = probe [i];
5951 if (o is ArrayList) {
5952 ArrayList sub_probe = o as ArrayList;
5953 if (idx + 1 >= dimensions){
5954 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5955 return false;
5958 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
5959 if (!ret)
5960 return false;
5961 } else if (child_bounds > 1) {
5962 ec.Report.Error (846, ((Expression) o).Location, "A nested array initializer was expected");
5963 } else {
5964 Expression element = ResolveArrayElement (ec, (Expression) o);
5965 if (element == null)
5966 continue;
5968 // Initializers with the default values can be ignored
5969 Constant c = element as Constant;
5970 if (c != null) {
5971 if (c.IsDefaultInitializer (array_element_type)) {
5972 element = null;
5974 else {
5975 ++const_initializers_count;
5977 } else {
5978 only_constant_initializers = false;
5981 array_data.Add (element);
5985 return true;
5988 public override Expression CreateExpressionTree (ResolveContext ec)
5990 Arguments args;
5992 if (array_data == null) {
5993 args = new Arguments (arguments.Count + 1);
5994 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5995 foreach (Expression a in arguments)
5996 args.Add (new Argument (a.CreateExpressionTree (ec)));
5998 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6001 if (dimensions > 1) {
6002 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6003 return null;
6006 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6007 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
6008 if (array_data != null) {
6009 for (int i = 0; i < array_data.Count; ++i) {
6010 Expression e = (Expression) array_data [i];
6011 if (e == null)
6012 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
6014 args.Add (new Argument (e.CreateExpressionTree (ec)));
6018 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6021 public void UpdateIndices ()
6023 int i = 0;
6024 for (ArrayList probe = initializers; probe != null;) {
6025 if (probe.Count > 0 && probe [0] is ArrayList) {
6026 Expression e = new IntConstant (probe.Count, Location.Null);
6027 arguments.Add (e);
6029 bounds [i++] = probe.Count;
6031 probe = (ArrayList) probe [0];
6033 } else {
6034 Expression e = new IntConstant (probe.Count, Location.Null);
6035 arguments.Add (e);
6037 bounds [i++] = probe.Count;
6038 return;
6044 Expression first_emit;
6045 LocalTemporary first_emit_temp;
6047 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
6049 element = element.Resolve (ec);
6050 if (element == null)
6051 return null;
6053 if (element is CompoundAssign.TargetExpression) {
6054 if (first_emit != null)
6055 throw new InternalErrorException ("Can only handle one mutator at a time");
6056 first_emit = element;
6057 element = first_emit_temp = new LocalTemporary (element.Type);
6060 return Convert.ImplicitConversionRequired (
6061 ec, element, array_element_type, loc);
6064 protected bool ResolveInitializers (ResolveContext ec)
6066 if (initializers == null) {
6067 return !expect_initializers;
6071 // We use this to store all the date values in the order in which we
6072 // will need to store them in the byte blob later
6074 array_data = new ArrayList ();
6075 bounds = new System.Collections.Specialized.HybridDictionary ();
6077 if (arguments != null)
6078 return CheckIndices (ec, initializers, 0, true, dimensions);
6080 arguments = new ArrayList ();
6082 if (!CheckIndices (ec, initializers, 0, false, dimensions))
6083 return false;
6085 UpdateIndices ();
6087 return true;
6091 // Resolved the type of the array
6093 bool ResolveArrayType (ResolveContext ec)
6095 if (requested_base_type == null) {
6096 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6097 return false;
6100 if (requested_base_type is VarExpr) {
6101 ec.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6102 return false;
6105 StringBuilder array_qualifier = new StringBuilder (rank);
6108 // `In the first form allocates an array instace of the type that results
6109 // from deleting each of the individual expression from the expression list'
6111 if (num_arguments > 0) {
6112 array_qualifier.Append ("[");
6113 for (int i = num_arguments-1; i > 0; i--)
6114 array_qualifier.Append (",");
6115 array_qualifier.Append ("]");
6119 // Lookup the type
6121 TypeExpr array_type_expr;
6122 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6123 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6124 if (array_type_expr == null)
6125 return false;
6127 type = array_type_expr.Type;
6128 array_element_type = TypeManager.GetElementType (type);
6129 dimensions = type.GetArrayRank ();
6131 return true;
6134 public override Expression DoResolve (ResolveContext ec)
6136 if (type != null)
6137 return this;
6139 if (!ResolveArrayType (ec))
6140 return null;
6143 // First step is to validate the initializers and fill
6144 // in any missing bits
6146 if (!ResolveInitializers (ec))
6147 return null;
6149 for (int i = 0; i < arguments.Count; ++i) {
6150 Expression e = ((Expression) arguments[i]).Resolve (ec);
6151 if (e == null)
6152 continue;
6154 arguments [i] = ConvertExpressionToArrayIndex (ec, e);
6157 eclass = ExprClass.Value;
6158 return this;
6161 MethodInfo GetArrayMethod (int arguments)
6163 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
6165 Type[] arg_types = new Type[arguments];
6166 for (int i = 0; i < arguments; i++)
6167 arg_types[i] = TypeManager.int32_type;
6169 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6170 arg_types);
6172 if (mi == null) {
6173 RootContext.ToplevelTypes.Compiler.Report.Error (-6, "New invocation: Can not find a constructor for " +
6174 "this argument list");
6175 return null;
6178 return mi;
6181 byte [] MakeByteBlob ()
6183 int factor;
6184 byte [] data;
6185 byte [] element;
6186 int count = array_data.Count;
6188 if (TypeManager.IsEnumType (array_element_type))
6189 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6191 factor = GetTypeSize (array_element_type);
6192 if (factor == 0)
6193 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6195 data = new byte [(count * factor + 3) & ~3];
6196 int idx = 0;
6198 for (int i = 0; i < count; ++i) {
6199 object v = array_data [i];
6201 if (v is EnumConstant)
6202 v = ((EnumConstant) v).Child;
6204 if (v is Constant && !(v is StringConstant))
6205 v = ((Constant) v).GetValue ();
6206 else {
6207 idx += factor;
6208 continue;
6211 if (array_element_type == TypeManager.int64_type){
6212 if (!(v is Expression)){
6213 long val = (long) v;
6215 for (int j = 0; j < factor; ++j) {
6216 data [idx + j] = (byte) (val & 0xFF);
6217 val = (val >> 8);
6220 } else if (array_element_type == TypeManager.uint64_type){
6221 if (!(v is Expression)){
6222 ulong val = (ulong) v;
6224 for (int j = 0; j < factor; ++j) {
6225 data [idx + j] = (byte) (val & 0xFF);
6226 val = (val >> 8);
6229 } else if (array_element_type == TypeManager.float_type) {
6230 if (!(v is Expression)){
6231 element = BitConverter.GetBytes ((float) v);
6233 for (int j = 0; j < factor; ++j)
6234 data [idx + j] = element [j];
6235 if (!BitConverter.IsLittleEndian)
6236 System.Array.Reverse (data, idx, 4);
6238 } else if (array_element_type == TypeManager.double_type) {
6239 if (!(v is Expression)){
6240 element = BitConverter.GetBytes ((double) v);
6242 for (int j = 0; j < factor; ++j)
6243 data [idx + j] = element [j];
6245 // FIXME: Handle the ARM float format.
6246 if (!BitConverter.IsLittleEndian)
6247 System.Array.Reverse (data, idx, 8);
6249 } else if (array_element_type == TypeManager.char_type){
6250 if (!(v is Expression)){
6251 int val = (int) ((char) v);
6253 data [idx] = (byte) (val & 0xff);
6254 data [idx+1] = (byte) (val >> 8);
6256 } else if (array_element_type == TypeManager.short_type){
6257 if (!(v is Expression)){
6258 int val = (int) ((short) v);
6260 data [idx] = (byte) (val & 0xff);
6261 data [idx+1] = (byte) (val >> 8);
6263 } else if (array_element_type == TypeManager.ushort_type){
6264 if (!(v is Expression)){
6265 int val = (int) ((ushort) v);
6267 data [idx] = (byte) (val & 0xff);
6268 data [idx+1] = (byte) (val >> 8);
6270 } else if (array_element_type == TypeManager.int32_type) {
6271 if (!(v is Expression)){
6272 int val = (int) v;
6274 data [idx] = (byte) (val & 0xff);
6275 data [idx+1] = (byte) ((val >> 8) & 0xff);
6276 data [idx+2] = (byte) ((val >> 16) & 0xff);
6277 data [idx+3] = (byte) (val >> 24);
6279 } else if (array_element_type == TypeManager.uint32_type) {
6280 if (!(v is Expression)){
6281 uint val = (uint) v;
6283 data [idx] = (byte) (val & 0xff);
6284 data [idx+1] = (byte) ((val >> 8) & 0xff);
6285 data [idx+2] = (byte) ((val >> 16) & 0xff);
6286 data [idx+3] = (byte) (val >> 24);
6288 } else if (array_element_type == TypeManager.sbyte_type) {
6289 if (!(v is Expression)){
6290 sbyte val = (sbyte) v;
6291 data [idx] = (byte) val;
6293 } else if (array_element_type == TypeManager.byte_type) {
6294 if (!(v is Expression)){
6295 byte val = (byte) v;
6296 data [idx] = (byte) val;
6298 } else if (array_element_type == TypeManager.bool_type) {
6299 if (!(v is Expression)){
6300 bool val = (bool) v;
6301 data [idx] = (byte) (val ? 1 : 0);
6303 } else if (array_element_type == TypeManager.decimal_type){
6304 if (!(v is Expression)){
6305 int [] bits = Decimal.GetBits ((decimal) v);
6306 int p = idx;
6308 // FIXME: For some reason, this doesn't work on the MS runtime.
6309 int [] nbits = new int [4];
6310 nbits [0] = bits [3];
6311 nbits [1] = bits [2];
6312 nbits [2] = bits [0];
6313 nbits [3] = bits [1];
6315 for (int j = 0; j < 4; j++){
6316 data [p++] = (byte) (nbits [j] & 0xff);
6317 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6318 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6319 data [p++] = (byte) (nbits [j] >> 24);
6322 } else
6323 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6325 idx += factor;
6328 return data;
6331 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6333 array_element_type = storey.MutateType (array_element_type);
6334 type = storey.MutateType (type);
6335 if (arguments != null) {
6336 foreach (Expression e in arguments)
6337 e.MutateHoistedGenericType (storey);
6340 if (array_data != null) {
6341 foreach (Expression e in array_data) {
6342 // Don't mutate values optimized away
6343 if (e == null)
6344 continue;
6346 e.MutateHoistedGenericType (storey);
6352 // Emits the initializers for the array
6354 void EmitStaticInitializers (EmitContext ec)
6356 // FIXME: This should go to Resolve !
6357 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6358 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6359 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6360 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6361 if (TypeManager.void_initializearray_array_fieldhandle == null)
6362 return;
6366 // First, the static data
6368 FieldBuilder fb;
6369 ILGenerator ig = ec.ig;
6371 byte [] data = MakeByteBlob ();
6373 fb = RootContext.MakeStaticData (data);
6375 ig.Emit (OpCodes.Dup);
6376 ig.Emit (OpCodes.Ldtoken, fb);
6377 ig.Emit (OpCodes.Call,
6378 TypeManager.void_initializearray_array_fieldhandle);
6382 // Emits pieces of the array that can not be computed at compile
6383 // time (variables and string locations).
6385 // This always expect the top value on the stack to be the array
6387 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6389 ILGenerator ig = ec.ig;
6390 int dims = bounds.Count;
6391 int [] current_pos = new int [dims];
6393 MethodInfo set = null;
6395 if (dims != 1){
6396 Type [] args = new Type [dims + 1];
6398 for (int j = 0; j < dims; j++)
6399 args [j] = TypeManager.int32_type;
6400 args [dims] = array_element_type;
6402 set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
6403 type, "Set",
6404 CallingConventions.HasThis | CallingConventions.Standard,
6405 TypeManager.void_type, args);
6408 for (int i = 0; i < array_data.Count; i++){
6410 Expression e = (Expression)array_data [i];
6412 // Constant can be initialized via StaticInitializer
6413 if (e != null && !(!emitConstants && e is Constant)) {
6414 Type etype = e.Type;
6416 ig.Emit (OpCodes.Dup);
6418 for (int idx = 0; idx < dims; idx++)
6419 IntConstant.EmitInt (ig, current_pos [idx]);
6422 // If we are dealing with a struct, get the
6423 // address of it, so we can store it.
6425 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6426 (!TypeManager.IsBuiltinOrEnum (etype) ||
6427 etype == TypeManager.decimal_type)) {
6429 ig.Emit (OpCodes.Ldelema, etype);
6432 e.Emit (ec);
6434 if (dims == 1) {
6435 bool is_stobj, has_type_arg;
6436 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6437 if (is_stobj)
6438 ig.Emit (OpCodes.Stobj, etype);
6439 else if (has_type_arg)
6440 ig.Emit (op, etype);
6441 else
6442 ig.Emit (op);
6443 } else
6444 ig.Emit (OpCodes.Call, set);
6449 // Advance counter
6451 for (int j = dims - 1; j >= 0; j--){
6452 current_pos [j]++;
6453 if (current_pos [j] < (int) bounds [j])
6454 break;
6455 current_pos [j] = 0;
6460 public override void Emit (EmitContext ec)
6462 ILGenerator ig = ec.ig;
6464 if (first_emit != null) {
6465 first_emit.Emit (ec);
6466 first_emit_temp.Store (ec);
6469 foreach (Expression e in arguments)
6470 e.Emit (ec);
6472 if (arguments.Count == 1)
6473 ig.Emit (OpCodes.Newarr, TypeManager.TypeToReflectionType (array_element_type));
6474 else {
6475 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6478 if (initializers == null)
6479 return;
6481 // Emit static initializer for arrays which have contain more than 4 items and
6482 // the static initializer will initialize at least 25% of array values.
6483 // NOTE: const_initializers_count does not contain default constant values.
6484 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6485 TypeManager.IsPrimitiveType (array_element_type)) {
6486 EmitStaticInitializers (ec);
6488 if (!only_constant_initializers)
6489 EmitDynamicInitializers (ec, false);
6490 } else {
6491 EmitDynamicInitializers (ec, true);
6494 if (first_emit_temp != null)
6495 first_emit_temp.Release (ec);
6498 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
6500 if (arguments.Count != 1) {
6501 // ec.Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6502 return base.GetAttributableValue (ec, null, out value);
6505 if (array_data == null) {
6506 Expression arg = (Expression) arguments[0];
6507 object arg_value;
6508 if (arg.GetAttributableValue (ec, arg.Type, out arg_value) && arg_value is int && (int)arg_value == 0) {
6509 value = Array.CreateInstance (array_element_type, 0);
6510 return true;
6513 // ec.Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6514 return base.GetAttributableValue (ec, null, out value);
6517 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6518 object element_value;
6519 for (int i = 0; i < ret.Length; ++i)
6521 Expression e = (Expression)array_data [i];
6523 // Is null when an initializer is optimized (value == predefined value)
6524 if (e == null)
6525 continue;
6527 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6528 value = null;
6529 return false;
6531 ret.SetValue (element_value, i);
6533 value = ret;
6534 return true;
6537 protected override void CloneTo (CloneContext clonectx, Expression t)
6539 ArrayCreation target = (ArrayCreation) t;
6541 if (requested_base_type != null)
6542 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6544 if (arguments != null){
6545 target.arguments = new ArrayList (arguments.Count);
6546 foreach (Expression e in arguments)
6547 target.arguments.Add (e.Clone (clonectx));
6550 if (initializers != null){
6551 target.initializers = new ArrayList (initializers.Count);
6552 foreach (object initializer in initializers)
6553 if (initializer is ArrayList) {
6554 ArrayList this_al = (ArrayList)initializer;
6555 ArrayList al = new ArrayList (this_al.Count);
6556 target.initializers.Add (al);
6557 foreach (Expression e in this_al)
6558 al.Add (e.Clone (clonectx));
6559 } else {
6560 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6567 // Represents an implicitly typed array epxression
6569 public class ImplicitlyTypedArrayCreation : ArrayCreation
6571 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6572 : base (null, rank, initializers, loc)
6574 if (rank.Length > 2) {
6575 while (rank [++dimensions] == ',');
6576 } else {
6577 dimensions = 1;
6581 public override Expression DoResolve (ResolveContext ec)
6583 if (type != null)
6584 return this;
6586 if (!ResolveInitializers (ec))
6587 return null;
6589 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6590 array_element_type == TypeManager.void_type || array_element_type == InternalType.AnonymousMethod ||
6591 array_element_type == InternalType.MethodGroup ||
6592 arguments.Count != dimensions) {
6593 Error_NoBestType (ec);
6594 return null;
6598 // At this point we found common base type for all initializer elements
6599 // but we have to be sure that all static initializer elements are of
6600 // same type
6602 UnifyInitializerElement (ec);
6604 type = TypeManager.GetConstructedType (array_element_type, rank);
6605 eclass = ExprClass.Value;
6606 return this;
6609 void Error_NoBestType (ResolveContext ec)
6611 ec.Report.Error (826, loc,
6612 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6616 // Converts static initializer only
6618 void UnifyInitializerElement (ResolveContext ec)
6620 for (int i = 0; i < array_data.Count; ++i) {
6621 Expression e = (Expression)array_data[i];
6622 if (e != null)
6623 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6627 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6629 element = element.Resolve (ec);
6630 if (element == null)
6631 return null;
6633 if (array_element_type == null) {
6634 if (element.Type != TypeManager.null_type)
6635 array_element_type = element.Type;
6637 return element;
6640 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6641 return element;
6644 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6645 array_element_type = element.Type;
6646 return element;
6649 Error_NoBestType (ec);
6650 return null;
6654 public sealed class CompilerGeneratedThis : This
6656 public static This Instance = new CompilerGeneratedThis ();
6658 private CompilerGeneratedThis ()
6659 : base (Location.Null)
6663 public CompilerGeneratedThis (Type type, Location loc)
6664 : base (loc)
6666 this.type = type;
6669 public override Expression DoResolve (ResolveContext ec)
6671 eclass = ExprClass.Variable;
6672 if (type == null)
6673 type = ec.CurrentType;
6675 is_struct = type.IsValueType;
6676 return this;
6679 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6681 return null;
6685 /// <summary>
6686 /// Represents the `this' construct
6687 /// </summary>
6689 public class This : VariableReference
6691 sealed class ThisVariable : ILocalVariable
6693 public static readonly ILocalVariable Instance = new ThisVariable ();
6695 public void Emit (EmitContext ec)
6697 ec.ig.Emit (OpCodes.Ldarg_0);
6700 public void EmitAssign (EmitContext ec)
6702 throw new InvalidOperationException ();
6705 public void EmitAddressOf (EmitContext ec)
6707 ec.ig.Emit (OpCodes.Ldarg_0);
6711 Block block;
6712 VariableInfo variable_info;
6713 protected bool is_struct;
6715 public This (Block block, Location loc)
6717 this.loc = loc;
6718 this.block = block;
6721 public This (Location loc)
6723 this.loc = loc;
6726 public override VariableInfo VariableInfo {
6727 get { return variable_info; }
6730 public override bool IsFixed {
6731 get { return false; }
6734 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6736 if (ae == null)
6737 return null;
6739 AnonymousMethodStorey storey = ae.Storey;
6740 while (storey != null) {
6741 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6742 if (temp == null)
6743 return storey.HoistedThis;
6745 storey = temp;
6748 return null;
6751 public override bool IsRef {
6752 get { return is_struct; }
6755 protected override ILocalVariable Variable {
6756 get { return ThisVariable.Instance; }
6759 public static bool IsThisAvailable (ResolveContext ec)
6761 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
6762 return false;
6764 if (ec.CurrentAnonymousMethod == null)
6765 return true;
6767 if (ec.CurrentType.IsValueType && ec.CurrentIterator == null)
6768 return false;
6770 return true;
6773 public bool ResolveBase (ResolveContext ec)
6775 if (eclass != ExprClass.Invalid)
6776 return true;
6778 eclass = ExprClass.Variable;
6779 type = ec.CurrentType;
6781 if (!IsThisAvailable (ec)) {
6782 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6783 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6784 } else if (ec.CurrentAnonymousMethod != null) {
6785 ec.Report.Error (1673, loc,
6786 "Anonymous methods inside structs cannot access instance members of `this'. " +
6787 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6788 } else {
6789 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6793 is_struct = type.IsValueType;
6795 if (block != null) {
6796 if (block.Toplevel.ThisVariable != null)
6797 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6799 AnonymousExpression am = ec.CurrentAnonymousMethod;
6800 if (am != null && ec.IsVariableCapturingRequired) {
6801 am.SetHasThisAccess ();
6805 return true;
6809 // Called from Invocation to check if the invocation is correct
6811 public override void CheckMarshalByRefAccess (ResolveContext ec)
6813 if ((variable_info != null) && !(TypeManager.IsStruct (type) && ec.OmitStructFlowAnalysis) &&
6814 !variable_info.IsAssigned (ec)) {
6815 ec.Report.Error (188, loc,
6816 "The `this' object cannot be used before all of its fields are assigned to");
6817 variable_info.SetAssigned (ec);
6821 public override Expression CreateExpressionTree (ResolveContext ec)
6823 Arguments args = new Arguments (1);
6824 args.Add (new Argument (this));
6826 // Use typeless constant for ldarg.0 to save some
6827 // space and avoid problems with anonymous stories
6828 return CreateExpressionFactoryCall (ec, "Constant", args);
6831 public override Expression DoResolve (ResolveContext ec)
6833 ResolveBase (ec);
6834 return this;
6837 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6839 if (!ResolveBase (ec))
6840 return null;
6842 if (variable_info != null)
6843 variable_info.SetAssigned (ec);
6845 if (ec.CurrentType.IsClass){
6846 if (right_side == EmptyExpression.UnaryAddress)
6847 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6848 else if (right_side == EmptyExpression.OutAccess)
6849 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6850 else
6851 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6854 return this;
6857 public override int GetHashCode()
6859 return block.GetHashCode ();
6862 public override string Name {
6863 get { return "this"; }
6866 public override bool Equals (object obj)
6868 This t = obj as This;
6869 if (t == null)
6870 return false;
6872 return block == t.block;
6875 protected override void CloneTo (CloneContext clonectx, Expression t)
6877 This target = (This) t;
6879 target.block = clonectx.LookupBlock (block);
6882 public override void SetHasAddressTaken ()
6884 // Nothing
6888 /// <summary>
6889 /// Represents the `__arglist' construct
6890 /// </summary>
6891 public class ArglistAccess : Expression
6893 public ArglistAccess (Location loc)
6895 this.loc = loc;
6898 public override Expression CreateExpressionTree (ResolveContext ec)
6900 throw new NotSupportedException ("ET");
6903 public override Expression DoResolve (ResolveContext ec)
6905 eclass = ExprClass.Variable;
6906 type = TypeManager.runtime_argument_handle_type;
6908 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.Toplevel.Parameters.HasArglist) {
6909 ec.Report.Error (190, loc,
6910 "The __arglist construct is valid only within a variable argument method");
6913 return this;
6916 public override void Emit (EmitContext ec)
6918 ec.ig.Emit (OpCodes.Arglist);
6921 protected override void CloneTo (CloneContext clonectx, Expression target)
6923 // nothing.
6927 /// <summary>
6928 /// Represents the `__arglist (....)' construct
6929 /// </summary>
6930 class Arglist : Expression
6932 Arguments Arguments;
6934 public Arglist (Location loc)
6935 : this (null, loc)
6939 public Arglist (Arguments args, Location l)
6941 Arguments = args;
6942 loc = l;
6945 public Type[] ArgumentTypes {
6946 get {
6947 if (Arguments == null)
6948 return Type.EmptyTypes;
6950 Type[] retval = new Type [Arguments.Count];
6951 for (int i = 0; i < retval.Length; i++)
6952 retval [i] = Arguments [i].Expr.Type;
6954 return retval;
6958 public override Expression CreateExpressionTree (ResolveContext ec)
6960 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6961 return null;
6964 public override Expression DoResolve (ResolveContext ec)
6966 eclass = ExprClass.Variable;
6967 type = InternalType.Arglist;
6968 if (Arguments != null) {
6969 bool dynamic; // Can be ignored as there is always only 1 overload
6970 Arguments.Resolve (ec, out dynamic);
6973 return this;
6976 public override void Emit (EmitContext ec)
6978 if (Arguments != null)
6979 Arguments.Emit (ec);
6982 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6984 if (Arguments != null)
6985 Arguments.MutateHoistedGenericType (storey);
6988 protected override void CloneTo (CloneContext clonectx, Expression t)
6990 Arglist target = (Arglist) t;
6992 if (Arguments != null)
6993 target.Arguments = Arguments.Clone (clonectx);
6997 /// <summary>
6998 /// Implements the typeof operator
6999 /// </summary>
7000 public class TypeOf : Expression {
7001 Expression QueriedType;
7002 protected Type typearg;
7004 public TypeOf (Expression queried_type, Location l)
7006 QueriedType = queried_type;
7007 loc = l;
7010 public override Expression CreateExpressionTree (ResolveContext ec)
7012 Arguments args = new Arguments (2);
7013 args.Add (new Argument (this));
7014 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7015 return CreateExpressionFactoryCall (ec, "Constant", args);
7018 public override Expression DoResolve (ResolveContext ec)
7020 if (eclass != ExprClass.Invalid)
7021 return this;
7023 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7024 if (texpr == null)
7025 return null;
7027 typearg = texpr.Type;
7029 if (typearg == TypeManager.void_type) {
7030 ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
7031 } else if (typearg.IsPointer && !ec.IsUnsafe){
7032 UnsafeError (ec, loc);
7033 } else if (texpr is DynamicTypeExpr) {
7034 ec.Report.Error (1962, QueriedType.Location,
7035 "The typeof operator cannot be used on the dynamic type");
7038 type = TypeManager.type_type;
7040 return DoResolveBase ();
7043 protected Expression DoResolveBase ()
7045 if (TypeManager.system_type_get_type_from_handle == null) {
7046 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
7047 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
7050 // Even though what is returned is a type object, it's treated as a value by the compiler.
7051 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7052 eclass = ExprClass.Value;
7053 return this;
7056 public override void Emit (EmitContext ec)
7058 ec.ig.Emit (OpCodes.Ldtoken, TypeManager.TypeToReflectionType (typearg));
7059 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
7062 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
7064 if (TypeManager.ContainsGenericParameters (typearg) &&
7065 !TypeManager.IsGenericTypeDefinition (typearg)) {
7066 ec.Report.SymbolRelatedToPreviousError (typearg);
7067 ec.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7068 TypeManager.CSharpName (typearg));
7069 value = null;
7070 return false;
7073 if (value_type == TypeManager.object_type) {
7074 value = (object)typearg;
7075 return true;
7077 value = typearg;
7078 return true;
7081 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7083 typearg = storey.MutateType (typearg);
7086 public Type TypeArgument {
7087 get {
7088 return typearg;
7092 protected override void CloneTo (CloneContext clonectx, Expression t)
7094 TypeOf target = (TypeOf) t;
7095 if (QueriedType != null)
7096 target.QueriedType = QueriedType.Clone (clonectx);
7100 /// <summary>
7101 /// Implements the `typeof (void)' operator
7102 /// </summary>
7103 public class TypeOfVoid : TypeOf {
7104 public TypeOfVoid (Location l) : base (null, l)
7106 loc = l;
7109 public override Expression DoResolve (ResolveContext ec)
7111 type = TypeManager.type_type;
7112 typearg = TypeManager.void_type;
7114 return DoResolveBase ();
7118 class TypeOfMethod : TypeOfMember
7120 public TypeOfMethod (MethodBase method, Location loc)
7121 : base (method, loc)
7125 public override Expression DoResolve (ResolveContext ec)
7127 if (member is MethodInfo) {
7128 type = TypeManager.methodinfo_type;
7129 if (type == null)
7130 type = TypeManager.methodinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", "MethodInfo", Kind.Class, true);
7131 } else {
7132 type = TypeManager.ctorinfo_type;
7133 if (type == null)
7134 type = TypeManager.ctorinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", "ConstructorInfo", Kind.Class, true);
7137 return base.DoResolve (ec);
7140 public override void Emit (EmitContext ec)
7142 if (member is ConstructorInfo)
7143 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) member);
7144 else
7145 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) member);
7147 base.Emit (ec);
7148 ec.ig.Emit (OpCodes.Castclass, type);
7151 protected override string GetMethodName {
7152 get { return "GetMethodFromHandle"; }
7155 protected override string RuntimeHandleName {
7156 get { return "RuntimeMethodHandle"; }
7159 protected override MethodInfo TypeFromHandle {
7160 get {
7161 return TypeManager.methodbase_get_type_from_handle;
7163 set {
7164 TypeManager.methodbase_get_type_from_handle = value;
7168 protected override MethodInfo TypeFromHandleGeneric {
7169 get {
7170 return TypeManager.methodbase_get_type_from_handle_generic;
7172 set {
7173 TypeManager.methodbase_get_type_from_handle_generic = value;
7177 protected override string TypeName {
7178 get { return "MethodBase"; }
7182 abstract class TypeOfMember : Expression
7184 protected readonly MemberInfo member;
7186 protected TypeOfMember (MemberInfo member, Location loc)
7188 this.member = member;
7189 this.loc = loc;
7192 public override Expression CreateExpressionTree (ResolveContext ec)
7194 Arguments args = new Arguments (2);
7195 args.Add (new Argument (this));
7196 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7197 return CreateExpressionFactoryCall (ec, "Constant", args);
7200 public override Expression DoResolve (ResolveContext ec)
7202 bool is_generic = TypeManager.IsGenericType (member.DeclaringType);
7203 MethodInfo mi = is_generic ? TypeFromHandleGeneric : TypeFromHandle;
7205 if (mi == null) {
7206 Type t = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", TypeName, Kind.Class, true);
7207 Type handle_type = TypeManager.CoreLookupType (ec.Compiler, "System", RuntimeHandleName, Kind.Class, true);
7209 if (t == null || handle_type == null)
7210 return null;
7212 mi = TypeManager.GetPredefinedMethod (t, GetMethodName, loc,
7213 is_generic ?
7214 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7215 new Type[] { handle_type } );
7217 if (is_generic)
7218 TypeFromHandleGeneric = mi;
7219 else
7220 TypeFromHandle = mi;
7223 eclass = ExprClass.Value;
7224 return this;
7227 public override void Emit (EmitContext ec)
7229 bool is_generic = TypeManager.IsGenericType (member.DeclaringType);
7230 MethodInfo mi;
7231 if (is_generic) {
7232 mi = TypeFromHandleGeneric;
7233 ec.ig.Emit (OpCodes.Ldtoken, member.DeclaringType);
7234 } else {
7235 mi = TypeFromHandle;
7238 ec.ig.Emit (OpCodes.Call, mi);
7241 protected abstract string GetMethodName { get; }
7242 protected abstract string RuntimeHandleName { get; }
7243 protected abstract MethodInfo TypeFromHandle { get; set; }
7244 protected abstract MethodInfo TypeFromHandleGeneric { get; set; }
7245 protected abstract string TypeName { get; }
7248 class TypeOfField : TypeOfMember
7250 public TypeOfField (FieldInfo field, Location loc)
7251 : base (field, loc)
7255 public override Expression DoResolve (ResolveContext ec)
7257 if (TypeManager.fieldinfo_type == null)
7258 TypeManager.fieldinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", TypeName, Kind.Class, true);
7260 type = TypeManager.fieldinfo_type;
7261 return base.DoResolve (ec);
7264 public override void Emit (EmitContext ec)
7266 ec.ig.Emit (OpCodes.Ldtoken, (FieldInfo) member);
7267 base.Emit (ec);
7270 protected override string GetMethodName {
7271 get { return "GetFieldFromHandle"; }
7274 protected override string RuntimeHandleName {
7275 get { return "RuntimeFieldHandle"; }
7278 protected override MethodInfo TypeFromHandle {
7279 get {
7280 return TypeManager.fieldinfo_get_field_from_handle;
7282 set {
7283 TypeManager.fieldinfo_get_field_from_handle = value;
7287 protected override MethodInfo TypeFromHandleGeneric {
7288 get {
7289 return TypeManager.fieldinfo_get_field_from_handle_generic;
7291 set {
7292 TypeManager.fieldinfo_get_field_from_handle_generic = value;
7296 protected override string TypeName {
7297 get { return "FieldInfo"; }
7301 /// <summary>
7302 /// Implements the sizeof expression
7303 /// </summary>
7304 public class SizeOf : Expression {
7305 readonly Expression QueriedType;
7306 Type type_queried;
7308 public SizeOf (Expression queried_type, Location l)
7310 this.QueriedType = queried_type;
7311 loc = l;
7314 public override Expression CreateExpressionTree (ResolveContext ec)
7316 Error_PointerInsideExpressionTree (ec);
7317 return null;
7320 public override Expression DoResolve (ResolveContext ec)
7322 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7323 if (texpr == null)
7324 return null;
7326 type_queried = texpr.Type;
7327 if (TypeManager.IsEnumType (type_queried))
7328 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7330 int size_of = GetTypeSize (type_queried);
7331 if (size_of > 0) {
7332 return new IntConstant (size_of, loc);
7335 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7336 return null;
7339 if (!ec.IsUnsafe) {
7340 ec.Report.Error (233, loc,
7341 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7342 TypeManager.CSharpName (type_queried));
7345 type = TypeManager.int32_type;
7346 eclass = ExprClass.Value;
7347 return this;
7350 public override void Emit (EmitContext ec)
7352 int size = GetTypeSize (type_queried);
7354 if (size == 0)
7355 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7356 else
7357 IntConstant.EmitInt (ec.ig, size);
7360 protected override void CloneTo (CloneContext clonectx, Expression t)
7365 /// <summary>
7366 /// Implements the qualified-alias-member (::) expression.
7367 /// </summary>
7368 public class QualifiedAliasMember : MemberAccess
7370 readonly string alias;
7371 public static readonly string GlobalAlias = "global";
7373 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7374 : base (null, identifier, targs, l)
7376 this.alias = alias;
7379 public QualifiedAliasMember (string alias, string identifier, Location l)
7380 : base (null, identifier, l)
7382 this.alias = alias;
7385 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7387 if (alias == GlobalAlias) {
7388 expr = GlobalRootNamespace.Instance;
7389 return base.ResolveAsTypeStep (ec, silent);
7392 int errors = ec.Compiler.Report.Errors;
7393 expr = ec.LookupNamespaceAlias (alias);
7394 if (expr == null) {
7395 if (errors == ec.Compiler.Report.Errors)
7396 ec.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7397 return null;
7400 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7401 if (fne == null)
7402 return null;
7404 if (expr.eclass == ExprClass.Type) {
7405 if (!silent) {
7406 ec.Compiler.Report.Error (431, loc,
7407 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7409 return null;
7412 return fne;
7415 public override Expression DoResolve (ResolveContext ec)
7417 return ResolveAsTypeStep (ec, false);
7420 protected override void Error_IdentifierNotFound (IMemberContext rc, FullNamedExpression expr_type, string identifier)
7422 rc.Compiler.Report.Error (687, loc,
7423 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7424 GetSignatureForError ());
7427 public override string GetSignatureForError ()
7429 string name = Name;
7430 if (targs != null) {
7431 name = TypeManager.RemoveGenericArity (Name) + "<" +
7432 targs.GetSignatureForError () + ">";
7435 return alias + "::" + name;
7438 protected override void CloneTo (CloneContext clonectx, Expression t)
7440 // Nothing
7444 /// <summary>
7445 /// Implements the member access expression
7446 /// </summary>
7447 public class MemberAccess : ATypeNameExpression {
7448 protected Expression expr;
7450 public MemberAccess (Expression expr, string id)
7451 : base (id, expr.Location)
7453 this.expr = expr;
7456 public MemberAccess (Expression expr, string identifier, Location loc)
7457 : base (identifier, loc)
7459 this.expr = expr;
7462 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7463 : base (identifier, args, loc)
7465 this.expr = expr;
7468 Expression DoResolve (ResolveContext ec, Expression right_side)
7470 if (type != null)
7471 throw new Exception ();
7474 // Resolve the expression with flow analysis turned off, we'll do the definite
7475 // assignment checks later. This is because we don't know yet what the expression
7476 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7477 // definite assignment check on the actual field and not on the whole struct.
7480 SimpleName original = expr as SimpleName;
7481 Expression expr_resolved = expr.Resolve (ec,
7482 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7483 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7485 if (expr_resolved == null)
7486 return null;
7488 string LookupIdentifier = MemberName.MakeName (Name, targs);
7490 Namespace ns = expr_resolved as Namespace;
7491 if (ns != null) {
7492 FullNamedExpression retval = ns.Lookup (ec.Compiler, LookupIdentifier, loc);
7494 if (retval == null)
7495 ns.Error_NamespaceDoesNotExist (loc, LookupIdentifier, ec.Report);
7496 else if (targs != null)
7497 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
7499 return retval;
7502 Type expr_type = expr_resolved.Type;
7503 if (TypeManager.IsDynamicType (expr_type)) {
7504 Arguments args = new Arguments (2);
7505 args.Add (new Argument (expr_resolved.Resolve (ec)));
7506 if (right_side != null)
7507 args.Add (new Argument (right_side));
7509 return new DynamicMemberBinder (right_side != null, Name, args, loc).Resolve (ec);
7512 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7513 expr_type == TypeManager.null_type || expr_type == InternalType.AnonymousMethod) {
7514 Unary.Error_OperatorCannotBeApplied (ec, loc, ".", expr_type);
7515 return null;
7518 Constant c = expr_resolved as Constant;
7519 if (c != null && c.GetValue () == null) {
7520 ec.Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7521 "System.NullReferenceException");
7524 if (targs != null) {
7525 if (!targs.Resolve (ec))
7526 return null;
7529 Expression member_lookup;
7530 member_lookup = MemberLookup (ec.Compiler,
7531 ec.CurrentType, expr_type, expr_type, Name, loc);
7533 if (member_lookup == null && targs != null) {
7534 member_lookup = MemberLookup (ec.Compiler,
7535 ec.CurrentType, expr_type, expr_type, LookupIdentifier, loc);
7538 if (member_lookup == null) {
7539 ExprClass expr_eclass = expr_resolved.eclass;
7542 // Extension methods are not allowed on all expression types
7544 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7545 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7546 expr_eclass == ExprClass.EventAccess) {
7547 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
7548 if (ex_method_lookup != null) {
7549 ex_method_lookup.ExtensionExpression = expr_resolved;
7551 if (targs != null) {
7552 ex_method_lookup.SetTypeArguments (ec, targs);
7555 return ex_method_lookup.DoResolve (ec);
7559 expr = expr_resolved;
7560 member_lookup = Error_MemberLookupFailed (ec,
7561 ec.CurrentType, expr_type, expr_type, Name, null,
7562 AllMemberTypes, AllBindingFlags);
7563 if (member_lookup == null)
7564 return null;
7567 TypeExpr texpr = member_lookup as TypeExpr;
7568 if (texpr != null) {
7569 if (!(expr_resolved is TypeExpr) &&
7570 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7571 ec.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7572 Name, member_lookup.GetSignatureForError ());
7573 return null;
7576 if (!texpr.CheckAccessLevel (ec.MemberContext)) {
7577 ec.Report.SymbolRelatedToPreviousError (member_lookup.Type);
7578 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type), ec.Report);
7579 return null;
7582 GenericTypeExpr ct = expr_resolved as GenericTypeExpr;
7583 if (ct != null) {
7585 // When looking up a nested type in a generic instance
7586 // via reflection, we always get a generic type definition
7587 // and not a generic instance - so we have to do this here.
7589 // See gtest-172-lib.cs and gtest-172.cs for an example.
7592 TypeArguments nested_targs;
7593 if (HasTypeArguments) {
7594 nested_targs = ct.TypeArguments.Clone ();
7595 nested_targs.Add (targs);
7596 } else {
7597 nested_targs = ct.TypeArguments;
7600 ct = new GenericTypeExpr (member_lookup.Type, nested_targs, loc);
7602 return ct.ResolveAsTypeStep (ec, false);
7605 return member_lookup;
7608 MemberExpr me = (MemberExpr) member_lookup;
7609 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7610 if (me == null)
7611 return null;
7613 if (targs != null) {
7614 me.SetTypeArguments (ec, targs);
7617 if (original != null && !TypeManager.IsValueType (expr_type)) {
7618 if (me.IsInstance) {
7619 LocalVariableReference var = expr_resolved as LocalVariableReference;
7620 if (var != null && !var.VerifyAssigned (ec))
7621 return null;
7625 // The following DoResolve/DoResolveLValue will do the definite assignment
7626 // check.
7628 if (right_side != null)
7629 return me.DoResolveLValue (ec, right_side);
7630 else
7631 return me.DoResolve (ec);
7634 public override Expression DoResolve (ResolveContext ec)
7636 return DoResolve (ec, null);
7639 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7641 return DoResolve (ec, right_side);
7644 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7646 return ResolveNamespaceOrType (ec, silent);
7649 public FullNamedExpression ResolveNamespaceOrType (IMemberContext rc, bool silent)
7651 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7653 if (expr_resolved == null)
7654 return null;
7656 string LookupIdentifier = MemberName.MakeName (Name, targs);
7658 Namespace ns = expr_resolved as Namespace;
7659 if (ns != null) {
7660 FullNamedExpression retval = ns.Lookup (rc.Compiler, LookupIdentifier, loc);
7662 if (retval == null && !silent)
7663 ns.Error_NamespaceDoesNotExist (loc, LookupIdentifier, rc.Compiler.Report);
7664 else if (targs != null)
7665 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7667 return retval;
7670 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7671 if (tnew_expr == null)
7672 return null;
7674 Type expr_type = tnew_expr.Type;
7675 if (TypeManager.IsGenericParameter (expr_type)) {
7676 rc.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7677 tnew_expr.GetSignatureForError ());
7678 return null;
7681 Expression member_lookup = MemberLookup (rc.Compiler,
7682 rc.CurrentType, expr_type, expr_type, LookupIdentifier,
7683 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7684 if (member_lookup == null) {
7685 if (silent)
7686 return null;
7688 Error_IdentifierNotFound (rc, expr_resolved, LookupIdentifier);
7689 return null;
7692 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7693 if (texpr == null)
7694 return null;
7696 TypeArguments the_args = targs;
7697 Type declaring_type = texpr.Type.DeclaringType;
7698 if (TypeManager.HasGenericArguments (declaring_type) && !TypeManager.IsGenericTypeDefinition (expr_type)) {
7699 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7700 expr_type = expr_type.BaseType;
7703 TypeArguments new_args = new TypeArguments ();
7704 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7705 new_args.Add (new TypeExpression (TypeManager.TypeToCoreType (decl), loc));
7707 if (targs != null)
7708 new_args.Add (targs);
7710 the_args = new_args;
7713 if (the_args != null) {
7714 GenericTypeExpr ctype = new GenericTypeExpr (texpr.Type, the_args, loc);
7715 return ctype.ResolveAsTypeStep (rc, false);
7718 return texpr;
7721 protected virtual void Error_IdentifierNotFound (IMemberContext rc, FullNamedExpression expr_type, string identifier)
7723 Expression member_lookup = MemberLookup (rc.Compiler,
7724 rc.CurrentType, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7725 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7727 if (member_lookup != null) {
7728 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7729 if (expr_type == null)
7730 return;
7732 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type, loc);
7733 return;
7736 member_lookup = MemberLookup (rc.Compiler,
7737 rc.CurrentType, expr_type.Type, expr_type.Type, identifier,
7738 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7740 if (member_lookup == null) {
7741 rc.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7742 Name, expr_type.GetSignatureForError ());
7743 } else {
7744 // TODO: Report.SymbolRelatedToPreviousError
7745 member_lookup.Error_UnexpectedKind (rc.Compiler.Report, null, "type", loc);
7749 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
7751 if (RootContext.Version > LanguageVersion.ISO_2 &&
7752 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7753 ec.Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7754 "extension method `{1}' of type `{0}' could be found " +
7755 "(are you missing a using directive or an assembly reference?)",
7756 TypeManager.CSharpName (type), name);
7757 return;
7760 base.Error_TypeDoesNotContainDefinition (ec, type, name);
7763 public override string GetSignatureForError ()
7765 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7768 public Expression Left {
7769 get {
7770 return expr;
7774 protected override void CloneTo (CloneContext clonectx, Expression t)
7776 MemberAccess target = (MemberAccess) t;
7778 target.expr = expr.Clone (clonectx);
7782 /// <summary>
7783 /// Implements checked expressions
7784 /// </summary>
7785 public class CheckedExpr : Expression {
7787 public Expression Expr;
7789 public CheckedExpr (Expression e, Location l)
7791 Expr = e;
7792 loc = l;
7795 public override Expression CreateExpressionTree (ResolveContext ec)
7797 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7798 return Expr.CreateExpressionTree (ec);
7801 public override Expression DoResolve (ResolveContext ec)
7803 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7804 Expr = Expr.Resolve (ec);
7806 if (Expr == null)
7807 return null;
7809 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7810 return Expr;
7812 eclass = Expr.eclass;
7813 type = Expr.Type;
7814 return this;
7817 public override void Emit (EmitContext ec)
7819 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7820 Expr.Emit (ec);
7823 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7825 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7826 Expr.EmitBranchable (ec, target, on_true);
7829 #if NET_4_0
7830 public override SLE.Expression MakeExpression (BuilderContext ctx)
7832 using (ctx.With (BuilderContext.Options.AllCheckStateFlags, true)) {
7833 return Expr.MakeExpression (ctx);
7836 #endif
7838 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7840 Expr.MutateHoistedGenericType (storey);
7843 protected override void CloneTo (CloneContext clonectx, Expression t)
7845 CheckedExpr target = (CheckedExpr) t;
7847 target.Expr = Expr.Clone (clonectx);
7851 /// <summary>
7852 /// Implements the unchecked expression
7853 /// </summary>
7854 public class UnCheckedExpr : Expression {
7856 public Expression Expr;
7858 public UnCheckedExpr (Expression e, Location l)
7860 Expr = e;
7861 loc = l;
7864 public override Expression CreateExpressionTree (ResolveContext ec)
7866 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7867 return Expr.CreateExpressionTree (ec);
7870 public override Expression DoResolve (ResolveContext ec)
7872 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7873 Expr = Expr.Resolve (ec);
7875 if (Expr == null)
7876 return null;
7878 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7879 return Expr;
7881 eclass = Expr.eclass;
7882 type = Expr.Type;
7883 return this;
7886 public override void Emit (EmitContext ec)
7888 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7889 Expr.Emit (ec);
7892 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7894 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7895 Expr.EmitBranchable (ec, target, on_true);
7898 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7900 Expr.MutateHoistedGenericType (storey);
7903 protected override void CloneTo (CloneContext clonectx, Expression t)
7905 UnCheckedExpr target = (UnCheckedExpr) t;
7907 target.Expr = Expr.Clone (clonectx);
7911 /// <summary>
7912 /// An Element Access expression.
7914 /// During semantic analysis these are transformed into
7915 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7916 /// </summary>
7917 public class ElementAccess : Expression {
7918 public Arguments Arguments;
7919 public Expression Expr;
7921 public ElementAccess (Expression e, Arguments args)
7923 Expr = e;
7924 loc = e.Location;
7925 this.Arguments = args;
7928 public override Expression CreateExpressionTree (ResolveContext ec)
7930 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
7931 Expr.CreateExpressionTree (ec));
7933 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
7936 Expression MakePointerAccess (ResolveContext ec, Type t)
7938 if (Arguments.Count != 1){
7939 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
7940 return null;
7943 if (Arguments [0] is NamedArgument)
7944 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
7946 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), t, loc);
7947 return new Indirection (p, loc).Resolve (ec);
7950 public override Expression DoResolve (ResolveContext ec)
7952 Expr = Expr.Resolve (ec);
7953 if (Expr == null)
7954 return null;
7957 // We perform some simple tests, and then to "split" the emit and store
7958 // code we create an instance of a different class, and return that.
7960 // I am experimenting with this pattern.
7962 Type t = Expr.Type;
7964 if (t == TypeManager.array_type){
7965 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7966 return null;
7969 if (t.IsArray)
7970 return (new ArrayAccess (this, loc)).Resolve (ec);
7971 if (t.IsPointer)
7972 return MakePointerAccess (ec, t);
7974 FieldExpr fe = Expr as FieldExpr;
7975 if (fe != null) {
7976 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7977 if (ff != null) {
7978 return MakePointerAccess (ec, ff.ElementType);
7981 return (new IndexerAccess (this, loc)).Resolve (ec);
7984 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7986 Expr = Expr.Resolve (ec);
7987 if (Expr == null)
7988 return null;
7990 type = Expr.Type;
7991 if (type.IsArray)
7992 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7994 if (type.IsPointer)
7995 return MakePointerAccess (ec, type);
7997 if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
7998 Error_CannotModifyIntermediateExpressionValue (ec);
8000 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
8003 public override void Emit (EmitContext ec)
8005 throw new Exception ("Should never be reached");
8008 public static void Error_NamedArgument (NamedArgument na, Report Report)
8010 Report.Error (1742, na.Name.Location, "An element access expression cannot use named argument");
8013 public override string GetSignatureForError ()
8015 return Expr.GetSignatureForError ();
8018 protected override void CloneTo (CloneContext clonectx, Expression t)
8020 ElementAccess target = (ElementAccess) t;
8022 target.Expr = Expr.Clone (clonectx);
8023 if (Arguments != null)
8024 target.Arguments = Arguments.Clone (clonectx);
8028 /// <summary>
8029 /// Implements array access
8030 /// </summary>
8031 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
8033 // Points to our "data" repository
8035 ElementAccess ea;
8037 LocalTemporary temp;
8039 bool prepared;
8041 public ArrayAccess (ElementAccess ea_data, Location l)
8043 ea = ea_data;
8044 loc = l;
8047 public override Expression CreateExpressionTree (ResolveContext ec)
8049 return ea.CreateExpressionTree (ec);
8052 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8054 return DoResolve (ec);
8057 public override Expression DoResolve (ResolveContext ec)
8059 #if false
8060 ExprClass eclass = ea.Expr.eclass;
8062 // As long as the type is valid
8063 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
8064 eclass == ExprClass.Value)) {
8065 ea.Expr.Error_UnexpectedKind ("variable or value");
8066 return null;
8068 #endif
8070 if (eclass != ExprClass.Invalid)
8071 return this;
8073 // dynamic is used per argument in ConvertExpressionToArrayIndex case
8074 bool dynamic;
8075 ea.Arguments.Resolve (ec, out dynamic);
8077 Type t = ea.Expr.Type;
8078 int rank = ea.Arguments.Count;
8079 if (t.GetArrayRank () != rank) {
8080 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8081 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
8082 return null;
8085 type = TypeManager.GetElementType (t);
8086 if (type.IsPointer && !ec.IsUnsafe) {
8087 UnsafeError (ec, ea.Location);
8090 foreach (Argument a in ea.Arguments) {
8091 if (a is NamedArgument)
8092 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
8094 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
8097 eclass = ExprClass.Variable;
8099 return this;
8102 /// <summary>
8103 /// Emits the right opcode to load an object of Type `t'
8104 /// from an array of T
8105 /// </summary>
8106 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
8108 if (rank > 1) {
8109 MethodInfo get = FetchGetMethod ();
8110 ig.Emit (OpCodes.Call, get);
8111 return;
8114 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
8115 ig.Emit (OpCodes.Ldelem_U1);
8116 else if (type == TypeManager.sbyte_type)
8117 ig.Emit (OpCodes.Ldelem_I1);
8118 else if (type == TypeManager.short_type)
8119 ig.Emit (OpCodes.Ldelem_I2);
8120 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
8121 ig.Emit (OpCodes.Ldelem_U2);
8122 else if (type == TypeManager.int32_type)
8123 ig.Emit (OpCodes.Ldelem_I4);
8124 else if (type == TypeManager.uint32_type)
8125 ig.Emit (OpCodes.Ldelem_U4);
8126 else if (type == TypeManager.uint64_type)
8127 ig.Emit (OpCodes.Ldelem_I8);
8128 else if (type == TypeManager.int64_type)
8129 ig.Emit (OpCodes.Ldelem_I8);
8130 else if (type == TypeManager.float_type)
8131 ig.Emit (OpCodes.Ldelem_R4);
8132 else if (type == TypeManager.double_type)
8133 ig.Emit (OpCodes.Ldelem_R8);
8134 else if (type == TypeManager.intptr_type)
8135 ig.Emit (OpCodes.Ldelem_I);
8136 else if (TypeManager.IsEnumType (type)){
8137 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
8138 } else if (TypeManager.IsStruct (type)){
8139 ig.Emit (OpCodes.Ldelema, type);
8140 ig.Emit (OpCodes.Ldobj, type);
8141 } else if (type.IsGenericParameter) {
8142 ig.Emit (OpCodes.Ldelem, type);
8143 } else if (type.IsPointer)
8144 ig.Emit (OpCodes.Ldelem_I);
8145 else
8146 ig.Emit (OpCodes.Ldelem_Ref);
8149 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8151 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8154 /// <summary>
8155 /// Returns the right opcode to store an object of Type `t'
8156 /// from an array of T.
8157 /// </summary>
8158 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8160 has_type_arg = false; is_stobj = false;
8161 t = TypeManager.TypeToCoreType (t);
8162 if (TypeManager.IsEnumType (t))
8163 t = TypeManager.GetEnumUnderlyingType (t);
8164 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8165 t == TypeManager.bool_type)
8166 return OpCodes.Stelem_I1;
8167 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8168 t == TypeManager.char_type)
8169 return OpCodes.Stelem_I2;
8170 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8171 return OpCodes.Stelem_I4;
8172 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8173 return OpCodes.Stelem_I8;
8174 else if (t == TypeManager.float_type)
8175 return OpCodes.Stelem_R4;
8176 else if (t == TypeManager.double_type)
8177 return OpCodes.Stelem_R8;
8178 else if (t == TypeManager.intptr_type) {
8179 has_type_arg = true;
8180 is_stobj = true;
8181 return OpCodes.Stobj;
8182 } else if (TypeManager.IsStruct (t)) {
8183 has_type_arg = true;
8184 is_stobj = true;
8185 return OpCodes.Stobj;
8186 } else if (t.IsGenericParameter) {
8187 has_type_arg = true;
8188 return OpCodes.Stelem;
8189 } else if (t.IsPointer)
8190 return OpCodes.Stelem_I;
8191 else
8192 return OpCodes.Stelem_Ref;
8195 MethodInfo FetchGetMethod ()
8197 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8198 int arg_count = ea.Arguments.Count;
8199 Type [] args = new Type [arg_count];
8200 MethodInfo get;
8202 for (int i = 0; i < arg_count; i++){
8203 //args [i++] = a.Type;
8204 args [i] = TypeManager.int32_type;
8207 get = mb.GetArrayMethod (
8208 ea.Expr.Type, "Get",
8209 CallingConventions.HasThis |
8210 CallingConventions.Standard,
8211 type, args);
8212 return get;
8216 MethodInfo FetchAddressMethod ()
8218 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8219 int arg_count = ea.Arguments.Count;
8220 Type [] args = new Type [arg_count];
8221 MethodInfo address;
8222 Type ret_type;
8224 ret_type = TypeManager.GetReferenceType (type);
8226 for (int i = 0; i < arg_count; i++){
8227 //args [i++] = a.Type;
8228 args [i] = TypeManager.int32_type;
8231 address = mb.GetArrayMethod (
8232 ea.Expr.Type, "Address",
8233 CallingConventions.HasThis |
8234 CallingConventions.Standard,
8235 ret_type, args);
8237 return address;
8241 // Load the array arguments into the stack.
8243 void LoadArrayAndArguments (EmitContext ec)
8245 ea.Expr.Emit (ec);
8247 for (int i = 0; i < ea.Arguments.Count; ++i) {
8248 ea.Arguments [i].Emit (ec);
8252 public void Emit (EmitContext ec, bool leave_copy)
8254 int rank = ea.Expr.Type.GetArrayRank ();
8255 ILGenerator ig = ec.ig;
8257 if (prepared) {
8258 LoadFromPtr (ig, this.type);
8259 } else {
8260 LoadArrayAndArguments (ec);
8261 EmitLoadOpcode (ig, type, rank);
8264 if (leave_copy) {
8265 ig.Emit (OpCodes.Dup);
8266 temp = new LocalTemporary (this.type);
8267 temp.Store (ec);
8271 public override void Emit (EmitContext ec)
8273 Emit (ec, false);
8276 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8278 int rank = ea.Expr.Type.GetArrayRank ();
8279 ILGenerator ig = ec.ig;
8280 Type t = source.Type;
8281 prepared = prepare_for_load;
8283 if (prepared) {
8284 AddressOf (ec, AddressOp.LoadStore);
8285 ec.ig.Emit (OpCodes.Dup);
8286 } else {
8287 LoadArrayAndArguments (ec);
8290 if (rank == 1) {
8291 bool is_stobj, has_type_arg;
8292 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8294 if (!prepared) {
8296 // The stobj opcode used by value types will need
8297 // an address on the stack, not really an array/array
8298 // pair
8300 if (is_stobj)
8301 ig.Emit (OpCodes.Ldelema, t);
8304 source.Emit (ec);
8305 if (leave_copy) {
8306 ec.ig.Emit (OpCodes.Dup);
8307 temp = new LocalTemporary (this.type);
8308 temp.Store (ec);
8311 if (prepared)
8312 StoreFromPtr (ig, t);
8313 else if (is_stobj)
8314 ig.Emit (OpCodes.Stobj, t);
8315 else if (has_type_arg)
8316 ig.Emit (op, t);
8317 else
8318 ig.Emit (op);
8319 } else {
8320 source.Emit (ec);
8321 if (leave_copy) {
8322 ec.ig.Emit (OpCodes.Dup);
8323 temp = new LocalTemporary (this.type);
8324 temp.Store (ec);
8327 if (prepared) {
8328 StoreFromPtr (ig, t);
8329 } else {
8330 int arg_count = ea.Arguments.Count;
8331 Type [] args = new Type [arg_count + 1];
8332 for (int i = 0; i < arg_count; i++) {
8333 //args [i++] = a.Type;
8334 args [i] = TypeManager.int32_type;
8336 args [arg_count] = type;
8338 MethodInfo set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
8339 ea.Expr.Type, "Set",
8340 CallingConventions.HasThis |
8341 CallingConventions.Standard,
8342 TypeManager.void_type, args);
8344 ig.Emit (OpCodes.Call, set);
8348 if (temp != null) {
8349 temp.Emit (ec);
8350 temp.Release (ec);
8354 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8356 if (!source.Emit (ec, this)) {
8357 if (leave_copy)
8358 throw new NotImplementedException ();
8360 return;
8363 throw new NotImplementedException ();
8366 public void AddressOf (EmitContext ec, AddressOp mode)
8368 int rank = ea.Expr.Type.GetArrayRank ();
8369 ILGenerator ig = ec.ig;
8371 LoadArrayAndArguments (ec);
8373 if (rank == 1){
8374 ig.Emit (OpCodes.Ldelema, type);
8375 } else {
8376 MethodInfo address = FetchAddressMethod ();
8377 ig.Emit (OpCodes.Call, address);
8381 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8383 type = storey.MutateType (type);
8384 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8388 /// <summary>
8389 /// Expressions that represent an indexer call.
8390 /// </summary>
8391 public class IndexerAccess : Expression, IAssignMethod
8393 class IndexerMethodGroupExpr : MethodGroupExpr
8395 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8396 : base (null, loc)
8398 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8401 public override string Name {
8402 get {
8403 return "this";
8407 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8410 // Here is the trick, decrease number of arguments by 1 when only
8411 // available property method is setter. This makes overload resolution
8412 // work correctly for indexers.
8415 if (method.Name [0] == 'g')
8416 return parameters.Count;
8418 return parameters.Count - 1;
8422 class Indexers
8424 // Contains either property getter or setter
8425 public ArrayList Methods;
8426 public ArrayList Properties;
8428 Indexers ()
8432 void Append (Type caller_type, MemberInfo [] mi)
8434 if (mi == null)
8435 return;
8437 foreach (PropertyInfo property in mi) {
8438 MethodInfo accessor = property.GetGetMethod (true);
8439 if (accessor == null)
8440 accessor = property.GetSetMethod (true);
8442 if (Methods == null) {
8443 Methods = new ArrayList ();
8444 Properties = new ArrayList ();
8447 Methods.Add (accessor);
8448 Properties.Add (property);
8452 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8454 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8456 return TypeManager.MemberLookup (
8457 caller_type, caller_type, lookup_type, MemberTypes.Property,
8458 BindingFlags.Public | BindingFlags.Instance |
8459 BindingFlags.DeclaredOnly, p_name, null);
8462 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8464 Indexers ix = new Indexers ();
8466 if (TypeManager.IsGenericParameter (lookup_type)) {
8467 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8468 if (gc == null)
8469 return ix;
8471 if (gc.HasClassConstraint) {
8472 Type class_contraint = gc.ClassConstraint;
8473 while (class_contraint != TypeManager.object_type && class_contraint != null) {
8474 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, class_contraint));
8475 class_contraint = class_contraint.BaseType;
8479 Type[] ifaces = gc.InterfaceConstraints;
8480 foreach (Type itype in ifaces)
8481 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8483 return ix;
8486 Type copy = lookup_type;
8487 while (copy != TypeManager.object_type && copy != null){
8488 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8489 copy = copy.BaseType;
8492 if (lookup_type.IsInterface) {
8493 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8494 if (ifaces != null) {
8495 foreach (Type itype in ifaces)
8496 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8500 return ix;
8505 // Points to our "data" repository
8507 MethodInfo get, set;
8508 bool is_base_indexer;
8509 bool prepared;
8510 LocalTemporary temp;
8511 LocalTemporary prepared_value;
8512 Expression set_expr;
8514 protected Type indexer_type;
8515 protected Type current_type;
8516 protected Expression instance_expr;
8517 protected Arguments arguments;
8519 public IndexerAccess (ElementAccess ea, Location loc)
8520 : this (ea.Expr, false, loc)
8522 this.arguments = ea.Arguments;
8525 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8526 Location loc)
8528 this.instance_expr = instance_expr;
8529 this.is_base_indexer = is_base_indexer;
8530 this.eclass = ExprClass.Value;
8531 this.loc = loc;
8534 static string GetAccessorName (bool isSet)
8536 return isSet ? "set" : "get";
8539 public override Expression CreateExpressionTree (ResolveContext ec)
8541 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8542 instance_expr.CreateExpressionTree (ec),
8543 new TypeOfMethod (get, loc));
8545 return CreateExpressionFactoryCall (ec, "Call", args);
8548 protected virtual void CommonResolve (ResolveContext ec)
8550 indexer_type = instance_expr.Type;
8551 current_type = ec.CurrentType;
8554 public override Expression DoResolve (ResolveContext ec)
8556 return ResolveAccessor (ec, null);
8559 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8561 if (right_side == EmptyExpression.OutAccess) {
8562 ec.Report.Error (206, loc,
8563 "A property or indexer may not be passed as an out or ref parameter");
8564 return null;
8567 // if the indexer returns a value type, and we try to set a field in it
8568 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8569 Error_CannotModifyIntermediateExpressionValue (ec);
8572 return ResolveAccessor (ec, right_side);
8575 Expression ResolveAccessor (ResolveContext ec, Expression right_side)
8577 CommonResolve (ec);
8579 bool dynamic;
8580 arguments.Resolve (ec, out dynamic);
8581 if (dynamic || TypeManager.IsDynamicType (indexer_type)) {
8582 int additional = right_side == null ? 1 : 2;
8583 Arguments args = new Arguments (arguments.Count + additional);
8584 if (is_base_indexer) {
8585 ec.Report.Error (1972, loc, "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8586 } else {
8587 args.Add (new Argument (instance_expr));
8589 args.AddRange (arguments);
8590 if (right_side != null)
8591 args.Add (new Argument (right_side));
8593 return new DynamicIndexBinder (right_side != null, args, loc).Resolve (ec);
8596 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8597 if (ilist.Methods == null) {
8598 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8599 TypeManager.CSharpName (indexer_type));
8600 return null;
8603 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8604 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8605 if (mg == null)
8606 return null;
8608 MethodInfo mi = (MethodInfo) mg;
8609 PropertyInfo pi = null;
8610 for (int i = 0; i < ilist.Methods.Count; ++i) {
8611 if (ilist.Methods [i] == mi) {
8612 pi = (PropertyInfo) ilist.Properties [i];
8613 break;
8617 type = TypeManager.TypeToCoreType (pi.PropertyType);
8618 if (type.IsPointer && !ec.IsUnsafe)
8619 UnsafeError (ec, loc);
8621 MethodInfo accessor;
8622 if (right_side == null) {
8623 accessor = get = pi.GetGetMethod (true);
8624 } else {
8625 accessor = set = pi.GetSetMethod (true);
8626 if (accessor == null && pi.GetGetMethod (true) != null) {
8627 ec.Report.SymbolRelatedToPreviousError (pi);
8628 ec.Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8629 TypeManager.GetFullNameSignature (pi));
8630 return null;
8633 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8636 if (accessor == null) {
8637 ec.Report.SymbolRelatedToPreviousError (pi);
8638 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8639 TypeManager.GetFullNameSignature (pi), GetAccessorName (right_side != null));
8640 return null;
8644 // Only base will allow this invocation to happen.
8646 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8647 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (pi));
8650 bool must_do_cs1540_check;
8651 if (!IsAccessorAccessible (ec.CurrentType, accessor, out must_do_cs1540_check)) {
8652 if (set == null)
8653 set = pi.GetSetMethod (true);
8654 else
8655 get = pi.GetGetMethod (true);
8657 if (set != null && get != null &&
8658 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8659 ec.Report.SymbolRelatedToPreviousError (accessor);
8660 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8661 TypeManager.GetFullNameSignature (pi), GetAccessorName (right_side != null));
8662 } else {
8663 ec.Report.SymbolRelatedToPreviousError (pi);
8664 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi), ec.Report);
8668 instance_expr.CheckMarshalByRefAccess (ec);
8669 eclass = ExprClass.IndexerAccess;
8670 return this;
8673 public void Emit (EmitContext ec, bool leave_copy)
8675 if (prepared) {
8676 prepared_value.Emit (ec);
8677 } else {
8678 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8679 arguments, loc, false, false);
8682 if (leave_copy) {
8683 ec.ig.Emit (OpCodes.Dup);
8684 temp = new LocalTemporary (Type);
8685 temp.Store (ec);
8690 // source is ignored, because we already have a copy of it from the
8691 // LValue resolution and we have already constructed a pre-cached
8692 // version of the arguments (ea.set_arguments);
8694 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8696 prepared = prepare_for_load;
8697 Expression value = set_expr;
8699 if (prepared) {
8700 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8701 arguments, loc, true, false);
8703 prepared_value = new LocalTemporary (type);
8704 prepared_value.Store (ec);
8705 source.Emit (ec);
8706 prepared_value.Release (ec);
8708 if (leave_copy) {
8709 ec.ig.Emit (OpCodes.Dup);
8710 temp = new LocalTemporary (Type);
8711 temp.Store (ec);
8713 } else if (leave_copy) {
8714 temp = new LocalTemporary (Type);
8715 source.Emit (ec);
8716 temp.Store (ec);
8717 value = temp;
8720 if (!prepared)
8721 arguments.Add (new Argument (value));
8723 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8725 if (temp != null) {
8726 temp.Emit (ec);
8727 temp.Release (ec);
8731 public override void Emit (EmitContext ec)
8733 Emit (ec, false);
8736 public override string GetSignatureForError ()
8738 return TypeManager.CSharpSignature (get != null ? get : set, false);
8741 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8743 if (get != null)
8744 get = storey.MutateGenericMethod (get);
8745 if (set != null)
8746 set = storey.MutateGenericMethod (set);
8748 instance_expr.MutateHoistedGenericType (storey);
8749 if (arguments != null)
8750 arguments.MutateHoistedGenericType (storey);
8752 type = storey.MutateType (type);
8755 protected override void CloneTo (CloneContext clonectx, Expression t)
8757 IndexerAccess target = (IndexerAccess) t;
8759 if (arguments != null)
8760 target.arguments = arguments.Clone (clonectx);
8762 if (instance_expr != null)
8763 target.instance_expr = instance_expr.Clone (clonectx);
8767 /// <summary>
8768 /// The base operator for method names
8769 /// </summary>
8770 public class BaseAccess : Expression {
8771 public readonly string Identifier;
8772 TypeArguments args;
8774 public BaseAccess (string member, Location l)
8776 this.Identifier = member;
8777 loc = l;
8780 public BaseAccess (string member, TypeArguments args, Location l)
8781 : this (member, l)
8783 this.args = args;
8786 public override Expression CreateExpressionTree (ResolveContext ec)
8788 throw new NotSupportedException ("ET");
8791 public override Expression DoResolve (ResolveContext ec)
8793 Expression c = CommonResolve (ec);
8795 if (c == null)
8796 return null;
8799 // MethodGroups use this opportunity to flag an error on lacking ()
8801 if (!(c is MethodGroupExpr))
8802 return c.Resolve (ec);
8803 return c;
8806 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8808 Expression c = CommonResolve (ec);
8810 if (c == null)
8811 return null;
8814 // MethodGroups use this opportunity to flag an error on lacking ()
8816 if (! (c is MethodGroupExpr))
8817 return c.DoResolveLValue (ec, right_side);
8819 return c;
8822 Expression CommonResolve (ResolveContext ec)
8824 Expression member_lookup;
8825 Type current_type = ec.CurrentType;
8826 Type base_type = current_type.BaseType;
8828 if (!This.IsThisAvailable (ec)) {
8829 if (ec.IsStatic) {
8830 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
8831 } else {
8832 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
8834 return null;
8837 member_lookup = MemberLookup (ec.Compiler, ec.CurrentType, null, base_type, Identifier,
8838 AllMemberTypes, AllBindingFlags, loc);
8839 if (member_lookup == null) {
8840 Error_MemberLookupFailed (ec, ec.CurrentType, base_type, base_type, Identifier,
8841 null, AllMemberTypes, AllBindingFlags);
8842 return null;
8845 Expression left;
8847 if (ec.IsStatic)
8848 left = new TypeExpression (base_type, loc);
8849 else
8850 left = ec.GetThis (loc);
8852 MemberExpr me = member_lookup as MemberExpr;
8853 if (me == null){
8854 if (member_lookup is TypeExpression){
8855 ec.Report.Error (582, loc, "{0}: Can not reference a type through an expression, try `{1}' instead",
8856 Identifier, member_lookup.GetSignatureForError ());
8857 } else {
8858 ec.Report.Error (582, loc, "{0}: Can not reference a {1} through an expression",
8859 Identifier, member_lookup.ExprClassName);
8862 return null;
8865 me = me.ResolveMemberAccess (ec, left, loc, null);
8866 if (me == null)
8867 return null;
8869 me.IsBase = true;
8870 if (args != null) {
8871 args.Resolve (ec);
8872 me.SetTypeArguments (ec, args);
8875 return me;
8878 public override void Emit (EmitContext ec)
8880 throw new Exception ("Should never be called");
8883 protected override void CloneTo (CloneContext clonectx, Expression t)
8885 BaseAccess target = (BaseAccess) t;
8887 if (args != null)
8888 target.args = args.Clone ();
8892 /// <summary>
8893 /// The base indexer operator
8894 /// </summary>
8895 public class BaseIndexerAccess : IndexerAccess {
8896 public BaseIndexerAccess (Arguments args, Location loc)
8897 : base (null, true, loc)
8899 this.arguments = args;
8902 protected override void CommonResolve (ResolveContext ec)
8904 instance_expr = ec.GetThis (loc);
8906 current_type = ec.CurrentType.BaseType;
8907 indexer_type = current_type;
8910 public override Expression CreateExpressionTree (ResolveContext ec)
8912 MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
8913 return base.CreateExpressionTree (ec);
8917 /// <summary>
8918 /// This class exists solely to pass the Type around and to be a dummy
8919 /// that can be passed to the conversion functions (this is used by
8920 /// foreach implementation to typecast the object return value from
8921 /// get_Current into the proper type. All code has been generated and
8922 /// we only care about the side effect conversions to be performed
8924 /// This is also now used as a placeholder where a no-action expression
8925 /// is needed (the `New' class).
8926 /// </summary>
8927 public class EmptyExpression : Expression {
8928 public static readonly Expression Null = new EmptyExpression ();
8930 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8931 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8932 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8933 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8935 static EmptyExpression temp = new EmptyExpression ();
8936 public static EmptyExpression Grab ()
8938 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8939 temp = null;
8940 return retval;
8943 public static void Release (EmptyExpression e)
8945 temp = e;
8948 EmptyExpression ()
8950 // FIXME: Don't set to object
8951 type = TypeManager.object_type;
8952 eclass = ExprClass.Value;
8953 loc = Location.Null;
8956 public EmptyExpression (Type t)
8958 type = t;
8959 eclass = ExprClass.Value;
8960 loc = Location.Null;
8963 public override Expression CreateExpressionTree (ResolveContext ec)
8965 throw new NotSupportedException ("ET");
8968 public override Expression DoResolve (ResolveContext ec)
8970 return this;
8973 public override void Emit (EmitContext ec)
8975 // nothing, as we only exist to not do anything.
8978 public override void EmitSideEffect (EmitContext ec)
8983 // This is just because we might want to reuse this bad boy
8984 // instead of creating gazillions of EmptyExpressions.
8985 // (CanImplicitConversion uses it)
8987 public void SetType (Type t)
8989 type = t;
8994 // Empty statement expression
8996 public sealed class EmptyExpressionStatement : ExpressionStatement
8998 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
9000 private EmptyExpressionStatement ()
9002 eclass = ExprClass.Value;
9003 loc = Location.Null;
9006 public override Expression CreateExpressionTree (ResolveContext ec)
9008 return null;
9011 public override void EmitStatement (EmitContext ec)
9013 // Do nothing
9016 public override Expression DoResolve (ResolveContext ec)
9018 type = TypeManager.object_type;
9019 return this;
9022 public override void Emit (EmitContext ec)
9024 // Do nothing
9028 public class UserCast : Expression {
9029 MethodInfo method;
9030 Expression source;
9032 public UserCast (MethodInfo method, Expression source, Location l)
9034 this.method = method;
9035 this.source = source;
9036 type = TypeManager.TypeToCoreType (method.ReturnType);
9037 loc = l;
9040 public Expression Source {
9041 get {
9042 return source;
9046 public override Expression CreateExpressionTree (ResolveContext ec)
9048 Arguments args = new Arguments (3);
9049 args.Add (new Argument (source.CreateExpressionTree (ec)));
9050 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9051 args.Add (new Argument (new TypeOfMethod (method, loc)));
9052 return CreateExpressionFactoryCall (ec, "Convert", args);
9055 public override Expression DoResolve (ResolveContext ec)
9057 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
9058 if (oa != null)
9059 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
9061 eclass = ExprClass.Value;
9062 return this;
9065 public override void Emit (EmitContext ec)
9067 source.Emit (ec);
9068 ec.ig.Emit (OpCodes.Call, method);
9071 public override string GetSignatureForError ()
9073 return TypeManager.CSharpSignature (method);
9076 #if NET_4_0
9077 public override SLE.Expression MakeExpression (BuilderContext ctx)
9079 return SLE.Expression.Convert (source.MakeExpression (ctx), type, method);
9081 #endif
9083 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9085 source.MutateHoistedGenericType (storey);
9086 method = storey.MutateGenericMethod (method);
9090 // <summary>
9091 // This class is used to "construct" the type during a typecast
9092 // operation. Since the Type.GetType class in .NET can parse
9093 // the type specification, we just use this to construct the type
9094 // one bit at a time.
9095 // </summary>
9096 public class ComposedCast : TypeExpr {
9097 FullNamedExpression left;
9098 string dim;
9100 public ComposedCast (FullNamedExpression left, string dim)
9101 : this (left, dim, left.Location)
9105 public ComposedCast (FullNamedExpression left, string dim, Location l)
9107 this.left = left;
9108 this.dim = dim;
9109 loc = l;
9112 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
9114 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
9115 if (lexpr == null)
9116 return null;
9118 Type ltype = lexpr.Type;
9119 if ((dim.Length > 0) && (dim [0] == '?')) {
9120 TypeExpr nullable = new Nullable.NullableType (lexpr, loc);
9121 if (dim.Length > 1)
9122 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
9123 return nullable.ResolveAsTypeTerminal (ec, false);
9126 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
9127 return null;
9129 if (dim.Length != 0 && dim [0] == '[') {
9130 if (TypeManager.IsSpecialType (ltype)) {
9131 ec.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
9132 return null;
9135 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
9136 ec.Compiler.Report.SymbolRelatedToPreviousError (ltype);
9137 ec.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9138 TypeManager.CSharpName (ltype));
9142 if (dim != "")
9143 type = TypeManager.GetConstructedType (ltype, dim);
9144 else
9145 type = ltype;
9147 if (type == null)
9148 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
9150 if (type.IsPointer && !ec.IsUnsafe){
9151 UnsafeError (ec.Compiler.Report, loc);
9154 eclass = ExprClass.Type;
9155 return this;
9158 public override string GetSignatureForError ()
9160 return left.GetSignatureForError () + dim;
9163 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
9165 return ResolveAsBaseTerminal (ec, silent);
9169 public class FixedBufferPtr : Expression {
9170 Expression array;
9172 public FixedBufferPtr (Expression array, Type array_type, Location l)
9174 this.array = array;
9175 this.loc = l;
9177 type = TypeManager.GetPointerType (array_type);
9178 eclass = ExprClass.Value;
9181 public override Expression CreateExpressionTree (ResolveContext ec)
9183 Error_PointerInsideExpressionTree (ec);
9184 return null;
9187 public override void Emit(EmitContext ec)
9189 array.Emit (ec);
9192 public override Expression DoResolve (ResolveContext ec)
9195 // We are born fully resolved
9197 return this;
9203 // This class is used to represent the address of an array, used
9204 // only by the Fixed statement, this generates "&a [0]" construct
9205 // for fixed (char *pa = a)
9207 public class ArrayPtr : FixedBufferPtr {
9208 Type array_type;
9210 public ArrayPtr (Expression array, Type array_type, Location l):
9211 base (array, array_type, l)
9213 this.array_type = array_type;
9216 public override void Emit (EmitContext ec)
9218 base.Emit (ec);
9220 ILGenerator ig = ec.ig;
9221 IntLiteral.EmitInt (ig, 0);
9222 ig.Emit (OpCodes.Ldelema, array_type);
9227 // Encapsulates a conversion rules required for array indexes
9229 public class ArrayIndexCast : TypeCast
9231 public ArrayIndexCast (Expression expr)
9232 : base (expr, expr.Type)
9234 if (type == TypeManager.int32_type)
9235 throw new ArgumentException ("unnecessary conversion");
9238 public override Expression CreateExpressionTree (ResolveContext ec)
9240 Arguments args = new Arguments (2);
9241 args.Add (new Argument (child.CreateExpressionTree (ec)));
9242 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9243 return CreateExpressionFactoryCall (ec, "ConvertChecked", args);
9246 public override void Emit (EmitContext ec)
9248 child.Emit (ec);
9250 if (type == TypeManager.uint32_type)
9251 ec.ig.Emit (OpCodes.Conv_U);
9252 else if (type == TypeManager.int64_type)
9253 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9254 else if (type == TypeManager.uint64_type)
9255 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9256 else
9257 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9260 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
9262 return child.GetAttributableValue (ec, value_type, out value);
9267 // Implements the `stackalloc' keyword
9269 public class StackAlloc : Expression {
9270 Type otype;
9271 Expression t;
9272 Expression count;
9274 public StackAlloc (Expression type, Expression count, Location l)
9276 t = type;
9277 this.count = count;
9278 loc = l;
9281 public override Expression CreateExpressionTree (ResolveContext ec)
9283 throw new NotSupportedException ("ET");
9286 public override Expression DoResolve (ResolveContext ec)
9288 count = count.Resolve (ec);
9289 if (count == null)
9290 return null;
9292 if (count.Type != TypeManager.uint32_type){
9293 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9294 if (count == null)
9295 return null;
9298 Constant c = count as Constant;
9299 if (c != null && c.IsNegative) {
9300 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9301 return null;
9304 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9305 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9308 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9309 if (texpr == null)
9310 return null;
9312 otype = texpr.Type;
9314 if (!TypeManager.VerifyUnManaged (otype, loc))
9315 return null;
9317 type = TypeManager.GetPointerType (otype);
9318 eclass = ExprClass.Value;
9320 return this;
9323 public override void Emit (EmitContext ec)
9325 int size = GetTypeSize (otype);
9326 ILGenerator ig = ec.ig;
9328 count.Emit (ec);
9330 if (size == 0)
9331 ig.Emit (OpCodes.Sizeof, otype);
9332 else
9333 IntConstant.EmitInt (ig, size);
9335 ig.Emit (OpCodes.Mul_Ovf_Un);
9336 ig.Emit (OpCodes.Localloc);
9339 protected override void CloneTo (CloneContext clonectx, Expression t)
9341 StackAlloc target = (StackAlloc) t;
9342 target.count = count.Clone (clonectx);
9343 target.t = t.Clone (clonectx);
9348 // An object initializer expression
9350 public class ElementInitializer : Assign
9352 public readonly string Name;
9354 public ElementInitializer (string name, Expression initializer, Location loc)
9355 : base (null, initializer, loc)
9357 this.Name = name;
9360 protected override void CloneTo (CloneContext clonectx, Expression t)
9362 ElementInitializer target = (ElementInitializer) t;
9363 target.source = source.Clone (clonectx);
9366 public override Expression CreateExpressionTree (ResolveContext ec)
9368 Arguments args = new Arguments (2);
9369 FieldExpr fe = target as FieldExpr;
9370 if (fe != null)
9371 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9372 else
9373 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9375 args.Add (new Argument (source.CreateExpressionTree (ec)));
9376 return CreateExpressionFactoryCall (ec,
9377 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9378 args);
9381 public override Expression DoResolve (ResolveContext ec)
9383 if (source == null)
9384 return EmptyExpressionStatement.Instance;
9386 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9387 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9389 if (me == null)
9390 return null;
9392 target = me;
9393 me.InstanceExpression = ec.CurrentInitializerVariable;
9395 if (source is CollectionOrObjectInitializers) {
9396 Expression previous = ec.CurrentInitializerVariable;
9397 ec.CurrentInitializerVariable = target;
9398 source = source.Resolve (ec);
9399 ec.CurrentInitializerVariable = previous;
9400 if (source == null)
9401 return null;
9403 eclass = source.eclass;
9404 type = source.Type;
9405 return this;
9408 Expression expr = base.DoResolve (ec);
9409 if (expr == null)
9410 return null;
9413 // Ignore field initializers with default value
9415 Constant c = source as Constant;
9416 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9417 return EmptyExpressionStatement.Instance.DoResolve (ec);
9419 return expr;
9422 protected override Expression Error_MemberLookupFailed (ResolveContext ec, Type type, MemberInfo[] members)
9424 MemberInfo member = members [0];
9425 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9426 ec.Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9427 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9428 else
9429 ec.Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9430 TypeManager.GetFullNameSignature (member));
9432 return null;
9435 public override void EmitStatement (EmitContext ec)
9437 if (source is CollectionOrObjectInitializers)
9438 source.Emit (ec);
9439 else
9440 base.EmitStatement (ec);
9445 // A collection initializer expression
9447 class CollectionElementInitializer : Invocation
9449 public class ElementInitializerArgument : Argument
9451 public ElementInitializerArgument (Expression e)
9452 : base (e)
9457 sealed class AddMemberAccess : MemberAccess
9459 public AddMemberAccess (Expression expr, Location loc)
9460 : base (expr, "Add", loc)
9464 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
9466 if (TypeManager.HasElementType (type))
9467 return;
9469 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9473 public CollectionElementInitializer (Expression argument)
9474 : base (null, new Arguments (1))
9476 base.arguments.Add (new ElementInitializerArgument (argument));
9477 this.loc = argument.Location;
9480 public CollectionElementInitializer (ArrayList arguments, Location loc)
9481 : base (null, new Arguments (arguments.Count))
9483 foreach (Expression e in arguments)
9484 base.arguments.Add (new ElementInitializerArgument (e));
9486 this.loc = loc;
9489 public override Expression CreateExpressionTree (ResolveContext ec)
9491 Arguments args = new Arguments (2);
9492 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9494 ArrayList expr_initializers = new ArrayList (arguments.Count);
9495 foreach (Argument a in arguments)
9496 expr_initializers.Add (a.CreateExpressionTree (ec));
9498 args.Add (new Argument (new ArrayCreation (
9499 CreateExpressionTypeExpression (ec, loc), "[]", expr_initializers, loc)));
9500 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9503 protected override void CloneTo (CloneContext clonectx, Expression t)
9505 CollectionElementInitializer target = (CollectionElementInitializer) t;
9506 if (arguments != null)
9507 target.arguments = arguments.Clone (clonectx);
9510 public override Expression DoResolve (ResolveContext ec)
9512 if (eclass != ExprClass.Invalid)
9513 return this;
9515 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9517 return base.DoResolve (ec);
9522 // A block of object or collection initializers
9524 public class CollectionOrObjectInitializers : ExpressionStatement
9526 ArrayList initializers;
9527 bool is_collection_initialization;
9529 public static readonly CollectionOrObjectInitializers Empty =
9530 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9532 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9534 this.initializers = initializers;
9535 this.loc = loc;
9538 public bool IsEmpty {
9539 get {
9540 return initializers.Count == 0;
9544 public bool IsCollectionInitializer {
9545 get {
9546 return is_collection_initialization;
9550 protected override void CloneTo (CloneContext clonectx, Expression target)
9552 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9554 t.initializers = new ArrayList (initializers.Count);
9555 foreach (Expression e in initializers)
9556 t.initializers.Add (e.Clone (clonectx));
9559 public override Expression CreateExpressionTree (ResolveContext ec)
9561 ArrayList expr_initializers = new ArrayList (initializers.Count);
9562 foreach (Expression e in initializers) {
9563 Expression expr = e.CreateExpressionTree (ec);
9564 if (expr != null)
9565 expr_initializers.Add (expr);
9568 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9571 public override Expression DoResolve (ResolveContext ec)
9573 if (eclass != ExprClass.Invalid)
9574 return this;
9576 ArrayList element_names = null;
9577 for (int i = 0; i < initializers.Count; ++i) {
9578 Expression initializer = (Expression) initializers [i];
9579 ElementInitializer element_initializer = initializer as ElementInitializer;
9581 if (i == 0) {
9582 if (element_initializer != null) {
9583 element_names = new ArrayList (initializers.Count);
9584 element_names.Add (element_initializer.Name);
9585 } else if (initializer is CompletingExpression){
9586 initializer.Resolve (ec);
9587 throw new InternalErrorException ("This line should never be reached");
9588 } else {
9589 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type, TypeManager.ienumerable_type)) {
9590 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9591 "object initializer because type `{1}' does not implement `{2}' interface",
9592 ec.CurrentInitializerVariable.GetSignatureForError (),
9593 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9594 TypeManager.CSharpName (TypeManager.ienumerable_type));
9595 return null;
9597 is_collection_initialization = true;
9599 } else {
9600 if (is_collection_initialization != (element_initializer == null)) {
9601 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9602 is_collection_initialization ? "collection initializer" : "object initializer");
9603 continue;
9606 if (!is_collection_initialization) {
9607 if (element_names.Contains (element_initializer.Name)) {
9608 ec.Report.Error (1912, element_initializer.Location,
9609 "An object initializer includes more than one member `{0}' initialization",
9610 element_initializer.Name);
9611 } else {
9612 element_names.Add (element_initializer.Name);
9617 Expression e = initializer.Resolve (ec);
9618 if (e == EmptyExpressionStatement.Instance)
9619 initializers.RemoveAt (i--);
9620 else
9621 initializers [i] = e;
9624 type = ec.CurrentInitializerVariable.Type;
9625 if (is_collection_initialization) {
9626 if (TypeManager.HasElementType (type)) {
9627 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9628 TypeManager.CSharpName (type));
9632 eclass = ExprClass.Variable;
9633 return this;
9636 public override void Emit (EmitContext ec)
9638 EmitStatement (ec);
9641 public override void EmitStatement (EmitContext ec)
9643 foreach (ExpressionStatement e in initializers)
9644 e.EmitStatement (ec);
9647 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9649 foreach (Expression e in initializers)
9650 e.MutateHoistedGenericType (storey);
9655 // New expression with element/object initializers
9657 public class NewInitialize : New
9660 // This class serves as a proxy for variable initializer target instances.
9661 // A real variable is assigned later when we resolve left side of an
9662 // assignment
9664 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9666 NewInitialize new_instance;
9668 public InitializerTargetExpression (NewInitialize newInstance)
9670 this.type = newInstance.type;
9671 this.loc = newInstance.loc;
9672 this.eclass = newInstance.eclass;
9673 this.new_instance = newInstance;
9676 public override Expression CreateExpressionTree (ResolveContext ec)
9678 // Should not be reached
9679 throw new NotSupportedException ("ET");
9682 public override Expression DoResolve (ResolveContext ec)
9684 return this;
9687 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9689 return this;
9692 public override void Emit (EmitContext ec)
9694 Expression e = (Expression) new_instance.instance;
9695 e.Emit (ec);
9698 #region IMemoryLocation Members
9700 public void AddressOf (EmitContext ec, AddressOp mode)
9702 new_instance.instance.AddressOf (ec, mode);
9705 #endregion
9708 CollectionOrObjectInitializers initializers;
9709 IMemoryLocation instance;
9711 public NewInitialize (Expression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9712 : base (requested_type, arguments, l)
9714 this.initializers = initializers;
9717 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9719 instance = base.EmitAddressOf (ec, Mode);
9721 if (!initializers.IsEmpty)
9722 initializers.Emit (ec);
9724 return instance;
9727 protected override void CloneTo (CloneContext clonectx, Expression t)
9729 base.CloneTo (clonectx, t);
9731 NewInitialize target = (NewInitialize) t;
9732 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9735 public override Expression CreateExpressionTree (ResolveContext ec)
9737 Arguments args = new Arguments (2);
9738 args.Add (new Argument (base.CreateExpressionTree (ec)));
9739 if (!initializers.IsEmpty)
9740 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9742 return CreateExpressionFactoryCall (ec,
9743 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9744 args);
9747 public override Expression DoResolve (ResolveContext ec)
9749 if (eclass != ExprClass.Invalid)
9750 return this;
9752 Expression e = base.DoResolve (ec);
9753 if (type == null)
9754 return null;
9756 Expression previous = ec.CurrentInitializerVariable;
9757 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9758 initializers.Resolve (ec);
9759 ec.CurrentInitializerVariable = previous;
9760 return e;
9763 public override bool Emit (EmitContext ec, IMemoryLocation target)
9765 bool left_on_stack = base.Emit (ec, target);
9767 if (initializers.IsEmpty)
9768 return left_on_stack;
9770 LocalTemporary temp = target as LocalTemporary;
9771 if (temp == null) {
9772 if (!left_on_stack) {
9773 VariableReference vr = target as VariableReference;
9775 // FIXME: This still does not work correctly for pre-set variables
9776 if (vr != null && vr.IsRef)
9777 target.AddressOf (ec, AddressOp.Load);
9779 ((Expression) target).Emit (ec);
9780 left_on_stack = true;
9783 temp = new LocalTemporary (type);
9786 instance = temp;
9787 if (left_on_stack)
9788 temp.Store (ec);
9790 initializers.Emit (ec);
9792 if (left_on_stack) {
9793 temp.Emit (ec);
9794 temp.Release (ec);
9797 return left_on_stack;
9800 public override bool HasInitializer {
9801 get {
9802 return !initializers.IsEmpty;
9806 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9808 base.MutateHoistedGenericType (storey);
9809 initializers.MutateHoistedGenericType (storey);
9813 public class AnonymousTypeDeclaration : Expression
9815 ArrayList parameters;
9816 readonly TypeContainer parent;
9817 static readonly ArrayList EmptyParameters = new ArrayList (0);
9819 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9821 this.parameters = parameters;
9822 this.parent = parent;
9823 this.loc = loc;
9826 protected override void CloneTo (CloneContext clonectx, Expression target)
9828 if (parameters == null)
9829 return;
9831 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9832 t.parameters = new ArrayList (parameters.Count);
9833 foreach (AnonymousTypeParameter atp in parameters)
9834 t.parameters.Add (atp.Clone (clonectx));
9837 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, ArrayList parameters)
9839 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
9840 if (type != null)
9841 return type;
9843 type = AnonymousTypeClass.Create (ec.Compiler, parent, parameters, loc);
9844 if (type == null)
9845 return null;
9847 type.DefineType ();
9848 type.Define ();
9849 type.EmitType ();
9850 if (ec.Report.Errors == 0)
9851 type.CloseType ();
9853 parent.Module.AddAnonymousType (type);
9854 return type;
9857 public override Expression CreateExpressionTree (ResolveContext ec)
9859 throw new NotSupportedException ("ET");
9862 public override Expression DoResolve (ResolveContext ec)
9864 AnonymousTypeClass anonymous_type;
9866 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
9867 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9868 return null;
9871 if (parameters == null) {
9872 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
9873 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9874 null, loc).Resolve (ec);
9877 bool error = false;
9878 Arguments arguments = new Arguments (parameters.Count);
9879 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9880 for (int i = 0; i < parameters.Count; ++i) {
9881 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9882 if (e == null) {
9883 error = true;
9884 continue;
9887 arguments.Add (new Argument (e));
9888 t_args [i] = new TypeExpression (e.Type, e.Location);
9891 if (error)
9892 return null;
9894 anonymous_type = CreateAnonymousType (ec, parameters);
9895 if (anonymous_type == null)
9896 return null;
9898 GenericTypeExpr te = new GenericTypeExpr (anonymous_type.TypeBuilder,
9899 new TypeArguments (t_args), loc);
9901 return new New (te, arguments, loc).Resolve (ec);
9904 public override void Emit (EmitContext ec)
9906 throw new InternalErrorException ("Should not be reached");
9910 public class AnonymousTypeParameter : ShimExpression
9912 public readonly string Name;
9914 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9915 : base (initializer)
9917 this.Name = name;
9918 this.loc = loc;
9921 public AnonymousTypeParameter (Parameter parameter)
9922 : base (new SimpleName (parameter.Name, parameter.Location))
9924 this.Name = parameter.Name;
9925 this.loc = parameter.Location;
9928 public override bool Equals (object o)
9930 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9931 return other != null && Name == other.Name;
9934 public override int GetHashCode ()
9936 return Name.GetHashCode ();
9939 public override Expression DoResolve (ResolveContext ec)
9941 Expression e = expr.Resolve (ec);
9942 if (e == null)
9943 return null;
9945 if (e.eclass == ExprClass.MethodGroup) {
9946 Error_InvalidInitializer (ec, e.ExprClassName);
9947 return null;
9950 type = e.Type;
9951 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9952 type == InternalType.AnonymousMethod || type.IsPointer) {
9953 Error_InvalidInitializer (ec, e.GetSignatureForError ());
9954 return null;
9957 return e;
9960 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
9962 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9963 Name, initializer);