* xbuild/Microsoft.Common.targets (_RecordCleanFile): Append list of
[mcs.git] / mcs / expression.cs
bloba0753c9648cf45dc7765ec5e1fe0dd55cb35f583
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.Generic;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Text;
19 using System.Linq;
20 using SLE = System.Linq.Expressions;
23 // This is an user operator expression, automatically created during
24 // resolve phase
26 public class UserOperatorCall : Expression {
27 public delegate Expression ExpressionTreeExpression (ResolveContext ec, MethodGroupExpr mg);
29 protected readonly Arguments arguments;
30 protected readonly MethodGroupExpr mg;
31 readonly ExpressionTreeExpression expr_tree;
33 public UserOperatorCall (MethodGroupExpr mg, Arguments args, ExpressionTreeExpression expr_tree, Location loc)
35 this.mg = mg;
36 this.arguments = args;
37 this.expr_tree = expr_tree;
39 type = TypeManager.TypeToCoreType (((MethodSpec) mg).ReturnType);
40 eclass = ExprClass.Value;
41 this.loc = loc;
44 public override Expression CreateExpressionTree (ResolveContext ec)
46 if (expr_tree != null)
47 return expr_tree (ec, mg);
49 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
50 new NullLiteral (loc),
51 mg.CreateExpressionTree (ec));
53 return CreateExpressionFactoryCall (ec, "Call", args);
56 protected override void CloneTo (CloneContext context, Expression target)
58 // Nothing to clone
61 protected override Expression DoResolve (ResolveContext ec)
64 // We are born fully resolved
66 return this;
69 public override void Emit (EmitContext ec)
71 mg.EmitCall (ec, arguments);
74 public override SLE.Expression MakeExpression (BuilderContext ctx)
76 var method = ((MethodSpec) mg).MetaInfo as MethodInfo;
77 return SLE.Expression.Call (method, Arguments.MakeExpression (arguments, ctx));
80 public MethodGroupExpr Method {
81 get { return mg; }
84 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
86 arguments.MutateHoistedGenericType (storey);
87 mg.MutateHoistedGenericType (storey);
91 public class ParenthesizedExpression : ShimExpression
93 public ParenthesizedExpression (Expression expr)
94 : base (expr)
96 loc = expr.Location;
99 protected override Expression DoResolve (ResolveContext ec)
101 return expr.Resolve (ec);
104 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
106 return expr.DoResolveLValue (ec, right_side);
111 // Unary implements unary expressions.
113 public class Unary : Expression
115 public enum Operator : byte {
116 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
117 AddressOf, TOP
120 static Type [] [] predefined_operators;
122 public readonly Operator Oper;
123 public Expression Expr;
124 Expression enum_conversion;
126 public Unary (Operator op, Expression expr)
128 Oper = op;
129 Expr = expr;
130 loc = expr.Location;
133 // <summary>
134 // This routine will attempt to simplify the unary expression when the
135 // argument is a constant.
136 // </summary>
137 Constant TryReduceConstant (ResolveContext ec, Constant e)
139 if (e is EmptyConstantCast)
140 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
142 if (e is SideEffectConstant) {
143 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
144 return r == null ? null : new SideEffectConstant (r, e, r.Location);
147 Type expr_type = e.Type;
149 switch (Oper){
150 case Operator.UnaryPlus:
151 // Unary numeric promotions
152 if (expr_type == TypeManager.byte_type)
153 return new IntConstant (((ByteConstant)e).Value, e.Location);
154 if (expr_type == TypeManager.sbyte_type)
155 return new IntConstant (((SByteConstant)e).Value, e.Location);
156 if (expr_type == TypeManager.short_type)
157 return new IntConstant (((ShortConstant)e).Value, e.Location);
158 if (expr_type == TypeManager.ushort_type)
159 return new IntConstant (((UShortConstant)e).Value, e.Location);
160 if (expr_type == TypeManager.char_type)
161 return new IntConstant (((CharConstant)e).Value, e.Location);
163 // Predefined operators
164 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
165 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
166 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
167 expr_type == TypeManager.decimal_type) {
168 return e;
171 return null;
173 case Operator.UnaryNegation:
174 // Unary numeric promotions
175 if (expr_type == TypeManager.byte_type)
176 return new IntConstant (-((ByteConstant)e).Value, e.Location);
177 if (expr_type == TypeManager.sbyte_type)
178 return new IntConstant (-((SByteConstant)e).Value, e.Location);
179 if (expr_type == TypeManager.short_type)
180 return new IntConstant (-((ShortConstant)e).Value, e.Location);
181 if (expr_type == TypeManager.ushort_type)
182 return new IntConstant (-((UShortConstant)e).Value, e.Location);
183 if (expr_type == TypeManager.char_type)
184 return new IntConstant (-((CharConstant)e).Value, e.Location);
186 // Predefined operators
187 if (expr_type == TypeManager.int32_type) {
188 int value = ((IntConstant)e).Value;
189 if (value == int.MinValue) {
190 if (ec.ConstantCheckState) {
191 ConstantFold.Error_CompileTimeOverflow (ec, loc);
192 return null;
194 return e;
196 return new IntConstant (-value, e.Location);
198 if (expr_type == TypeManager.int64_type) {
199 long value = ((LongConstant)e).Value;
200 if (value == long.MinValue) {
201 if (ec.ConstantCheckState) {
202 ConstantFold.Error_CompileTimeOverflow (ec, loc);
203 return null;
205 return e;
207 return new LongConstant (-value, e.Location);
210 if (expr_type == TypeManager.uint32_type) {
211 UIntLiteral uil = e as UIntLiteral;
212 if (uil != null) {
213 if (uil.Value == int.MaxValue + (uint) 1)
214 return new IntLiteral (int.MinValue, e.Location);
215 return new LongLiteral (-uil.Value, e.Location);
217 return new LongConstant (-((UIntConstant)e).Value, e.Location);
220 if (expr_type == TypeManager.uint64_type) {
221 ULongLiteral ull = e as ULongLiteral;
222 if (ull != null && ull.Value == 9223372036854775808)
223 return new LongLiteral (long.MinValue, e.Location);
224 return null;
227 if (expr_type == TypeManager.float_type) {
228 FloatLiteral fl = e as FloatLiteral;
229 // For better error reporting
230 if (fl != null)
231 return new FloatLiteral (-fl.Value, e.Location);
233 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
235 if (expr_type == TypeManager.double_type) {
236 DoubleLiteral dl = e as DoubleLiteral;
237 // For better error reporting
238 if (dl != null)
239 return new DoubleLiteral (-dl.Value, e.Location);
241 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
243 if (expr_type == TypeManager.decimal_type)
244 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
246 return null;
248 case Operator.LogicalNot:
249 if (expr_type != TypeManager.bool_type)
250 return null;
252 bool b = (bool)e.GetValue ();
253 return new BoolConstant (!b, e.Location);
255 case Operator.OnesComplement:
256 // Unary numeric promotions
257 if (expr_type == TypeManager.byte_type)
258 return new IntConstant (~((ByteConstant)e).Value, e.Location);
259 if (expr_type == TypeManager.sbyte_type)
260 return new IntConstant (~((SByteConstant)e).Value, e.Location);
261 if (expr_type == TypeManager.short_type)
262 return new IntConstant (~((ShortConstant)e).Value, e.Location);
263 if (expr_type == TypeManager.ushort_type)
264 return new IntConstant (~((UShortConstant)e).Value, e.Location);
265 if (expr_type == TypeManager.char_type)
266 return new IntConstant (~((CharConstant)e).Value, e.Location);
268 // Predefined operators
269 if (expr_type == TypeManager.int32_type)
270 return new IntConstant (~((IntConstant)e).Value, e.Location);
271 if (expr_type == TypeManager.uint32_type)
272 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
273 if (expr_type == TypeManager.int64_type)
274 return new LongConstant (~((LongConstant)e).Value, e.Location);
275 if (expr_type == TypeManager.uint64_type){
276 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
278 if (e is EnumConstant) {
279 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
280 if (e != null)
281 e = new EnumConstant (e, expr_type);
282 return e;
284 return null;
286 throw new Exception ("Can not constant fold: " + Oper.ToString());
289 protected Expression ResolveOperator (ResolveContext ec, Expression expr)
291 eclass = ExprClass.Value;
293 if (predefined_operators == null)
294 CreatePredefinedOperatorsTable ();
296 Type expr_type = expr.Type;
297 Expression best_expr;
300 // Primitive types first
302 if (TypeManager.IsPrimitiveType (expr_type)) {
303 best_expr = ResolvePrimitivePredefinedType (expr);
304 if (best_expr == null)
305 return null;
307 type = best_expr.Type;
308 Expr = best_expr;
309 return this;
313 // E operator ~(E x);
315 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
316 return ResolveEnumOperator (ec, expr);
318 return ResolveUserType (ec, expr);
321 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr)
323 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
324 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
325 if (best_expr == null)
326 return null;
328 Expr = best_expr;
329 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
330 type = expr.Type;
331 return EmptyCast.Create (this, type);
334 public override Expression CreateExpressionTree (ResolveContext ec)
336 return CreateExpressionTree (ec, null);
339 Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr user_op)
341 string method_name;
342 switch (Oper) {
343 case Operator.AddressOf:
344 Error_PointerInsideExpressionTree (ec);
345 return null;
346 case Operator.UnaryNegation:
347 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
348 method_name = "NegateChecked";
349 else
350 method_name = "Negate";
351 break;
352 case Operator.OnesComplement:
353 case Operator.LogicalNot:
354 method_name = "Not";
355 break;
356 case Operator.UnaryPlus:
357 method_name = "UnaryPlus";
358 break;
359 default:
360 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
363 Arguments args = new Arguments (2);
364 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
365 if (user_op != null)
366 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
367 return CreateExpressionFactoryCall (ec, method_name, args);
370 static void CreatePredefinedOperatorsTable ()
372 predefined_operators = new Type [(int) Operator.TOP] [];
375 // 7.6.1 Unary plus operator
377 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
378 TypeManager.int32_type, TypeManager.uint32_type,
379 TypeManager.int64_type, TypeManager.uint64_type,
380 TypeManager.float_type, TypeManager.double_type,
381 TypeManager.decimal_type
385 // 7.6.2 Unary minus operator
387 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
388 TypeManager.int32_type,
389 TypeManager.int64_type,
390 TypeManager.float_type, TypeManager.double_type,
391 TypeManager.decimal_type
395 // 7.6.3 Logical negation operator
397 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
398 TypeManager.bool_type
402 // 7.6.4 Bitwise complement operator
404 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
405 TypeManager.int32_type, TypeManager.uint32_type,
406 TypeManager.int64_type, TypeManager.uint64_type
411 // Unary numeric promotions
413 static Expression DoNumericPromotion (Operator op, Expression expr)
415 Type expr_type = expr.Type;
416 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
417 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
418 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
419 expr_type == TypeManager.char_type)
420 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
422 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
423 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
425 return expr;
428 protected override Expression DoResolve (ResolveContext ec)
430 if (Oper == Operator.AddressOf) {
431 return ResolveAddressOf (ec);
434 Expr = Expr.Resolve (ec);
435 if (Expr == null)
436 return null;
438 if (TypeManager.IsDynamicType (Expr.Type)) {
439 Arguments args = new Arguments (1);
440 args.Add (new Argument (Expr));
441 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
444 if (TypeManager.IsNullableType (Expr.Type))
445 return new Nullable.LiftedUnaryOperator (Oper, Expr).Resolve (ec);
448 // Attempt to use a constant folding operation.
450 Constant cexpr = Expr as Constant;
451 if (cexpr != null) {
452 cexpr = TryReduceConstant (ec, cexpr);
453 if (cexpr != null)
454 return cexpr.Resolve (ec);
457 Expression expr = ResolveOperator (ec, Expr);
458 if (expr == null)
459 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
462 // Reduce unary operator on predefined types
464 if (expr == this && Oper == Operator.UnaryPlus)
465 return Expr;
467 return expr;
470 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
472 return null;
475 public override void Emit (EmitContext ec)
477 EmitOperator (ec, type);
480 protected void EmitOperator (EmitContext ec, Type type)
482 ILGenerator ig = ec.ig;
484 switch (Oper) {
485 case Operator.UnaryPlus:
486 Expr.Emit (ec);
487 break;
489 case Operator.UnaryNegation:
490 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
491 ig.Emit (OpCodes.Ldc_I4_0);
492 if (type == TypeManager.int64_type)
493 ig.Emit (OpCodes.Conv_U8);
494 Expr.Emit (ec);
495 ig.Emit (OpCodes.Sub_Ovf);
496 } else {
497 Expr.Emit (ec);
498 ig.Emit (OpCodes.Neg);
501 break;
503 case Operator.LogicalNot:
504 Expr.Emit (ec);
505 ig.Emit (OpCodes.Ldc_I4_0);
506 ig.Emit (OpCodes.Ceq);
507 break;
509 case Operator.OnesComplement:
510 Expr.Emit (ec);
511 ig.Emit (OpCodes.Not);
512 break;
514 case Operator.AddressOf:
515 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
516 break;
518 default:
519 throw new Exception ("This should not happen: Operator = "
520 + Oper.ToString ());
524 // Same trick as in Binary expression
526 if (enum_conversion != null)
527 enum_conversion.Emit (ec);
530 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
532 if (Oper == Operator.LogicalNot)
533 Expr.EmitBranchable (ec, target, !on_true);
534 else
535 base.EmitBranchable (ec, target, on_true);
538 public override void EmitSideEffect (EmitContext ec)
540 Expr.EmitSideEffect (ec);
543 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Location loc, string oper, Type t)
545 ec.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
546 oper, TypeManager.CSharpName (t));
550 // Converts operator to System.Linq.Expressions.ExpressionType enum name
552 string GetOperatorExpressionTypeName ()
554 switch (Oper) {
555 case Operator.OnesComplement:
556 return "OnesComplement";
557 case Operator.LogicalNot:
558 return "Not";
559 case Operator.UnaryNegation:
560 return "Negate";
561 case Operator.UnaryPlus:
562 return "UnaryPlus";
563 default:
564 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
568 static bool IsFloat (Type t)
570 return t == TypeManager.float_type || t == TypeManager.double_type;
574 // Returns a stringified representation of the Operator
576 public static string OperName (Operator oper)
578 switch (oper) {
579 case Operator.UnaryPlus:
580 return "+";
581 case Operator.UnaryNegation:
582 return "-";
583 case Operator.LogicalNot:
584 return "!";
585 case Operator.OnesComplement:
586 return "~";
587 case Operator.AddressOf:
588 return "&";
591 throw new NotImplementedException (oper.ToString ());
594 public override SLE.Expression MakeExpression (BuilderContext ctx)
596 var expr = Expr.MakeExpression (ctx);
597 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
599 switch (Oper) {
600 case Operator.UnaryNegation:
601 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
602 case Operator.LogicalNot:
603 return SLE.Expression.Not (expr);
604 #if NET_4_0
605 case Operator.OnesComplement:
606 return SLE.Expression.OnesComplement (expr);
607 #endif
608 default:
609 throw new NotImplementedException (Oper.ToString ());
613 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
615 type = storey.MutateType (type);
616 Expr.MutateHoistedGenericType (storey);
619 Expression ResolveAddressOf (ResolveContext ec)
621 if (!ec.IsUnsafe)
622 UnsafeError (ec, loc);
624 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
625 if (Expr == null || Expr.eclass != ExprClass.Variable) {
626 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
627 return null;
630 if (!TypeManager.VerifyUnmanaged (ec.Compiler, Expr.Type, loc)) {
631 return null;
634 IVariableReference vr = Expr as IVariableReference;
635 bool is_fixed;
636 if (vr != null) {
637 VariableInfo vi = vr.VariableInfo;
638 if (vi != null) {
639 if (vi.LocalInfo != null)
640 vi.LocalInfo.Used = true;
643 // A variable is considered definitely assigned if you take its address.
645 vi.SetAssigned (ec);
648 is_fixed = vr.IsFixed;
649 vr.SetHasAddressTaken ();
651 if (vr.IsHoisted) {
652 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
654 } else {
655 IFixedExpression fe = Expr as IFixedExpression;
656 is_fixed = fe != null && fe.IsFixed;
659 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
660 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
663 type = TypeManager.GetPointerType (Expr.Type);
664 eclass = ExprClass.Value;
665 return this;
668 Expression ResolvePrimitivePredefinedType (Expression expr)
670 expr = DoNumericPromotion (Oper, expr);
671 Type expr_type = expr.Type;
672 Type[] predefined = predefined_operators [(int) Oper];
673 foreach (Type t in predefined) {
674 if (t == expr_type)
675 return expr;
677 return null;
681 // Perform user-operator overload resolution
683 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
685 CSharp.Operator.OpType op_type;
686 switch (Oper) {
687 case Operator.LogicalNot:
688 op_type = CSharp.Operator.OpType.LogicalNot; break;
689 case Operator.OnesComplement:
690 op_type = CSharp.Operator.OpType.OnesComplement; break;
691 case Operator.UnaryNegation:
692 op_type = CSharp.Operator.OpType.UnaryNegation; break;
693 case Operator.UnaryPlus:
694 op_type = CSharp.Operator.OpType.UnaryPlus; break;
695 default:
696 throw new InternalErrorException (Oper.ToString ());
699 string op_name = CSharp.Operator.GetMetadataName (op_type);
700 MethodGroupExpr user_op = MemberLookup (ec.Compiler, ec.CurrentType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
701 if (user_op == null)
702 return null;
704 Arguments args = new Arguments (1);
705 args.Add (new Argument (expr));
706 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
708 if (user_op == null)
709 return null;
711 Expr = args [0].Expr;
712 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
716 // Unary user type overload resolution
718 Expression ResolveUserType (ResolveContext ec, Expression expr)
720 Expression best_expr = ResolveUserOperator (ec, expr);
721 if (best_expr != null)
722 return best_expr;
724 Type[] predefined = predefined_operators [(int) Oper];
725 foreach (Type t in predefined) {
726 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false, false);
727 if (oper_expr == null)
728 continue;
731 // decimal type is predefined but has user-operators
733 if (oper_expr.Type == TypeManager.decimal_type)
734 oper_expr = ResolveUserType (ec, oper_expr);
735 else
736 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
738 if (oper_expr == null)
739 continue;
741 if (best_expr == null) {
742 best_expr = oper_expr;
743 continue;
746 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
747 if (result == 0) {
748 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
749 OperName (Oper), TypeManager.CSharpName (expr.Type));
750 break;
753 if (result == 2)
754 best_expr = oper_expr;
757 if (best_expr == null)
758 return null;
761 // HACK: Decimal user-operator is included in standard operators
763 if (best_expr.Type == TypeManager.decimal_type)
764 return best_expr;
766 Expr = best_expr;
767 type = best_expr.Type;
768 return this;
771 protected override void CloneTo (CloneContext clonectx, Expression t)
773 Unary target = (Unary) t;
775 target.Expr = Expr.Clone (clonectx);
780 // Unary operators are turned into Indirection expressions
781 // after semantic analysis (this is so we can take the address
782 // of an indirection).
784 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
785 Expression expr;
786 LocalTemporary temporary;
787 bool prepared;
789 public Indirection (Expression expr, Location l)
791 this.expr = expr;
792 loc = l;
795 public override Expression CreateExpressionTree (ResolveContext ec)
797 Error_PointerInsideExpressionTree (ec);
798 return null;
801 protected override void CloneTo (CloneContext clonectx, Expression t)
803 Indirection target = (Indirection) t;
804 target.expr = expr.Clone (clonectx);
807 public override void Emit (EmitContext ec)
809 if (!prepared)
810 expr.Emit (ec);
812 LoadFromPtr (ec.ig, Type);
815 public void Emit (EmitContext ec, bool leave_copy)
817 Emit (ec);
818 if (leave_copy) {
819 ec.ig.Emit (OpCodes.Dup);
820 temporary = new LocalTemporary (expr.Type);
821 temporary.Store (ec);
825 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
827 prepared = prepare_for_load;
829 expr.Emit (ec);
831 if (prepare_for_load)
832 ec.ig.Emit (OpCodes.Dup);
834 source.Emit (ec);
835 if (leave_copy) {
836 ec.ig.Emit (OpCodes.Dup);
837 temporary = new LocalTemporary (expr.Type);
838 temporary.Store (ec);
841 StoreFromPtr (ec.ig, type);
843 if (temporary != null) {
844 temporary.Emit (ec);
845 temporary.Release (ec);
849 public void AddressOf (EmitContext ec, AddressOp Mode)
851 expr.Emit (ec);
854 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
856 return DoResolve (ec);
859 protected override Expression DoResolve (ResolveContext ec)
861 expr = expr.Resolve (ec);
862 if (expr == null)
863 return null;
865 if (!ec.IsUnsafe)
866 UnsafeError (ec, loc);
868 if (!expr.Type.IsPointer) {
869 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
870 return null;
873 if (expr.Type == TypeManager.void_ptr_type) {
874 ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
875 return null;
878 type = TypeManager.GetElementType (expr.Type);
879 eclass = ExprClass.Variable;
880 return this;
883 public bool IsFixed {
884 get { return true; }
887 public override string ToString ()
889 return "*(" + expr + ")";
893 /// <summary>
894 /// Unary Mutator expressions (pre and post ++ and --)
895 /// </summary>
897 /// <remarks>
898 /// UnaryMutator implements ++ and -- expressions. It derives from
899 /// ExpressionStatement becuase the pre/post increment/decrement
900 /// operators can be used in a statement context.
902 /// FIXME: Idea, we could split this up in two classes, one simpler
903 /// for the common case, and one with the extra fields for more complex
904 /// classes (indexers require temporary access; overloaded require method)
906 /// </remarks>
907 public class UnaryMutator : ExpressionStatement
909 class DynamicPostMutator : Expression, IAssignMethod
911 LocalTemporary temp;
912 Expression expr;
914 public DynamicPostMutator (Expression expr)
916 this.expr = expr;
917 this.type = expr.Type;
918 this.loc = expr.Location;
921 public override Expression CreateExpressionTree (ResolveContext ec)
923 throw new NotImplementedException ("ET");
926 protected override Expression DoResolve (ResolveContext rc)
928 eclass = expr.eclass;
929 return this;
932 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
934 expr.DoResolveLValue (ec, right_side);
935 return DoResolve (ec);
938 public override void Emit (EmitContext ec)
940 temp.Emit (ec);
943 public void Emit (EmitContext ec, bool leave_copy)
945 throw new NotImplementedException ();
949 // Emits target assignment using unmodified source value
951 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
954 // Allocate temporary variable to keep original value before it's modified
956 temp = new LocalTemporary (type);
957 expr.Emit (ec);
958 temp.Store (ec);
960 ((IAssignMethod) expr).EmitAssign (ec, source, false, prepare_for_load);
962 if (leave_copy)
963 Emit (ec);
965 temp.Release (ec);
966 temp = null;
970 [Flags]
971 public enum Mode : byte {
972 IsIncrement = 0,
973 IsDecrement = 1,
974 IsPre = 0,
975 IsPost = 2,
977 PreIncrement = 0,
978 PreDecrement = IsDecrement,
979 PostIncrement = IsPost,
980 PostDecrement = IsPost | IsDecrement
983 Mode mode;
984 bool is_expr, recurse;
986 Expression expr;
988 // Holds the real operation
989 Expression operation;
991 public UnaryMutator (Mode m, Expression e)
993 mode = m;
994 loc = e.Location;
995 expr = e;
998 public override Expression CreateExpressionTree (ResolveContext ec)
1000 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1003 protected override Expression DoResolve (ResolveContext ec)
1005 expr = expr.Resolve (ec);
1007 if (expr == null)
1008 return null;
1010 if (TypeManager.IsDynamicType (expr.Type)) {
1012 // Handle postfix unary operators using local
1013 // temporary variable
1015 if ((mode & Mode.IsPost) != 0)
1016 expr = new DynamicPostMutator (expr);
1018 Arguments args = new Arguments (1);
1019 args.Add (new Argument (expr));
1020 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1023 if (TypeManager.IsNullableType (expr.Type))
1024 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1026 eclass = ExprClass.Value;
1027 type = expr.Type;
1028 return ResolveOperator (ec);
1031 void EmitCode (EmitContext ec, bool is_expr)
1033 recurse = true;
1034 this.is_expr = is_expr;
1035 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1038 public override void Emit (EmitContext ec)
1041 // We use recurse to allow ourselfs to be the source
1042 // of an assignment. This little hack prevents us from
1043 // having to allocate another expression
1045 if (recurse) {
1046 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1048 operation.Emit (ec);
1050 recurse = false;
1051 return;
1054 EmitCode (ec, true);
1057 public override void EmitStatement (EmitContext ec)
1059 EmitCode (ec, false);
1063 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1065 string GetOperatorExpressionTypeName ()
1067 return IsDecrement ? "Decrement" : "Increment";
1070 bool IsDecrement {
1071 get { return (mode & Mode.IsDecrement) != 0; }
1075 // Returns whether an object of type `t' can be incremented
1076 // or decremented with add/sub (ie, basically whether we can
1077 // use pre-post incr-decr operations on it, but it is not a
1078 // System.Decimal, which we require operator overloading to catch)
1080 static bool IsPredefinedOperator (Type t)
1082 return (TypeManager.IsPrimitiveType (t) && t != TypeManager.bool_type) ||
1083 TypeManager.IsEnumType (t) ||
1084 t.IsPointer && t != TypeManager.void_ptr_type;
1087 #if NET_4_0
1088 public override SLE.Expression MakeExpression (BuilderContext ctx)
1090 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1091 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1092 return SLE.Expression.Assign (target, source);
1094 #endif
1096 protected override void CloneTo (CloneContext clonectx, Expression t)
1098 UnaryMutator target = (UnaryMutator) t;
1100 target.expr = expr.Clone (clonectx);
1103 Expression ResolveOperator (ResolveContext ec)
1105 if (expr is RuntimeValueExpression) {
1106 operation = expr;
1107 } else {
1108 // Use itself at the top of the stack
1109 operation = new EmptyExpression (type);
1113 // The operand of the prefix/postfix increment decrement operators
1114 // should be an expression that is classified as a variable,
1115 // a property access or an indexer access
1117 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1118 expr = expr.ResolveLValue (ec, expr);
1119 } else {
1120 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1124 // 1. Check predefined types
1126 if (IsPredefinedOperator (type)) {
1127 // TODO: Move to IntConstant once I get rid of int32_type
1128 var one = new IntConstant (1, loc);
1130 // TODO: Cache this based on type when using EmptyExpression in
1131 // context cache
1132 Binary.Operator op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1133 operation = new Binary (op, operation, one);
1134 operation = operation.Resolve (ec);
1135 if (operation != null && operation.Type != type)
1136 operation = Convert.ExplicitNumericConversion (operation, type);
1138 return this;
1142 // Step 2: Perform Operator Overload location
1144 MethodGroupExpr mg;
1145 string op_name;
1147 if (IsDecrement)
1148 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
1149 else
1150 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
1152 mg = MemberLookup (ec.Compiler, ec.CurrentType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1154 if (mg != null) {
1155 Arguments args = new Arguments (1);
1156 args.Add (new Argument (expr));
1157 mg = mg.OverloadResolve (ec, ref args, false, loc);
1158 if (mg == null)
1159 return null;
1161 args[0].Expr = operation;
1162 operation = new UserOperatorCall (mg, args, null, loc);
1163 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1164 return this;
1167 string name = IsDecrement ?
1168 Operator.GetName (Operator.OpType.Decrement) :
1169 Operator.GetName (Operator.OpType.Increment);
1171 Unary.Error_OperatorCannotBeApplied (ec, loc, name, type);
1172 return null;
1176 /// <summary>
1177 /// Base class for the `Is' and `As' classes.
1178 /// </summary>
1180 /// <remarks>
1181 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1182 /// size.
1183 /// </remarks>
1184 public abstract class Probe : Expression {
1185 public Expression ProbeType;
1186 protected Expression expr;
1187 protected TypeExpr probe_type_expr;
1189 public Probe (Expression expr, Expression probe_type, Location l)
1191 ProbeType = probe_type;
1192 loc = l;
1193 this.expr = expr;
1196 public Expression Expr {
1197 get {
1198 return expr;
1202 protected override Expression DoResolve (ResolveContext ec)
1204 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1205 if (probe_type_expr == null)
1206 return null;
1208 expr = expr.Resolve (ec);
1209 if (expr == null)
1210 return null;
1212 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1213 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1214 OperatorName);
1217 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1218 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1219 OperatorName);
1220 return null;
1223 if (expr.Type == InternalType.AnonymousMethod) {
1224 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1225 OperatorName);
1226 return null;
1229 return this;
1232 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1234 expr.MutateHoistedGenericType (storey);
1235 probe_type_expr.MutateHoistedGenericType (storey);
1238 protected abstract string OperatorName { get; }
1240 protected override void CloneTo (CloneContext clonectx, Expression t)
1242 Probe target = (Probe) t;
1244 target.expr = expr.Clone (clonectx);
1245 target.ProbeType = ProbeType.Clone (clonectx);
1250 /// <summary>
1251 /// Implementation of the `is' operator.
1252 /// </summary>
1253 public class Is : Probe {
1254 Nullable.Unwrap expr_unwrap;
1256 public Is (Expression expr, Expression probe_type, Location l)
1257 : base (expr, probe_type, l)
1261 public override Expression CreateExpressionTree (ResolveContext ec)
1263 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1264 expr.CreateExpressionTree (ec),
1265 new TypeOf (probe_type_expr, loc));
1267 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1270 public override void Emit (EmitContext ec)
1272 ILGenerator ig = ec.ig;
1273 if (expr_unwrap != null) {
1274 expr_unwrap.EmitCheck (ec);
1275 return;
1278 expr.Emit (ec);
1279 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1280 ig.Emit (OpCodes.Ldnull);
1281 ig.Emit (OpCodes.Cgt_Un);
1284 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1286 ILGenerator ig = ec.ig;
1287 if (expr_unwrap != null) {
1288 expr_unwrap.EmitCheck (ec);
1289 } else {
1290 expr.Emit (ec);
1291 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1293 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1296 Expression CreateConstantResult (ResolveContext ec, bool result)
1298 if (result)
1299 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1300 TypeManager.CSharpName (probe_type_expr.Type));
1301 else
1302 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1303 TypeManager.CSharpName (probe_type_expr.Type));
1305 return ReducedExpression.Create (new BoolConstant (result, loc).Resolve (ec), this);
1308 protected override Expression DoResolve (ResolveContext ec)
1310 if (base.DoResolve (ec) == null)
1311 return null;
1313 Type d = expr.Type;
1314 bool d_is_nullable = false;
1317 // If E is a method group or the null literal, or if the type of E is a reference
1318 // type or a nullable type and the value of E is null, the result is false
1320 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1321 return CreateConstantResult (ec, false);
1323 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1324 d = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (d) [0]);
1325 d_is_nullable = true;
1328 type = TypeManager.bool_type;
1329 eclass = ExprClass.Value;
1330 Type t = probe_type_expr.Type;
1331 bool t_is_nullable = false;
1332 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1333 t = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (t) [0]);
1334 t_is_nullable = true;
1337 if (TypeManager.IsStruct (t)) {
1338 if (d == t) {
1340 // D and T are the same value types but D can be null
1342 if (d_is_nullable && !t_is_nullable) {
1343 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1344 return this;
1348 // The result is true if D and T are the same value types
1350 return CreateConstantResult (ec, true);
1353 if (TypeManager.IsGenericParameter (d))
1354 return ResolveGenericParameter (ec, t, d);
1357 // An unboxing conversion exists
1359 if (Convert.ExplicitReferenceConversionExists (d, t))
1360 return this;
1361 } else {
1362 if (TypeManager.IsGenericParameter (t))
1363 return ResolveGenericParameter (ec, d, t);
1365 if (TypeManager.IsStruct (d)) {
1366 bool temp;
1367 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1368 return CreateConstantResult (ec, true);
1369 } else {
1370 if (TypeManager.IsGenericParameter (d))
1371 return ResolveGenericParameter (ec, t, d);
1373 if (TypeManager.ContainsGenericParameters (d))
1374 return this;
1376 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1377 Convert.ExplicitReferenceConversionExists (d, t)) {
1378 return this;
1383 return CreateConstantResult (ec, false);
1386 Expression ResolveGenericParameter (ResolveContext ec, Type d, Type t)
1388 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1389 if (constraints != null) {
1390 if (constraints.IsReferenceType && TypeManager.IsStruct (d))
1391 return CreateConstantResult (ec, false);
1394 if (TypeManager.IsGenericParameter (expr.Type)) {
1395 if (constraints != null && constraints.IsValueType && expr.Type == t)
1396 return CreateConstantResult (ec, true);
1398 expr = new BoxedCast (expr, d);
1401 return this;
1404 protected override string OperatorName {
1405 get { return "is"; }
1409 /// <summary>
1410 /// Implementation of the `as' operator.
1411 /// </summary>
1412 public class As : Probe {
1413 bool do_isinst;
1414 Expression resolved_type;
1416 public As (Expression expr, Expression probe_type, Location l)
1417 : base (expr, probe_type, l)
1421 public override Expression CreateExpressionTree (ResolveContext ec)
1423 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1424 expr.CreateExpressionTree (ec),
1425 new TypeOf (probe_type_expr, loc));
1427 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1430 public override void Emit (EmitContext ec)
1432 ILGenerator ig = ec.ig;
1434 expr.Emit (ec);
1436 if (do_isinst)
1437 ig.Emit (OpCodes.Isinst, type);
1439 if (TypeManager.IsGenericParameter (type) || TypeManager.IsNullableType (type))
1440 ig.Emit (OpCodes.Unbox_Any, type);
1443 protected override Expression DoResolve (ResolveContext ec)
1445 if (resolved_type == null) {
1446 resolved_type = base.DoResolve (ec);
1448 if (resolved_type == null)
1449 return null;
1452 type = probe_type_expr.Type;
1453 eclass = ExprClass.Value;
1454 Type etype = expr.Type;
1456 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1457 if (TypeManager.IsGenericParameter (type)) {
1458 ec.Report.Error (413, loc,
1459 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1460 probe_type_expr.GetSignatureForError ());
1461 } else {
1462 ec.Report.Error (77, loc,
1463 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1464 TypeManager.CSharpName (type));
1466 return null;
1469 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1470 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1473 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1474 if (e != null){
1475 expr = e;
1476 do_isinst = false;
1477 return this;
1480 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1481 if (TypeManager.IsGenericParameter (etype))
1482 expr = new BoxedCast (expr, etype);
1484 do_isinst = true;
1485 return this;
1488 if (TypeManager.ContainsGenericParameters (etype) ||
1489 TypeManager.ContainsGenericParameters (type)) {
1490 expr = new BoxedCast (expr, etype);
1491 do_isinst = true;
1492 return this;
1495 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1496 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1498 return null;
1501 protected override string OperatorName {
1502 get { return "as"; }
1505 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1507 type = storey.MutateType (type);
1508 base.MutateHoistedGenericType (storey);
1511 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1513 return expr.GetAttributableValue (ec, value_type, out value);
1517 /// <summary>
1518 /// This represents a typecast in the source language.
1520 /// FIXME: Cast expressions have an unusual set of parsing
1521 /// rules, we need to figure those out.
1522 /// </summary>
1523 public class Cast : ShimExpression {
1524 Expression target_type;
1526 public Cast (Expression cast_type, Expression expr)
1527 : this (cast_type, expr, cast_type.Location)
1531 public Cast (Expression cast_type, Expression expr, Location loc)
1532 : base (expr)
1534 this.target_type = cast_type;
1535 this.loc = loc;
1538 public Expression TargetType {
1539 get { return target_type; }
1542 protected override Expression DoResolve (ResolveContext ec)
1544 expr = expr.Resolve (ec);
1545 if (expr == null)
1546 return null;
1548 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1549 if (target == null)
1550 return null;
1552 type = target.Type;
1554 if (type.IsAbstract && type.IsSealed) {
1555 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1556 return null;
1559 eclass = ExprClass.Value;
1561 Constant c = expr as Constant;
1562 if (c != null) {
1563 c = c.TryReduce (ec, type, loc);
1564 if (c != null)
1565 return c;
1568 if (type.IsPointer && !ec.IsUnsafe) {
1569 UnsafeError (ec, loc);
1570 } else if (TypeManager.IsDynamicType (expr.Type)) {
1571 Arguments arg = new Arguments (1);
1572 arg.Add (new Argument (expr));
1573 return new DynamicConversion (type, CSharpBinderFlags.ConvertExplicit, arg, loc).Resolve (ec);
1576 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1577 return expr;
1580 protected override void CloneTo (CloneContext clonectx, Expression t)
1582 Cast target = (Cast) t;
1584 target.target_type = target_type.Clone (clonectx);
1585 target.expr = expr.Clone (clonectx);
1589 public class ImplicitCast : ShimExpression
1591 bool arrayAccess;
1593 public ImplicitCast (Expression expr, Type target, bool arrayAccess)
1594 : base (expr)
1596 this.loc = expr.Location;
1597 this.type = target;
1598 this.arrayAccess = arrayAccess;
1601 protected override Expression DoResolve (ResolveContext ec)
1603 expr = expr.Resolve (ec);
1604 if (expr == null)
1605 return null;
1607 if (arrayAccess)
1608 expr = ConvertExpressionToArrayIndex (ec, expr);
1609 else
1610 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1612 return expr;
1617 // C# 2.0 Default value expression
1619 public class DefaultValueExpression : Expression
1621 Expression expr;
1623 public DefaultValueExpression (Expression expr, Location loc)
1625 this.expr = expr;
1626 this.loc = loc;
1629 public override Expression CreateExpressionTree (ResolveContext ec)
1631 Arguments args = new Arguments (2);
1632 args.Add (new Argument (this));
1633 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1634 return CreateExpressionFactoryCall (ec, "Constant", args);
1637 protected override Expression DoResolve (ResolveContext ec)
1639 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1640 if (texpr == null)
1641 return null;
1643 type = texpr.Type;
1645 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1646 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1649 if (type.IsPointer)
1650 return new NullLiteral (Location).ConvertImplicitly (ec, type);
1652 if (TypeManager.IsReferenceType (type))
1653 return new NullConstant (type, loc);
1655 Constant c = New.Constantify (type);
1656 if (c != null)
1657 return c.Resolve (ec);
1659 eclass = ExprClass.Variable;
1660 return this;
1663 public override void Emit (EmitContext ec)
1665 LocalTemporary temp_storage = new LocalTemporary(type);
1667 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1668 ec.ig.Emit(OpCodes.Initobj, type);
1669 temp_storage.Emit(ec);
1672 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1674 type = storey.MutateType (type);
1677 protected override void CloneTo (CloneContext clonectx, Expression t)
1679 DefaultValueExpression target = (DefaultValueExpression) t;
1681 target.expr = expr.Clone (clonectx);
1685 /// <summary>
1686 /// Binary operators
1687 /// </summary>
1688 public class Binary : Expression, IDynamicBinder
1691 protected class PredefinedOperator {
1692 protected readonly Type left;
1693 protected readonly Type right;
1694 public readonly Operator OperatorsMask;
1695 public Type ReturnType;
1697 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1698 : this (ltype, rtype, op_mask, ltype)
1702 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1703 : this (type, type, op_mask, return_type)
1707 public PredefinedOperator (Type type, Operator op_mask)
1708 : this (type, type, op_mask, type)
1712 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1714 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1715 throw new InternalErrorException ("Only masked values can be used");
1717 this.left = ltype;
1718 this.right = rtype;
1719 this.OperatorsMask = op_mask;
1720 this.ReturnType = return_type;
1723 public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1725 b.type = ReturnType;
1727 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1728 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1731 // A user operators does not support multiple user conversions, but decimal type
1732 // is considered to be predefined type therefore we apply predefined operators rules
1733 // and then look for decimal user-operator implementation
1735 if (left == TypeManager.decimal_type)
1736 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1738 var c = b.right as Constant;
1739 if (c != null) {
1740 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr || b.oper == Operator.Subtraction))
1741 return ReducedExpression.Create (b.left, b).Resolve (ec);
1742 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
1743 return ReducedExpression.Create (b.left, b).Resolve (ec);
1744 return b;
1747 c = b.left as Constant;
1748 if (c != null) {
1749 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr))
1750 return ReducedExpression.Create (b.right, b).Resolve (ec);
1751 if (b.oper == Operator.Multiply && c.IsOneInteger)
1752 return ReducedExpression.Create (b.right, b).Resolve (ec);
1753 return b;
1756 return b;
1759 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1762 // We are dealing with primitive types only
1764 return left == ltype && ltype == rtype;
1767 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1769 if (TypeManager.IsEqual (left, lexpr.Type) &&
1770 TypeManager.IsEqual (right, rexpr.Type))
1771 return true;
1773 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1774 Convert.ImplicitConversionExists (ec, rexpr, right);
1777 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1779 int result = 0;
1780 if (left != null && best_operator.left != null) {
1781 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1785 // When second arguments are same as the first one, the result is same
1787 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1788 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1791 if (result == 0 || result > 2)
1792 return null;
1794 return result == 1 ? best_operator : this;
1798 class PredefinedStringOperator : PredefinedOperator {
1799 public PredefinedStringOperator (Type type, Operator op_mask)
1800 : base (type, op_mask, type)
1802 ReturnType = TypeManager.string_type;
1805 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1806 : base (ltype, rtype, op_mask)
1808 ReturnType = TypeManager.string_type;
1811 public override Expression ConvertResult (ResolveContext ec, Binary b)
1814 // Use original expression for nullable arguments
1816 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1817 if (unwrap != null)
1818 b.left = unwrap.Original;
1820 unwrap = b.right as Nullable.Unwrap;
1821 if (unwrap != null)
1822 b.right = unwrap.Original;
1824 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1825 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1828 // Start a new concat expression using converted expression
1830 return StringConcat.Create (ec, b.left, b.right, b.loc);
1834 class PredefinedShiftOperator : PredefinedOperator {
1835 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1836 base (ltype, TypeManager.int32_type, op_mask)
1840 public override Expression ConvertResult (ResolveContext ec, Binary b)
1842 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1844 Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, TypeManager.int32_type, b.right.Location);
1846 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1849 // b = b.left >> b.right & (0x1f|0x3f)
1851 b.right = new Binary (Operator.BitwiseAnd,
1852 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1855 // Expression tree representation does not use & mask
1857 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1858 b.type = ReturnType;
1861 // Optimize shift by 0
1863 var c = b.right as Constant;
1864 if (c != null && c.IsDefaultValue)
1865 return ReducedExpression.Create (b.left, b).Resolve (ec);
1867 return b;
1871 class PredefinedPointerOperator : PredefinedOperator {
1872 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1873 : base (ltype, rtype, op_mask)
1877 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1878 : base (ltype, rtype, op_mask, retType)
1882 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1883 : base (type, op_mask, return_type)
1887 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1889 if (left == null) {
1890 if (!lexpr.Type.IsPointer)
1891 return false;
1892 } else {
1893 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1894 return false;
1897 if (right == null) {
1898 if (!rexpr.Type.IsPointer)
1899 return false;
1900 } else {
1901 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1902 return false;
1905 return true;
1908 public override Expression ConvertResult (ResolveContext ec, Binary b)
1910 if (left != null) {
1911 b.left = EmptyCast.Create (b.left, left);
1912 } else if (right != null) {
1913 b.right = EmptyCast.Create (b.right, right);
1916 Type r_type = ReturnType;
1917 Expression left_arg, right_arg;
1918 if (r_type == null) {
1919 if (left == null) {
1920 left_arg = b.left;
1921 right_arg = b.right;
1922 r_type = b.left.Type;
1923 } else {
1924 left_arg = b.right;
1925 right_arg = b.left;
1926 r_type = b.right.Type;
1928 } else {
1929 left_arg = b.left;
1930 right_arg = b.right;
1933 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1937 [Flags]
1938 public enum Operator {
1939 Multiply = 0 | ArithmeticMask,
1940 Division = 1 | ArithmeticMask,
1941 Modulus = 2 | ArithmeticMask,
1942 Addition = 3 | ArithmeticMask | AdditionMask,
1943 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1945 LeftShift = 5 | ShiftMask,
1946 RightShift = 6 | ShiftMask,
1948 LessThan = 7 | ComparisonMask | RelationalMask,
1949 GreaterThan = 8 | ComparisonMask | RelationalMask,
1950 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1951 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1952 Equality = 11 | ComparisonMask | EqualityMask,
1953 Inequality = 12 | ComparisonMask | EqualityMask,
1955 BitwiseAnd = 13 | BitwiseMask,
1956 ExclusiveOr = 14 | BitwiseMask,
1957 BitwiseOr = 15 | BitwiseMask,
1959 LogicalAnd = 16 | LogicalMask,
1960 LogicalOr = 17 | LogicalMask,
1963 // Operator masks
1965 ValuesOnlyMask = ArithmeticMask - 1,
1966 ArithmeticMask = 1 << 5,
1967 ShiftMask = 1 << 6,
1968 ComparisonMask = 1 << 7,
1969 EqualityMask = 1 << 8,
1970 BitwiseMask = 1 << 9,
1971 LogicalMask = 1 << 10,
1972 AdditionMask = 1 << 11,
1973 SubtractionMask = 1 << 12,
1974 RelationalMask = 1 << 13
1977 readonly Operator oper;
1978 protected Expression left, right;
1979 readonly bool is_compound;
1980 Expression enum_conversion;
1982 static PredefinedOperator [] standard_operators;
1983 static PredefinedOperator [] pointer_operators;
1985 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1986 : this (oper, left, right)
1988 this.is_compound = isCompound;
1991 public Binary (Operator oper, Expression left, Expression right)
1993 this.oper = oper;
1994 this.left = left;
1995 this.right = right;
1996 this.loc = left.Location;
1999 public Operator Oper {
2000 get {
2001 return oper;
2005 /// <summary>
2006 /// Returns a stringified representation of the Operator
2007 /// </summary>
2008 string OperName (Operator oper)
2010 string s;
2011 switch (oper){
2012 case Operator.Multiply:
2013 s = "*";
2014 break;
2015 case Operator.Division:
2016 s = "/";
2017 break;
2018 case Operator.Modulus:
2019 s = "%";
2020 break;
2021 case Operator.Addition:
2022 s = "+";
2023 break;
2024 case Operator.Subtraction:
2025 s = "-";
2026 break;
2027 case Operator.LeftShift:
2028 s = "<<";
2029 break;
2030 case Operator.RightShift:
2031 s = ">>";
2032 break;
2033 case Operator.LessThan:
2034 s = "<";
2035 break;
2036 case Operator.GreaterThan:
2037 s = ">";
2038 break;
2039 case Operator.LessThanOrEqual:
2040 s = "<=";
2041 break;
2042 case Operator.GreaterThanOrEqual:
2043 s = ">=";
2044 break;
2045 case Operator.Equality:
2046 s = "==";
2047 break;
2048 case Operator.Inequality:
2049 s = "!=";
2050 break;
2051 case Operator.BitwiseAnd:
2052 s = "&";
2053 break;
2054 case Operator.BitwiseOr:
2055 s = "|";
2056 break;
2057 case Operator.ExclusiveOr:
2058 s = "^";
2059 break;
2060 case Operator.LogicalOr:
2061 s = "||";
2062 break;
2063 case Operator.LogicalAnd:
2064 s = "&&";
2065 break;
2066 default:
2067 s = oper.ToString ();
2068 break;
2071 if (is_compound)
2072 return s + "=";
2074 return s;
2077 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2079 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2082 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2084 string l, r;
2085 l = TypeManager.CSharpName (left.Type);
2086 r = TypeManager.CSharpName (right.Type);
2088 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2089 oper, l, r);
2092 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2094 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2098 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2100 string GetOperatorExpressionTypeName ()
2102 switch (oper) {
2103 case Operator.Addition:
2104 return is_compound ? "AddAssign" : "Add";
2105 case Operator.BitwiseAnd:
2106 return is_compound ? "AndAssign" : "And";
2107 case Operator.BitwiseOr:
2108 return is_compound ? "OrAssign" : "Or";
2109 case Operator.Division:
2110 return is_compound ? "DivideAssign" : "Divide";
2111 case Operator.ExclusiveOr:
2112 return is_compound ? "ExclusiveOrAssign" : "ExclusiveOr";
2113 case Operator.Equality:
2114 return "Equal";
2115 case Operator.GreaterThan:
2116 return "GreaterThan";
2117 case Operator.GreaterThanOrEqual:
2118 return "GreaterThanOrEqual";
2119 case Operator.Inequality:
2120 return "NotEqual";
2121 case Operator.LeftShift:
2122 return is_compound ? "LeftShiftAssign" : "LeftShift";
2123 case Operator.LessThan:
2124 return "LessThan";
2125 case Operator.LessThanOrEqual:
2126 return "LessThanOrEqual";
2127 case Operator.LogicalAnd:
2128 return "And";
2129 case Operator.LogicalOr:
2130 return "Or";
2131 case Operator.Modulus:
2132 return is_compound ? "ModuloAssign" : "Modulo";
2133 case Operator.Multiply:
2134 return is_compound ? "MultiplyAssign" : "Multiply";
2135 case Operator.RightShift:
2136 return is_compound ? "RightShiftAssign" : "RightShift";
2137 case Operator.Subtraction:
2138 return is_compound ? "SubtractAssign" : "Subtract";
2139 default:
2140 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2144 static string GetOperatorMetadataName (Operator op)
2146 CSharp.Operator.OpType op_type;
2147 switch (op) {
2148 case Operator.Addition:
2149 op_type = CSharp.Operator.OpType.Addition; break;
2150 case Operator.BitwiseAnd:
2151 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2152 case Operator.BitwiseOr:
2153 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2154 case Operator.Division:
2155 op_type = CSharp.Operator.OpType.Division; break;
2156 case Operator.Equality:
2157 op_type = CSharp.Operator.OpType.Equality; break;
2158 case Operator.ExclusiveOr:
2159 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2160 case Operator.GreaterThan:
2161 op_type = CSharp.Operator.OpType.GreaterThan; break;
2162 case Operator.GreaterThanOrEqual:
2163 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2164 case Operator.Inequality:
2165 op_type = CSharp.Operator.OpType.Inequality; break;
2166 case Operator.LeftShift:
2167 op_type = CSharp.Operator.OpType.LeftShift; break;
2168 case Operator.LessThan:
2169 op_type = CSharp.Operator.OpType.LessThan; break;
2170 case Operator.LessThanOrEqual:
2171 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2172 case Operator.Modulus:
2173 op_type = CSharp.Operator.OpType.Modulus; break;
2174 case Operator.Multiply:
2175 op_type = CSharp.Operator.OpType.Multiply; break;
2176 case Operator.RightShift:
2177 op_type = CSharp.Operator.OpType.RightShift; break;
2178 case Operator.Subtraction:
2179 op_type = CSharp.Operator.OpType.Subtraction; break;
2180 default:
2181 throw new InternalErrorException (op.ToString ());
2184 return CSharp.Operator.GetMetadataName (op_type);
2187 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2189 OpCode opcode;
2190 ILGenerator ig = ec.ig;
2192 switch (oper){
2193 case Operator.Multiply:
2194 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2195 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2196 opcode = OpCodes.Mul_Ovf;
2197 else if (!IsFloat (l))
2198 opcode = OpCodes.Mul_Ovf_Un;
2199 else
2200 opcode = OpCodes.Mul;
2201 } else
2202 opcode = OpCodes.Mul;
2204 break;
2206 case Operator.Division:
2207 if (IsUnsigned (l))
2208 opcode = OpCodes.Div_Un;
2209 else
2210 opcode = OpCodes.Div;
2211 break;
2213 case Operator.Modulus:
2214 if (IsUnsigned (l))
2215 opcode = OpCodes.Rem_Un;
2216 else
2217 opcode = OpCodes.Rem;
2218 break;
2220 case Operator.Addition:
2221 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2222 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2223 opcode = OpCodes.Add_Ovf;
2224 else if (!IsFloat (l))
2225 opcode = OpCodes.Add_Ovf_Un;
2226 else
2227 opcode = OpCodes.Add;
2228 } else
2229 opcode = OpCodes.Add;
2230 break;
2232 case Operator.Subtraction:
2233 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2234 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2235 opcode = OpCodes.Sub_Ovf;
2236 else if (!IsFloat (l))
2237 opcode = OpCodes.Sub_Ovf_Un;
2238 else
2239 opcode = OpCodes.Sub;
2240 } else
2241 opcode = OpCodes.Sub;
2242 break;
2244 case Operator.RightShift:
2245 if (IsUnsigned (l))
2246 opcode = OpCodes.Shr_Un;
2247 else
2248 opcode = OpCodes.Shr;
2249 break;
2251 case Operator.LeftShift:
2252 opcode = OpCodes.Shl;
2253 break;
2255 case Operator.Equality:
2256 opcode = OpCodes.Ceq;
2257 break;
2259 case Operator.Inequality:
2260 ig.Emit (OpCodes.Ceq);
2261 ig.Emit (OpCodes.Ldc_I4_0);
2263 opcode = OpCodes.Ceq;
2264 break;
2266 case Operator.LessThan:
2267 if (IsUnsigned (l))
2268 opcode = OpCodes.Clt_Un;
2269 else
2270 opcode = OpCodes.Clt;
2271 break;
2273 case Operator.GreaterThan:
2274 if (IsUnsigned (l))
2275 opcode = OpCodes.Cgt_Un;
2276 else
2277 opcode = OpCodes.Cgt;
2278 break;
2280 case Operator.LessThanOrEqual:
2281 if (IsUnsigned (l) || IsFloat (l))
2282 ig.Emit (OpCodes.Cgt_Un);
2283 else
2284 ig.Emit (OpCodes.Cgt);
2285 ig.Emit (OpCodes.Ldc_I4_0);
2287 opcode = OpCodes.Ceq;
2288 break;
2290 case Operator.GreaterThanOrEqual:
2291 if (IsUnsigned (l) || IsFloat (l))
2292 ig.Emit (OpCodes.Clt_Un);
2293 else
2294 ig.Emit (OpCodes.Clt);
2296 ig.Emit (OpCodes.Ldc_I4_0);
2298 opcode = OpCodes.Ceq;
2299 break;
2301 case Operator.BitwiseOr:
2302 opcode = OpCodes.Or;
2303 break;
2305 case Operator.BitwiseAnd:
2306 opcode = OpCodes.And;
2307 break;
2309 case Operator.ExclusiveOr:
2310 opcode = OpCodes.Xor;
2311 break;
2313 default:
2314 throw new InternalErrorException (oper.ToString ());
2317 ig.Emit (opcode);
2320 static bool IsUnsigned (Type t)
2322 if (t.IsPointer)
2323 return true;
2325 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2326 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2329 static bool IsFloat (Type t)
2331 return t == TypeManager.float_type || t == TypeManager.double_type;
2334 Expression ResolveOperator (ResolveContext ec)
2336 Type l = left.Type;
2337 Type r = right.Type;
2338 Expression expr;
2339 bool primitives_only = false;
2341 if (standard_operators == null)
2342 CreateStandardOperatorsTable ();
2345 // Handles predefined primitive types
2347 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2348 if ((oper & Operator.ShiftMask) == 0) {
2349 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2350 return null;
2352 primitives_only = true;
2354 } else {
2355 // Pointers
2356 if (l.IsPointer || r.IsPointer)
2357 return ResolveOperatorPointer (ec, l, r);
2359 // Enums
2360 bool lenum = TypeManager.IsEnumType (l);
2361 bool renum = TypeManager.IsEnumType (r);
2362 if (lenum || renum) {
2363 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2365 // TODO: Can this be ambiguous
2366 if (expr != null)
2367 return expr;
2370 // Delegates
2371 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2372 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2374 expr = ResolveOperatorDelegate (ec, l, r);
2376 // TODO: Can this be ambiguous
2377 if (expr != null)
2378 return expr;
2381 // User operators
2382 expr = ResolveUserOperator (ec, l, r);
2383 if (expr != null)
2384 return expr;
2386 // Predefined reference types equality
2387 if ((oper & Operator.EqualityMask) != 0) {
2388 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2389 if (expr != null)
2390 return expr;
2394 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2397 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2398 // if 'left' is not an enumeration constant, create one from the type of 'right'
2399 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2401 switch (oper) {
2402 case Operator.BitwiseOr:
2403 case Operator.BitwiseAnd:
2404 case Operator.ExclusiveOr:
2405 case Operator.Equality:
2406 case Operator.Inequality:
2407 case Operator.LessThan:
2408 case Operator.LessThanOrEqual:
2409 case Operator.GreaterThan:
2410 case Operator.GreaterThanOrEqual:
2411 if (TypeManager.IsEnumType (left.Type))
2412 return left;
2414 if (left.IsZeroInteger)
2415 return left.TryReduce (ec, right.Type, loc);
2417 break;
2419 case Operator.Addition:
2420 case Operator.Subtraction:
2421 return left;
2423 case Operator.Multiply:
2424 case Operator.Division:
2425 case Operator.Modulus:
2426 case Operator.LeftShift:
2427 case Operator.RightShift:
2428 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2429 break;
2430 return left;
2432 Error_OperatorCannotBeApplied (ec, this.left, this.right);
2433 return null;
2437 // The `|' operator used on types which were extended is dangerous
2439 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2441 OpcodeCast lcast = left as OpcodeCast;
2442 if (lcast != null) {
2443 if (IsUnsigned (lcast.UnderlyingType))
2444 lcast = null;
2447 OpcodeCast rcast = right as OpcodeCast;
2448 if (rcast != null) {
2449 if (IsUnsigned (rcast.UnderlyingType))
2450 rcast = null;
2453 if (lcast == null && rcast == null)
2454 return;
2456 // FIXME: consider constants
2458 ec.Report.Warning (675, 3, loc,
2459 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2460 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2463 static void CreatePointerOperatorsTable ()
2465 var temp = new List<PredefinedPointerOperator> ();
2468 // Pointer arithmetic:
2470 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2471 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2472 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2473 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2475 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2476 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2477 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2478 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2481 // T* operator + (int y, T* x);
2482 // T* operator + (uint y, T *x);
2483 // T* operator + (long y, T *x);
2484 // T* operator + (ulong y, T *x);
2486 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2487 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2488 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2489 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2492 // long operator - (T* x, T *y)
2494 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2496 pointer_operators = temp.ToArray ();
2499 static void CreateStandardOperatorsTable ()
2501 var temp = new List<PredefinedOperator> ();
2502 Type bool_type = TypeManager.bool_type;
2504 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2505 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2506 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2507 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2508 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2509 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2510 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2512 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2513 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2514 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2515 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2516 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2517 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2518 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2520 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2522 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2523 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2524 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2526 temp.Add (new PredefinedOperator (bool_type,
2527 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2529 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2530 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2531 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2532 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2534 standard_operators = temp.ToArray ();
2538 // Rules used during binary numeric promotion
2540 static bool DoNumericPromotion (ResolveContext rc, ref Expression prim_expr, ref Expression second_expr, Type type)
2542 Expression temp;
2543 Type etype;
2545 Constant c = prim_expr as Constant;
2546 if (c != null) {
2547 temp = c.ConvertImplicitly (rc, type);
2548 if (temp != null) {
2549 prim_expr = temp;
2550 return true;
2554 if (type == TypeManager.uint32_type) {
2555 etype = prim_expr.Type;
2556 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2557 type = TypeManager.int64_type;
2559 if (type != second_expr.Type) {
2560 c = second_expr as Constant;
2561 if (c != null)
2562 temp = c.ConvertImplicitly (rc, type);
2563 else
2564 temp = Convert.ImplicitNumericConversion (second_expr, type);
2565 if (temp == null)
2566 return false;
2567 second_expr = temp;
2570 } else if (type == TypeManager.uint64_type) {
2572 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2574 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2575 type == TypeManager.short_type || type == TypeManager.sbyte_type)
2576 return false;
2579 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2580 if (temp == null)
2581 return false;
2583 prim_expr = temp;
2584 return true;
2588 // 7.2.6.2 Binary numeric promotions
2590 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2592 Type ltype = left.Type;
2593 Type rtype = right.Type;
2594 Expression temp;
2596 foreach (Type t in ConstantFold.binary_promotions) {
2597 if (t == ltype)
2598 return t == rtype || DoNumericPromotion (ec, ref right, ref left, t);
2600 if (t == rtype)
2601 return t == ltype || DoNumericPromotion (ec, ref left, ref right, t);
2604 Type int32 = TypeManager.int32_type;
2605 if (ltype != int32) {
2606 Constant c = left as Constant;
2607 if (c != null)
2608 temp = c.ConvertImplicitly (ec, int32);
2609 else
2610 temp = Convert.ImplicitNumericConversion (left, int32);
2612 if (temp == null)
2613 return false;
2614 left = temp;
2617 if (rtype != int32) {
2618 Constant c = right as Constant;
2619 if (c != null)
2620 temp = c.ConvertImplicitly (ec, int32);
2621 else
2622 temp = Convert.ImplicitNumericConversion (right, int32);
2624 if (temp == null)
2625 return false;
2626 right = temp;
2629 return true;
2632 protected override Expression DoResolve (ResolveContext ec)
2634 if (left == null)
2635 return null;
2637 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2638 left = ((ParenthesizedExpression) left).Expr;
2639 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2640 if (left == null)
2641 return null;
2643 if (left.eclass == ExprClass.Type) {
2644 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2645 return null;
2647 } else
2648 left = left.Resolve (ec);
2650 if (left == null)
2651 return null;
2653 Constant lc = left as Constant;
2655 if (lc != null && lc.Type == TypeManager.bool_type &&
2656 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2657 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2659 // FIXME: resolve right expression as unreachable
2660 // right.Resolve (ec);
2662 ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2663 return left;
2666 right = right.Resolve (ec);
2667 if (right == null)
2668 return null;
2670 eclass = ExprClass.Value;
2671 Constant rc = right as Constant;
2673 // The conversion rules are ignored in enum context but why
2674 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2675 lc = EnumLiftUp (ec, lc, rc, loc);
2676 if (lc != null)
2677 rc = EnumLiftUp (ec, rc, lc, loc);
2680 if (rc != null && lc != null) {
2681 int prev_e = ec.Report.Errors;
2682 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
2683 if (e != null)
2684 e = e.Resolve (ec);
2686 if (e != null || ec.Report.Errors != prev_e)
2687 return e;
2690 // Comparison warnings
2691 if ((oper & Operator.ComparisonMask) != 0) {
2692 if (left.Equals (right)) {
2693 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2695 CheckUselessComparison (ec, lc, right.Type);
2696 CheckUselessComparison (ec, rc, left.Type);
2699 if (TypeManager.IsDynamicType (left.Type) || TypeManager.IsDynamicType (right.Type)) {
2700 Arguments args = new Arguments (2);
2701 args.Add (new Argument (left));
2702 args.Add (new Argument (right));
2703 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
2706 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2707 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2708 (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
2709 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2710 (TypeManager.IsValueType (right.Type) && left is NullLiteral)))
2711 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2713 return DoResolveCore (ec, left, right);
2716 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
2718 Expression expr = ResolveOperator (ec);
2719 if (expr == null)
2720 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
2722 if (left == null || right == null)
2723 throw new InternalErrorException ("Invalid conversion");
2725 if (oper == Operator.BitwiseOr)
2726 CheckBitwiseOrOnSignExtended (ec);
2728 return expr;
2731 public override SLE.Expression MakeExpression (BuilderContext ctx)
2733 var le = left.MakeExpression (ctx);
2734 var re = right.MakeExpression (ctx);
2735 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
2737 switch (oper) {
2738 case Operator.Addition:
2739 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
2740 case Operator.BitwiseAnd:
2741 return SLE.Expression.And (le, re);
2742 case Operator.BitwiseOr:
2743 return SLE.Expression.Or (le, re);
2744 case Operator.Division:
2745 return SLE.Expression.Divide (le, re);
2746 case Operator.Equality:
2747 return SLE.Expression.Equal (le, re);
2748 case Operator.ExclusiveOr:
2749 return SLE.Expression.ExclusiveOr (le, re);
2750 case Operator.GreaterThan:
2751 return SLE.Expression.GreaterThan (le, re);
2752 case Operator.GreaterThanOrEqual:
2753 return SLE.Expression.GreaterThanOrEqual (le, re);
2754 case Operator.Inequality:
2755 return SLE.Expression.NotEqual (le, re);
2756 case Operator.LeftShift:
2757 return SLE.Expression.LeftShift (le, re);
2758 case Operator.LessThan:
2759 return SLE.Expression.LessThan (le, re);
2760 case Operator.LessThanOrEqual:
2761 return SLE.Expression.LessThanOrEqual (le, re);
2762 case Operator.LogicalAnd:
2763 return SLE.Expression.AndAlso (le, re);
2764 case Operator.LogicalOr:
2765 return SLE.Expression.OrElse (le, re);
2766 case Operator.Modulus:
2767 return SLE.Expression.Modulo (le, re);
2768 case Operator.Multiply:
2769 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
2770 case Operator.RightShift:
2771 return SLE.Expression.RightShift (le, re);
2772 case Operator.Subtraction:
2773 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
2774 default:
2775 throw new NotImplementedException (oper.ToString ());
2779 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2781 left.MutateHoistedGenericType (storey);
2782 right.MutateHoistedGenericType (storey);
2786 // D operator + (D x, D y)
2787 // D operator - (D x, D y)
2788 // bool operator == (D x, D y)
2789 // bool operator != (D x, D y)
2791 Expression ResolveOperatorDelegate (ResolveContext ec, Type l, Type r)
2793 bool is_equality = (oper & Operator.EqualityMask) != 0;
2794 if (!TypeManager.IsEqual (l, r) && !TypeManager.IsVariantOf (r, l)) {
2795 Expression tmp;
2796 if (right.eclass == ExprClass.MethodGroup || (r == InternalType.AnonymousMethod && !is_equality)) {
2797 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2798 if (tmp == null)
2799 return null;
2800 right = tmp;
2801 r = right.Type;
2802 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod && !is_equality)) {
2803 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2804 if (tmp == null)
2805 return null;
2806 left = tmp;
2807 l = left.Type;
2808 } else {
2809 return null;
2814 // Resolve delegate equality as a user operator
2816 if (is_equality)
2817 return ResolveUserOperator (ec, l, r);
2819 MethodSpec method;
2820 Arguments args = new Arguments (2);
2821 args.Add (new Argument (left));
2822 args.Add (new Argument (right));
2824 if (oper == Operator.Addition) {
2825 if (TypeManager.delegate_combine_delegate_delegate == null) {
2826 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2827 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2830 method = TypeManager.delegate_combine_delegate_delegate;
2831 } else {
2832 if (TypeManager.delegate_remove_delegate_delegate == null) {
2833 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2834 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2837 method = TypeManager.delegate_remove_delegate_delegate;
2840 MethodGroupExpr mg = new MethodGroupExpr (new [] { method }, TypeManager.delegate_type, loc);
2841 mg = mg.OverloadResolve (ec, ref args, false, loc);
2843 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2847 // Enumeration operators
2849 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2852 // bool operator == (E x, E y);
2853 // bool operator != (E x, E y);
2854 // bool operator < (E x, E y);
2855 // bool operator > (E x, E y);
2856 // bool operator <= (E x, E y);
2857 // bool operator >= (E x, E y);
2859 // E operator & (E x, E y);
2860 // E operator | (E x, E y);
2861 // E operator ^ (E x, E y);
2863 // U operator - (E e, E f)
2864 // E operator - (E e, U x)
2866 // E operator + (U x, E e)
2867 // E operator + (E e, U x)
2869 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2870 (oper == Operator.Subtraction && lenum) ||
2871 (oper == Operator.Addition && (lenum != renum || type != null)))) // type != null for lifted null
2872 return null;
2874 Expression ltemp = left;
2875 Expression rtemp = right;
2876 Type underlying_type;
2877 Expression expr;
2879 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2880 if (renum) {
2881 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2882 if (expr != null) {
2883 left = expr;
2884 ltype = expr.Type;
2886 } else if (lenum) {
2887 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2888 if (expr != null) {
2889 right = expr;
2890 rtype = expr.Type;
2895 if (TypeManager.IsEqual (ltype, rtype)) {
2896 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2898 if (left is Constant)
2899 left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
2900 else
2901 left = EmptyCast.Create (left, underlying_type);
2903 if (right is Constant)
2904 right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
2905 else
2906 right = EmptyCast.Create (right, underlying_type);
2907 } else if (lenum) {
2908 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2910 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2911 Constant c = right as Constant;
2912 if (c == null || !c.IsDefaultValue)
2913 return null;
2914 } else {
2915 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2916 return null;
2918 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2921 if (left is Constant)
2922 left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
2923 else
2924 left = EmptyCast.Create (left, underlying_type);
2926 } else if (renum) {
2927 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2929 if (oper != Operator.Addition) {
2930 Constant c = left as Constant;
2931 if (c == null || !c.IsDefaultValue)
2932 return null;
2933 } else {
2934 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2935 return null;
2937 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2940 if (right is Constant)
2941 right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
2942 else
2943 right = EmptyCast.Create (right, underlying_type);
2945 } else {
2946 return null;
2950 // C# specification uses explicit cast syntax which means binary promotion
2951 // should happen, however it seems that csc does not do that
2953 if (!DoBinaryOperatorPromotion (ec)) {
2954 left = ltemp;
2955 right = rtemp;
2956 return null;
2959 Type res_type = null;
2960 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2961 Type promoted_type = lenum ? left.Type : right.Type;
2962 enum_conversion = Convert.ExplicitNumericConversion (
2963 new EmptyExpression (promoted_type), underlying_type);
2965 if (oper == Operator.Subtraction && renum && lenum)
2966 res_type = underlying_type;
2967 else if (oper == Operator.Addition && renum)
2968 res_type = rtype;
2969 else
2970 res_type = ltype;
2973 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2974 if (!is_compound || expr == null)
2975 return expr;
2978 // Section: 7.16.2
2982 // If the return type of the selected operator is implicitly convertible to the type of x
2984 if (Convert.ImplicitConversionExists (ec, expr, ltype))
2985 return expr;
2988 // Otherwise, if the selected operator is a predefined operator, if the return type of the
2989 // selected operator is explicitly convertible to the type of x, and if y is implicitly
2990 // convertible to the type of x or the operator is a shift operator, then the operation
2991 // is evaluated as x = (T)(x op y), where T is the type of x
2993 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
2994 if (expr == null)
2995 return null;
2997 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
2998 return expr;
3000 return null;
3004 // 7.9.6 Reference type equality operators
3006 Binary ResolveOperatorEqualityRerefence (ResolveContext ec, Type l, Type r)
3009 // operator != (object a, object b)
3010 // operator == (object a, object b)
3013 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
3015 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
3016 return null;
3018 type = TypeManager.bool_type;
3019 GenericConstraints constraints;
3021 bool lgen = TypeManager.IsGenericParameter (l);
3023 if (TypeManager.IsEqual (l, r)) {
3024 if (lgen) {
3026 // Only allow to compare same reference type parameter
3028 if (TypeManager.IsReferenceType (l)) {
3029 left = new BoxedCast (left, TypeManager.object_type);
3030 right = new BoxedCast (right, TypeManager.object_type);
3031 return this;
3034 return null;
3037 if (l == InternalType.AnonymousMethod)
3038 return null;
3040 if (TypeManager.IsValueType (l))
3041 return null;
3043 return this;
3046 bool rgen = TypeManager.IsGenericParameter (r);
3049 // a, Both operands are reference-type values or the value null
3050 // b, One operand is a value of type T where T is a type-parameter and
3051 // the other operand is the value null. Furthermore T does not have the
3052 // value type constrain
3054 if (left is NullLiteral || right is NullLiteral) {
3055 if (lgen) {
3056 constraints = TypeManager.GetTypeParameterConstraints (l);
3057 if (constraints != null && constraints.HasValueTypeConstraint)
3058 return null;
3060 left = new BoxedCast (left, TypeManager.object_type);
3061 return this;
3064 if (rgen) {
3065 constraints = TypeManager.GetTypeParameterConstraints (r);
3066 if (constraints != null && constraints.HasValueTypeConstraint)
3067 return null;
3069 right = new BoxedCast (right, TypeManager.object_type);
3070 return this;
3075 // An interface is converted to the object before the
3076 // standard conversion is applied. It's not clear from the
3077 // standard but it looks like it works like that.
3079 if (lgen) {
3080 if (!TypeManager.IsReferenceType (l))
3081 return null;
3083 l = TypeManager.object_type;
3084 left = new BoxedCast (left, l);
3085 } else if (l.IsInterface) {
3086 l = TypeManager.object_type;
3087 } else if (TypeManager.IsStruct (l)) {
3088 return null;
3091 if (rgen) {
3092 if (!TypeManager.IsReferenceType (r))
3093 return null;
3095 r = TypeManager.object_type;
3096 right = new BoxedCast (right, r);
3097 } else if (r.IsInterface) {
3098 r = TypeManager.object_type;
3099 } else if (TypeManager.IsStruct (r)) {
3100 return null;
3104 const string ref_comparison = "Possible unintended reference comparison. " +
3105 "Consider casting the {0} side of the expression to `string' to compare the values";
3108 // A standard implicit conversion exists from the type of either
3109 // operand to the type of the other operand
3111 if (Convert.ImplicitReferenceConversionExists (left, r)) {
3112 if (l == TypeManager.string_type)
3113 ec.Report.Warning (253, 2, loc, ref_comparison, "right");
3115 return this;
3118 if (Convert.ImplicitReferenceConversionExists (right, l)) {
3119 if (r == TypeManager.string_type)
3120 ec.Report.Warning (252, 2, loc, ref_comparison, "left");
3122 return this;
3125 return null;
3129 Expression ResolveOperatorPointer (ResolveContext ec, Type l, Type r)
3132 // bool operator == (void* x, void* y);
3133 // bool operator != (void* x, void* y);
3134 // bool operator < (void* x, void* y);
3135 // bool operator > (void* x, void* y);
3136 // bool operator <= (void* x, void* y);
3137 // bool operator >= (void* x, void* y);
3139 if ((oper & Operator.ComparisonMask) != 0) {
3140 Expression temp;
3141 if (!l.IsPointer) {
3142 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3143 if (temp == null)
3144 return null;
3145 left = temp;
3148 if (!r.IsPointer) {
3149 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3150 if (temp == null)
3151 return null;
3152 right = temp;
3155 type = TypeManager.bool_type;
3156 return this;
3159 if (pointer_operators == null)
3160 CreatePointerOperatorsTable ();
3162 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
3166 // Build-in operators method overloading
3168 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
3170 PredefinedOperator best_operator = null;
3171 Type l = left.Type;
3172 Type r = right.Type;
3173 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3175 foreach (PredefinedOperator po in operators) {
3176 if ((po.OperatorsMask & oper_mask) == 0)
3177 continue;
3179 if (primitives_only) {
3180 if (!po.IsPrimitiveApplicable (l, r))
3181 continue;
3182 } else {
3183 if (!po.IsApplicable (ec, left, right))
3184 continue;
3187 if (best_operator == null) {
3188 best_operator = po;
3189 if (primitives_only)
3190 break;
3192 continue;
3195 best_operator = po.ResolveBetterOperator (ec, best_operator);
3197 if (best_operator == null) {
3198 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3199 OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
3201 best_operator = po;
3202 break;
3206 if (best_operator == null)
3207 return null;
3209 Expression expr = best_operator.ConvertResult (ec, this);
3212 // Optimize &/&& constant expressions with 0 value
3214 if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
3215 Constant rc = right as Constant;
3216 Constant lc = left as Constant;
3217 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
3219 // The result is a constant with side-effect
3221 Constant side_effect = rc == null ?
3222 new SideEffectConstant (lc, right, loc) :
3223 new SideEffectConstant (rc, left, loc);
3225 return ReducedExpression.Create (side_effect.Resolve (ec), expr);
3229 if (enum_type == null)
3230 return expr;
3233 // HACK: required by enum_conversion
3235 expr.Type = enum_type;
3236 return EmptyCast.Create (expr, enum_type);
3240 // Performs user-operator overloading
3242 protected virtual Expression ResolveUserOperator (ResolveContext ec, Type l, Type r)
3244 Operator user_oper;
3245 if (oper == Operator.LogicalAnd)
3246 user_oper = Operator.BitwiseAnd;
3247 else if (oper == Operator.LogicalOr)
3248 user_oper = Operator.BitwiseOr;
3249 else
3250 user_oper = oper;
3252 string op = GetOperatorMetadataName (user_oper);
3254 MethodGroupExpr left_operators = MemberLookup (ec.Compiler, ec.CurrentType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3255 MethodGroupExpr right_operators = null;
3257 if (!TypeManager.IsEqual (r, l)) {
3258 right_operators = MemberLookup (ec.Compiler, ec.CurrentType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3259 if (right_operators == null && left_operators == null)
3260 return null;
3261 } else if (left_operators == null) {
3262 return null;
3265 Arguments args = new Arguments (2);
3266 Argument larg = new Argument (left);
3267 args.Add (larg);
3268 Argument rarg = new Argument (right);
3269 args.Add (rarg);
3271 MethodGroupExpr union;
3274 // User-defined operator implementations always take precedence
3275 // over predefined operator implementations
3277 if (left_operators != null && right_operators != null) {
3278 if (IsPredefinedUserOperator (l, user_oper)) {
3279 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3280 if (union == null)
3281 union = left_operators;
3282 } else if (IsPredefinedUserOperator (r, user_oper)) {
3283 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3284 if (union == null)
3285 union = right_operators;
3286 } else {
3287 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3289 } else if (left_operators != null) {
3290 union = left_operators;
3291 } else {
3292 union = right_operators;
3295 union = union.OverloadResolve (ec, ref args, true, loc);
3296 if (union == null)
3297 return null;
3299 Expression oper_expr;
3301 // TODO: CreateExpressionTree is allocated every time
3302 if (user_oper != oper) {
3303 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3304 oper == Operator.LogicalAnd, loc).Resolve (ec);
3305 } else {
3306 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3309 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3310 // and not invoke user operator
3312 if ((oper & Operator.EqualityMask) != 0) {
3313 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3314 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3315 type = TypeManager.bool_type;
3316 if (left is NullLiteral || right is NullLiteral)
3317 oper_expr = ReducedExpression.Create (this, oper_expr);
3318 } else if (l != r) {
3319 var mi = union.BestCandidate;
3322 // Two System.Delegate(s) are never equal
3324 if (mi.DeclaringType == TypeManager.multicast_delegate_type)
3325 return null;
3330 left = larg.Expr;
3331 right = rarg.Expr;
3332 return oper_expr;
3335 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3337 return null;
3340 private void CheckUselessComparison (ResolveContext ec, Constant c, Type type)
3342 if (c == null || !IsTypeIntegral (type)
3343 || c is StringConstant
3344 || c is BoolConstant
3345 || c is FloatConstant
3346 || c is DoubleConstant
3347 || c is DecimalConstant
3349 return;
3351 long value = 0;
3353 if (c is ULongConstant) {
3354 ulong uvalue = ((ULongConstant) c).Value;
3355 if (uvalue > long.MaxValue) {
3356 if (type == TypeManager.byte_type ||
3357 type == TypeManager.sbyte_type ||
3358 type == TypeManager.short_type ||
3359 type == TypeManager.ushort_type ||
3360 type == TypeManager.int32_type ||
3361 type == TypeManager.uint32_type ||
3362 type == TypeManager.int64_type ||
3363 type == TypeManager.char_type)
3364 WarnUselessComparison (ec, type);
3365 return;
3367 value = (long) uvalue;
3369 else if (c is ByteConstant)
3370 value = ((ByteConstant) c).Value;
3371 else if (c is SByteConstant)
3372 value = ((SByteConstant) c).Value;
3373 else if (c is ShortConstant)
3374 value = ((ShortConstant) c).Value;
3375 else if (c is UShortConstant)
3376 value = ((UShortConstant) c).Value;
3377 else if (c is IntConstant)
3378 value = ((IntConstant) c).Value;
3379 else if (c is UIntConstant)
3380 value = ((UIntConstant) c).Value;
3381 else if (c is LongConstant)
3382 value = ((LongConstant) c).Value;
3383 else if (c is CharConstant)
3384 value = ((CharConstant)c).Value;
3386 if (value == 0)
3387 return;
3389 if (IsValueOutOfRange (value, type))
3390 WarnUselessComparison (ec, type);
3393 static bool IsValueOutOfRange (long value, Type type)
3395 if (IsTypeUnsigned (type) && value < 0)
3396 return true;
3397 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3398 type == TypeManager.byte_type && value >= 0x100 ||
3399 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3400 type == TypeManager.ushort_type && value >= 0x10000 ||
3401 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3402 type == TypeManager.uint32_type && value >= 0x100000000;
3405 static bool IsBuildInEqualityOperator (Type t)
3407 return t == TypeManager.object_type || t == TypeManager.string_type ||
3408 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3411 static bool IsPredefinedUserOperator (Type t, Operator op)
3414 // Some predefined types have user operators
3416 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3419 private static bool IsTypeIntegral (Type type)
3421 return type == TypeManager.uint64_type ||
3422 type == TypeManager.int64_type ||
3423 type == TypeManager.uint32_type ||
3424 type == TypeManager.int32_type ||
3425 type == TypeManager.ushort_type ||
3426 type == TypeManager.short_type ||
3427 type == TypeManager.sbyte_type ||
3428 type == TypeManager.byte_type ||
3429 type == TypeManager.char_type;
3432 private static bool IsTypeUnsigned (Type type)
3434 return type == TypeManager.uint64_type ||
3435 type == TypeManager.uint32_type ||
3436 type == TypeManager.ushort_type ||
3437 type == TypeManager.byte_type ||
3438 type == TypeManager.char_type;
3441 private void WarnUselessComparison (ResolveContext ec, Type type)
3443 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}'",
3444 TypeManager.CSharpName (type));
3447 /// <remarks>
3448 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3449 /// context of a conditional bool expression. This function will return
3450 /// false if it is was possible to use EmitBranchable, or true if it was.
3452 /// The expression's code is generated, and we will generate a branch to `target'
3453 /// if the resulting expression value is equal to isTrue
3454 /// </remarks>
3455 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3457 ILGenerator ig = ec.ig;
3460 // This is more complicated than it looks, but its just to avoid
3461 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3462 // but on top of that we want for == and != to use a special path
3463 // if we are comparing against null
3465 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3466 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3469 // put the constant on the rhs, for simplicity
3471 if (left is Constant) {
3472 Expression swap = right;
3473 right = left;
3474 left = swap;
3477 if (((Constant) right).IsZeroInteger) {
3478 left.EmitBranchable (ec, target, my_on_true);
3479 return;
3481 if (right.Type == TypeManager.bool_type) {
3482 // right is a boolean, and it's not 'false' => it is 'true'
3483 left.EmitBranchable (ec, target, !my_on_true);
3484 return;
3487 } else if (oper == Operator.LogicalAnd) {
3489 if (on_true) {
3490 Label tests_end = ig.DefineLabel ();
3492 left.EmitBranchable (ec, tests_end, false);
3493 right.EmitBranchable (ec, target, true);
3494 ig.MarkLabel (tests_end);
3495 } else {
3497 // This optimizes code like this
3498 // if (true && i > 4)
3500 if (!(left is Constant))
3501 left.EmitBranchable (ec, target, false);
3503 if (!(right is Constant))
3504 right.EmitBranchable (ec, target, false);
3507 return;
3509 } else if (oper == Operator.LogicalOr){
3510 if (on_true) {
3511 left.EmitBranchable (ec, target, true);
3512 right.EmitBranchable (ec, target, true);
3514 } else {
3515 Label tests_end = ig.DefineLabel ();
3516 left.EmitBranchable (ec, tests_end, true);
3517 right.EmitBranchable (ec, target, false);
3518 ig.MarkLabel (tests_end);
3521 return;
3523 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3524 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3525 oper == Operator.Equality || oper == Operator.Inequality)) {
3526 base.EmitBranchable (ec, target, on_true);
3527 return;
3530 left.Emit (ec);
3531 right.Emit (ec);
3533 Type t = left.Type;
3534 bool is_float = IsFloat (t);
3535 bool is_unsigned = is_float || IsUnsigned (t);
3537 switch (oper){
3538 case Operator.Equality:
3539 if (on_true)
3540 ig.Emit (OpCodes.Beq, target);
3541 else
3542 ig.Emit (OpCodes.Bne_Un, target);
3543 break;
3545 case Operator.Inequality:
3546 if (on_true)
3547 ig.Emit (OpCodes.Bne_Un, target);
3548 else
3549 ig.Emit (OpCodes.Beq, target);
3550 break;
3552 case Operator.LessThan:
3553 if (on_true)
3554 if (is_unsigned && !is_float)
3555 ig.Emit (OpCodes.Blt_Un, target);
3556 else
3557 ig.Emit (OpCodes.Blt, target);
3558 else
3559 if (is_unsigned)
3560 ig.Emit (OpCodes.Bge_Un, target);
3561 else
3562 ig.Emit (OpCodes.Bge, target);
3563 break;
3565 case Operator.GreaterThan:
3566 if (on_true)
3567 if (is_unsigned && !is_float)
3568 ig.Emit (OpCodes.Bgt_Un, target);
3569 else
3570 ig.Emit (OpCodes.Bgt, target);
3571 else
3572 if (is_unsigned)
3573 ig.Emit (OpCodes.Ble_Un, target);
3574 else
3575 ig.Emit (OpCodes.Ble, target);
3576 break;
3578 case Operator.LessThanOrEqual:
3579 if (on_true)
3580 if (is_unsigned && !is_float)
3581 ig.Emit (OpCodes.Ble_Un, target);
3582 else
3583 ig.Emit (OpCodes.Ble, target);
3584 else
3585 if (is_unsigned)
3586 ig.Emit (OpCodes.Bgt_Un, target);
3587 else
3588 ig.Emit (OpCodes.Bgt, target);
3589 break;
3592 case Operator.GreaterThanOrEqual:
3593 if (on_true)
3594 if (is_unsigned && !is_float)
3595 ig.Emit (OpCodes.Bge_Un, target);
3596 else
3597 ig.Emit (OpCodes.Bge, target);
3598 else
3599 if (is_unsigned)
3600 ig.Emit (OpCodes.Blt_Un, target);
3601 else
3602 ig.Emit (OpCodes.Blt, target);
3603 break;
3604 default:
3605 throw new InternalErrorException (oper.ToString ());
3609 public override void Emit (EmitContext ec)
3611 EmitOperator (ec, left.Type);
3614 protected virtual void EmitOperator (EmitContext ec, Type l)
3616 ILGenerator ig = ec.ig;
3619 // Handle short-circuit operators differently
3620 // than the rest
3622 if ((oper & Operator.LogicalMask) != 0) {
3623 Label load_result = ig.DefineLabel ();
3624 Label end = ig.DefineLabel ();
3626 bool is_or = oper == Operator.LogicalOr;
3627 left.EmitBranchable (ec, load_result, is_or);
3628 right.Emit (ec);
3629 ig.Emit (OpCodes.Br_S, end);
3631 ig.MarkLabel (load_result);
3632 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3633 ig.MarkLabel (end);
3634 return;
3638 // Optimize zero-based operations which cannot be optimized at expression level
3640 if (oper == Operator.Subtraction) {
3641 var lc = left as IntegralConstant;
3642 if (lc != null && lc.IsDefaultValue) {
3643 right.Emit (ec);
3644 ig.Emit (OpCodes.Neg);
3645 return;
3649 left.Emit (ec);
3650 right.Emit (ec);
3651 EmitOperatorOpcode (ec, oper, l);
3654 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3655 // expression because that would wrap lifted binary operation
3657 if (enum_conversion != null)
3658 enum_conversion.Emit (ec);
3661 public override void EmitSideEffect (EmitContext ec)
3663 if ((oper & Operator.LogicalMask) != 0 ||
3664 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3665 base.EmitSideEffect (ec);
3666 } else {
3667 left.EmitSideEffect (ec);
3668 right.EmitSideEffect (ec);
3672 protected override void CloneTo (CloneContext clonectx, Expression t)
3674 Binary target = (Binary) t;
3676 target.left = left.Clone (clonectx);
3677 target.right = right.Clone (clonectx);
3680 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3682 Arguments binder_args = new Arguments (3);
3684 MemberAccess sle = new MemberAccess (new MemberAccess (
3685 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3687 CSharpBinderFlags flags = 0;
3688 if (ec.HasSet (ResolveContext.Options.CheckedScope))
3689 flags = CSharpBinderFlags.CheckedContext;
3691 if ((oper & Operator.LogicalMask) != 0)
3692 flags |= CSharpBinderFlags.BinaryOperationLogical;
3694 binder_args.Add (new Argument (new EnumConstant (new IntLiteral ((int) flags, loc), TypeManager.binder_flags)));
3695 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3696 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (ec), loc)));
3698 return new Invocation (DynamicExpressionStatement.GetBinder ("BinaryOperation", loc), binder_args);
3701 public override Expression CreateExpressionTree (ResolveContext ec)
3703 return CreateExpressionTree (ec, null);
3706 Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr method)
3708 string method_name;
3709 bool lift_arg = false;
3711 switch (oper) {
3712 case Operator.Addition:
3713 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3714 method_name = "AddChecked";
3715 else
3716 method_name = "Add";
3717 break;
3718 case Operator.BitwiseAnd:
3719 method_name = "And";
3720 break;
3721 case Operator.BitwiseOr:
3722 method_name = "Or";
3723 break;
3724 case Operator.Division:
3725 method_name = "Divide";
3726 break;
3727 case Operator.Equality:
3728 method_name = "Equal";
3729 lift_arg = true;
3730 break;
3731 case Operator.ExclusiveOr:
3732 method_name = "ExclusiveOr";
3733 break;
3734 case Operator.GreaterThan:
3735 method_name = "GreaterThan";
3736 lift_arg = true;
3737 break;
3738 case Operator.GreaterThanOrEqual:
3739 method_name = "GreaterThanOrEqual";
3740 lift_arg = true;
3741 break;
3742 case Operator.Inequality:
3743 method_name = "NotEqual";
3744 lift_arg = true;
3745 break;
3746 case Operator.LeftShift:
3747 method_name = "LeftShift";
3748 break;
3749 case Operator.LessThan:
3750 method_name = "LessThan";
3751 lift_arg = true;
3752 break;
3753 case Operator.LessThanOrEqual:
3754 method_name = "LessThanOrEqual";
3755 lift_arg = true;
3756 break;
3757 case Operator.LogicalAnd:
3758 method_name = "AndAlso";
3759 break;
3760 case Operator.LogicalOr:
3761 method_name = "OrElse";
3762 break;
3763 case Operator.Modulus:
3764 method_name = "Modulo";
3765 break;
3766 case Operator.Multiply:
3767 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3768 method_name = "MultiplyChecked";
3769 else
3770 method_name = "Multiply";
3771 break;
3772 case Operator.RightShift:
3773 method_name = "RightShift";
3774 break;
3775 case Operator.Subtraction:
3776 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3777 method_name = "SubtractChecked";
3778 else
3779 method_name = "Subtract";
3780 break;
3782 default:
3783 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3786 Arguments args = new Arguments (2);
3787 args.Add (new Argument (left.CreateExpressionTree (ec)));
3788 args.Add (new Argument (right.CreateExpressionTree (ec)));
3789 if (method != null) {
3790 if (lift_arg)
3791 args.Add (new Argument (new BoolConstant (false, loc)));
3793 args.Add (new Argument (method.CreateExpressionTree (ec)));
3796 return CreateExpressionFactoryCall (ec, method_name, args);
3801 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3802 // b, c, d... may be strings or objects.
3804 public class StringConcat : Expression {
3805 Arguments arguments;
3807 public StringConcat (Expression left, Expression right, Location loc)
3809 this.loc = loc;
3810 type = TypeManager.string_type;
3811 eclass = ExprClass.Value;
3813 arguments = new Arguments (2);
3816 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
3818 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
3819 throw new ArgumentException ();
3821 var s = new StringConcat (left, right, loc);
3822 s.Append (rc, left);
3823 s.Append (rc, right);
3824 return s;
3827 public override Expression CreateExpressionTree (ResolveContext ec)
3829 Argument arg = arguments [0];
3830 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
3834 // Creates nested calls tree from an array of arguments used for IL emit
3836 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
3838 Arguments concat_args = new Arguments (2);
3839 Arguments add_args = new Arguments (3);
3841 concat_args.Add (left);
3842 add_args.Add (new Argument (left_etree));
3844 concat_args.Add (arguments [pos]);
3845 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
3847 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3848 if (method == null)
3849 return null;
3851 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3852 if (method == null)
3853 return null;
3855 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3857 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
3858 if (++pos == arguments.Count)
3859 return expr;
3861 left = new Argument (new EmptyExpression (method.BestCandidate.ReturnType));
3862 return CreateExpressionAddCall (ec, left, expr, pos);
3865 protected override Expression DoResolve (ResolveContext ec)
3867 return this;
3870 void Append (ResolveContext rc, Expression operand)
3873 // Constant folding
3875 StringConstant sc = operand as StringConstant;
3876 if (sc != null) {
3877 if (arguments.Count != 0) {
3878 Argument last_argument = arguments [arguments.Count - 1];
3879 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3880 if (last_expr_constant != null) {
3881 last_argument.Expr = new StringConstant (
3882 last_expr_constant.Value + sc.Value, sc.Location).Resolve (rc);
3883 return;
3886 } else {
3888 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3890 StringConcat concat_oper = operand as StringConcat;
3891 if (concat_oper != null) {
3892 arguments.AddRange (concat_oper.arguments);
3893 return;
3897 arguments.Add (new Argument (operand));
3900 Expression CreateConcatMemberExpression ()
3902 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3905 public override void Emit (EmitContext ec)
3907 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3908 concat = concat.Resolve (new ResolveContext (ec.MemberContext));
3909 if (concat != null)
3910 concat.Emit (ec);
3913 public override SLE.Expression MakeExpression (BuilderContext ctx)
3915 if (arguments.Count != 2)
3916 throw new NotImplementedException ("arguments.Count != 2");
3918 var concat = TypeManager.string_type.GetMethod ("Concat", new[] { typeof (object), typeof (object) });
3919 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
3922 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3924 arguments.MutateHoistedGenericType (storey);
3929 // User-defined conditional logical operator
3931 public class ConditionalLogicalOperator : UserOperatorCall {
3932 readonly bool is_and;
3933 Expression oper;
3935 public ConditionalLogicalOperator (MethodGroupExpr oper_method, Arguments arguments,
3936 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3937 : base (oper_method, arguments, expr_tree, loc)
3939 this.is_and = is_and;
3940 eclass = ExprClass.Unresolved;
3943 protected override Expression DoResolve (ResolveContext ec)
3945 var method = mg.BestCandidate;
3946 type = TypeManager.TypeToCoreType (method.ReturnType);
3947 AParametersCollection pd = method.Parameters;
3948 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3949 ec.Report.Error (217, loc,
3950 "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",
3951 TypeManager.CSharpSignature (method.MetaInfo));
3952 return null;
3955 Expression left_dup = new EmptyExpression (type);
3956 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3957 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3958 if (op_true == null || op_false == null) {
3959 ec.Report.Error (218, loc,
3960 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3961 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method.MetaInfo));
3962 return null;
3965 oper = is_and ? op_false : op_true;
3966 eclass = ExprClass.Value;
3967 return this;
3970 public override void Emit (EmitContext ec)
3972 ILGenerator ig = ec.ig;
3973 Label end_target = ig.DefineLabel ();
3976 // Emit and duplicate left argument
3978 arguments [0].Expr.Emit (ec);
3979 ig.Emit (OpCodes.Dup);
3980 arguments.RemoveAt (0);
3982 oper.EmitBranchable (ec, end_target, true);
3983 base.Emit (ec);
3984 ig.MarkLabel (end_target);
3988 public class PointerArithmetic : Expression {
3989 Expression left, right;
3990 Binary.Operator op;
3993 // We assume that `l' is always a pointer
3995 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3997 type = t;
3998 this.loc = loc;
3999 left = l;
4000 right = r;
4001 this.op = op;
4004 public override Expression CreateExpressionTree (ResolveContext ec)
4006 Error_PointerInsideExpressionTree (ec);
4007 return null;
4010 protected override Expression DoResolve (ResolveContext ec)
4012 eclass = ExprClass.Variable;
4014 if (left.Type == TypeManager.void_ptr_type) {
4015 ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
4016 return null;
4019 return this;
4022 public override void Emit (EmitContext ec)
4024 Type op_type = left.Type;
4025 ILGenerator ig = ec.ig;
4027 // It must be either array or fixed buffer
4028 Type element;
4029 if (TypeManager.HasElementType (op_type)) {
4030 element = TypeManager.GetElementType (op_type);
4031 } else {
4032 FieldExpr fe = left as FieldExpr;
4033 if (fe != null)
4034 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
4035 else
4036 element = op_type;
4039 int size = GetTypeSize (element);
4040 Type rtype = right.Type;
4042 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4044 // handle (pointer - pointer)
4046 left.Emit (ec);
4047 right.Emit (ec);
4048 ig.Emit (OpCodes.Sub);
4050 if (size != 1){
4051 if (size == 0)
4052 ig.Emit (OpCodes.Sizeof, element);
4053 else
4054 IntLiteral.EmitInt (ig, size);
4055 ig.Emit (OpCodes.Div);
4057 ig.Emit (OpCodes.Conv_I8);
4058 } else {
4060 // handle + and - on (pointer op int)
4062 Constant left_const = left as Constant;
4063 if (left_const != null) {
4065 // Optimize ((T*)null) pointer operations
4067 if (left_const.IsDefaultValue) {
4068 left = EmptyExpression.Null;
4069 } else {
4070 left_const = null;
4074 left.Emit (ec);
4076 var right_const = right as Constant;
4077 if (right_const != null) {
4079 // Optimize 0-based arithmetic
4081 if (right_const.IsDefaultValue)
4082 return;
4084 if (size != 0)
4085 right = new IntConstant (size, right.Location);
4086 else
4087 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
4089 // TODO: Should be the checks resolve context sensitive?
4090 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
4091 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
4092 if (right == null)
4093 return;
4096 right.Emit (ec);
4097 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
4098 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
4099 ig.Emit (OpCodes.Conv_I);
4100 } else if (rtype == TypeManager.uint32_type) {
4101 ig.Emit (OpCodes.Conv_U);
4104 if (right_const == null && size != 1){
4105 if (size == 0)
4106 ig.Emit (OpCodes.Sizeof, element);
4107 else
4108 IntLiteral.EmitInt (ig, size);
4109 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
4110 ig.Emit (OpCodes.Conv_I8);
4112 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4115 if (left_const == null) {
4116 if (rtype == TypeManager.int64_type)
4117 ig.Emit (OpCodes.Conv_I);
4118 else if (rtype == TypeManager.uint64_type)
4119 ig.Emit (OpCodes.Conv_U);
4121 Binary.EmitOperatorOpcode (ec, op, op_type);
4128 // A boolean-expression is an expression that yields a result
4129 // of type bool
4131 public class BooleanExpression : ShimExpression
4133 public BooleanExpression (Expression expr)
4134 : base (expr)
4136 this.loc = expr.Location;
4139 public override Expression CreateExpressionTree (ResolveContext ec)
4141 // TODO: We should emit IsTrue (v4) instead of direct user operator
4142 // call but that would break csc compatibility
4143 return base.CreateExpressionTree (ec);
4146 protected override Expression DoResolve (ResolveContext ec)
4148 // A boolean-expression is required to be of a type
4149 // that can be implicitly converted to bool or of
4150 // a type that implements operator true
4152 expr = expr.Resolve (ec);
4153 if (expr == null)
4154 return null;
4156 Assign ass = expr as Assign;
4157 if (ass != null && ass.Source is Constant) {
4158 ec.Report.Warning (665, 3, loc,
4159 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4162 if (expr.Type == TypeManager.bool_type)
4163 return expr;
4165 if (TypeManager.IsDynamicType (expr.Type)) {
4166 Arguments args = new Arguments (1);
4167 args.Add (new Argument (expr));
4168 return new DynamicUnaryConversion ("IsTrue", args, loc).Resolve (ec);
4171 type = TypeManager.bool_type;
4172 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4173 if (converted != null)
4174 return converted;
4177 // If no implicit conversion to bool exists, try using `operator true'
4179 converted = GetOperatorTrue (ec, expr, loc);
4180 if (converted == null) {
4181 expr.Error_ValueCannotBeConverted (ec, loc, type, false);
4182 return null;
4185 return converted;
4189 /// <summary>
4190 /// Implements the ternary conditional operator (?:)
4191 /// </summary>
4192 public class Conditional : Expression {
4193 Expression expr, true_expr, false_expr;
4195 public Conditional (BooleanExpression expr, Expression true_expr, Expression false_expr)
4197 this.expr = expr;
4198 this.true_expr = true_expr;
4199 this.false_expr = false_expr;
4200 this.loc = expr.Location;
4203 public Expression Expr {
4204 get {
4205 return expr;
4209 public Expression TrueExpr {
4210 get {
4211 return true_expr;
4215 public Expression FalseExpr {
4216 get {
4217 return false_expr;
4221 public override Expression CreateExpressionTree (ResolveContext ec)
4223 Arguments args = new Arguments (3);
4224 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4225 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4226 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4227 return CreateExpressionFactoryCall (ec, "Condition", args);
4230 protected override Expression DoResolve (ResolveContext ec)
4232 expr = expr.Resolve (ec);
4233 true_expr = true_expr.Resolve (ec);
4234 false_expr = false_expr.Resolve (ec);
4236 if (true_expr == null || false_expr == null || expr == null)
4237 return null;
4239 eclass = ExprClass.Value;
4240 Type true_type = true_expr.Type;
4241 Type false_type = false_expr.Type;
4242 type = true_type;
4245 // First, if an implicit conversion exists from true_expr
4246 // to false_expr, then the result type is of type false_expr.Type
4248 if (!TypeManager.IsEqual (true_type, false_type)) {
4249 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4250 if (conv != null) {
4252 // Check if both can convert implicitly to each other's type
4254 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
4255 ec.Report.Error (172, loc,
4256 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
4257 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4258 return null;
4260 type = false_type;
4261 true_expr = conv;
4262 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4263 false_expr = conv;
4264 } else {
4265 ec.Report.Error (173, loc,
4266 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4267 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4268 return null;
4272 // Dead code optimalization
4273 Constant c = expr as Constant;
4274 if (c != null){
4275 bool is_false = c.IsDefaultValue;
4276 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
4277 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
4280 return this;
4283 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4285 expr.MutateHoistedGenericType (storey);
4286 true_expr.MutateHoistedGenericType (storey);
4287 false_expr.MutateHoistedGenericType (storey);
4288 type = storey.MutateType (type);
4291 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
4293 return null;
4296 public override void Emit (EmitContext ec)
4298 ILGenerator ig = ec.ig;
4299 Label false_target = ig.DefineLabel ();
4300 Label end_target = ig.DefineLabel ();
4302 expr.EmitBranchable (ec, false_target, false);
4303 true_expr.Emit (ec);
4305 if (type.IsInterface) {
4306 LocalBuilder temp = ec.GetTemporaryLocal (type);
4307 ig.Emit (OpCodes.Stloc, temp);
4308 ig.Emit (OpCodes.Ldloc, temp);
4309 ec.FreeTemporaryLocal (temp, type);
4312 ig.Emit (OpCodes.Br, end_target);
4313 ig.MarkLabel (false_target);
4314 false_expr.Emit (ec);
4315 ig.MarkLabel (end_target);
4318 protected override void CloneTo (CloneContext clonectx, Expression t)
4320 Conditional target = (Conditional) t;
4322 target.expr = expr.Clone (clonectx);
4323 target.true_expr = true_expr.Clone (clonectx);
4324 target.false_expr = false_expr.Clone (clonectx);
4328 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4329 LocalTemporary temp;
4331 #region Abstract
4332 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4333 public abstract bool IsFixed { get; }
4334 public abstract bool IsRef { get; }
4335 public abstract string Name { get; }
4336 public abstract void SetHasAddressTaken ();
4339 // Variable IL data, it has to be protected to encapsulate hoisted variables
4341 protected abstract ILocalVariable Variable { get; }
4344 // Variable flow-analysis data
4346 public abstract VariableInfo VariableInfo { get; }
4347 #endregion
4349 public virtual void AddressOf (EmitContext ec, AddressOp mode)
4351 HoistedVariable hv = GetHoistedVariable (ec);
4352 if (hv != null) {
4353 hv.AddressOf (ec, mode);
4354 return;
4357 Variable.EmitAddressOf (ec);
4360 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4362 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4365 public HoistedVariable GetHoistedVariable (EmitContext ec)
4367 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4370 public override string GetSignatureForError ()
4372 return Name;
4375 public override void Emit (EmitContext ec)
4377 Emit (ec, false);
4380 public override void EmitSideEffect (EmitContext ec)
4382 // do nothing
4386 // This method is used by parameters that are references, that are
4387 // being passed as references: we only want to pass the pointer (that
4388 // is already stored in the parameter, not the address of the pointer,
4389 // and not the value of the variable).
4391 public void EmitLoad (EmitContext ec)
4393 Variable.Emit (ec);
4396 public void Emit (EmitContext ec, bool leave_copy)
4398 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4400 HoistedVariable hv = GetHoistedVariable (ec);
4401 if (hv != null) {
4402 hv.Emit (ec, leave_copy);
4403 return;
4406 EmitLoad (ec);
4408 if (IsRef) {
4410 // If we are a reference, we loaded on the stack a pointer
4411 // Now lets load the real value
4413 LoadFromPtr (ec.ig, type);
4416 if (leave_copy) {
4417 ec.ig.Emit (OpCodes.Dup);
4419 if (IsRef) {
4420 temp = new LocalTemporary (Type);
4421 temp.Store (ec);
4426 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4427 bool prepare_for_load)
4429 HoistedVariable hv = GetHoistedVariable (ec);
4430 if (hv != null) {
4431 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4432 return;
4435 New n_source = source as New;
4436 if (n_source != null) {
4437 if (!n_source.Emit (ec, this)) {
4438 if (leave_copy)
4439 EmitLoad (ec);
4440 return;
4442 } else {
4443 if (IsRef)
4444 EmitLoad (ec);
4446 source.Emit (ec);
4449 if (leave_copy) {
4450 ec.ig.Emit (OpCodes.Dup);
4451 if (IsRef) {
4452 temp = new LocalTemporary (Type);
4453 temp.Store (ec);
4457 if (IsRef)
4458 StoreFromPtr (ec.ig, type);
4459 else
4460 Variable.EmitAssign (ec);
4462 if (temp != null) {
4463 temp.Emit (ec);
4464 temp.Release (ec);
4468 public bool IsHoisted {
4469 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4472 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4474 type = storey.MutateType (type);
4478 /// <summary>
4479 /// Local variables
4480 /// </summary>
4481 public class LocalVariableReference : VariableReference {
4482 readonly string name;
4483 public Block Block;
4484 public LocalInfo local_info;
4485 bool is_readonly;
4487 public LocalVariableReference (Block block, string name, Location l)
4489 Block = block;
4490 this.name = name;
4491 loc = l;
4495 // Setting `is_readonly' to false will allow you to create a writable
4496 // reference to a read-only variable. This is used by foreach and using.
4498 public LocalVariableReference (Block block, string name, Location l,
4499 LocalInfo local_info, bool is_readonly)
4500 : this (block, name, l)
4502 this.local_info = local_info;
4503 this.is_readonly = is_readonly;
4506 public override VariableInfo VariableInfo {
4507 get { return local_info.VariableInfo; }
4510 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4512 return local_info.HoistedVariant;
4516 // A local variable is always fixed
4518 public override bool IsFixed {
4519 get { return true; }
4522 public override bool IsRef {
4523 get { return false; }
4526 public bool IsReadOnly {
4527 get { return is_readonly; }
4530 public override string Name {
4531 get { return name; }
4534 public bool VerifyAssigned (ResolveContext ec)
4536 VariableInfo variable_info = local_info.VariableInfo;
4537 return variable_info == null || variable_info.IsAssigned (ec, loc);
4540 void ResolveLocalInfo ()
4542 if (local_info == null) {
4543 local_info = Block.GetLocalInfo (Name);
4544 type = local_info.VariableType;
4545 is_readonly = local_info.ReadOnly;
4549 public override void SetHasAddressTaken ()
4551 local_info.AddressTaken = true;
4554 public override Expression CreateExpressionTree (ResolveContext ec)
4556 HoistedVariable hv = GetHoistedVariable (ec);
4557 if (hv != null)
4558 return hv.CreateExpressionTree ();
4560 Arguments arg = new Arguments (1);
4561 arg.Add (new Argument (this));
4562 return CreateExpressionFactoryCall (ec, "Constant", arg);
4565 Expression DoResolveBase (ResolveContext ec)
4567 Expression e = Block.GetConstantExpression (Name);
4568 if (e != null)
4569 return e.Resolve (ec);
4571 VerifyAssigned (ec);
4574 // If we are referencing a variable from the external block
4575 // flag it for capturing
4577 if (ec.MustCaptureVariable (local_info)) {
4578 if (local_info.AddressTaken)
4579 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4581 if (ec.IsVariableCapturingRequired) {
4582 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4583 storey.CaptureLocalVariable (ec, local_info);
4587 eclass = ExprClass.Variable;
4588 type = local_info.VariableType;
4589 return this;
4592 protected override Expression DoResolve (ResolveContext ec)
4594 ResolveLocalInfo ();
4595 local_info.Used = true;
4597 if (type == null && local_info.Type is VarExpr) {
4598 local_info.VariableType = TypeManager.object_type;
4599 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
4600 return null;
4603 return DoResolveBase (ec);
4606 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4608 ResolveLocalInfo ();
4610 // is out param
4611 if (right_side == EmptyExpression.OutAccess.Instance)
4612 local_info.Used = true;
4614 // Infer implicitly typed local variable
4615 if (type == null) {
4616 VarExpr ve = local_info.Type as VarExpr;
4617 if (ve != null) {
4618 if (!ve.InferType (ec, right_side))
4619 return null;
4620 type = local_info.VariableType = ve.Type;
4624 if (is_readonly) {
4625 int code;
4626 string msg;
4627 if (right_side == EmptyExpression.OutAccess.Instance) {
4628 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4629 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4630 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4631 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4632 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4633 } else if (right_side == EmptyExpression.UnaryAddress) {
4634 code = 459; msg = "Cannot take the address of {1} `{0}'";
4635 } else {
4636 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4638 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4639 } else if (VariableInfo != null) {
4640 VariableInfo.SetAssigned (ec);
4643 return DoResolveBase (ec);
4646 public override int GetHashCode ()
4648 return Name.GetHashCode ();
4651 public override bool Equals (object obj)
4653 LocalVariableReference lvr = obj as LocalVariableReference;
4654 if (lvr == null)
4655 return false;
4657 return Name == lvr.Name && Block == lvr.Block;
4660 protected override ILocalVariable Variable {
4661 get { return local_info; }
4664 public override string ToString ()
4666 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4669 protected override void CloneTo (CloneContext clonectx, Expression t)
4671 LocalVariableReference target = (LocalVariableReference) t;
4673 target.Block = clonectx.LookupBlock (Block);
4674 if (local_info != null)
4675 target.local_info = clonectx.LookupVariable (local_info);
4679 /// <summary>
4680 /// This represents a reference to a parameter in the intermediate
4681 /// representation.
4682 /// </summary>
4683 public class ParameterReference : VariableReference {
4684 readonly ToplevelParameterInfo pi;
4686 public ParameterReference (ToplevelParameterInfo pi, Location loc)
4688 this.pi = pi;
4689 this.loc = loc;
4692 public override bool IsRef {
4693 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4696 bool HasOutModifier {
4697 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4700 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4702 return pi.Parameter.HoistedVariant;
4706 // A ref or out parameter is classified as a moveable variable, even
4707 // if the argument given for the parameter is a fixed variable
4709 public override bool IsFixed {
4710 get { return !IsRef; }
4713 public override string Name {
4714 get { return Parameter.Name; }
4717 public Parameter Parameter {
4718 get { return pi.Parameter; }
4721 public override VariableInfo VariableInfo {
4722 get { return pi.VariableInfo; }
4725 protected override ILocalVariable Variable {
4726 get { return Parameter; }
4729 public bool IsAssigned (ResolveContext ec, Location loc)
4731 // HACK: Variables are not captured in probing mode
4732 if (ec.IsInProbingMode)
4733 return true;
4735 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4736 return true;
4738 ec.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4739 return false;
4742 public override void SetHasAddressTaken ()
4744 Parameter.HasAddressTaken = true;
4747 void SetAssigned (ResolveContext ec)
4749 if (HasOutModifier && ec.DoFlowAnalysis)
4750 ec.CurrentBranching.SetAssigned (VariableInfo);
4753 bool DoResolveBase (ResolveContext ec)
4755 type = pi.ParameterType;
4756 eclass = ExprClass.Variable;
4758 AnonymousExpression am = ec.CurrentAnonymousMethod;
4759 if (am == null)
4760 return true;
4762 Block b = ec.CurrentBlock;
4763 while (b != null) {
4764 b = b.Toplevel;
4765 IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
4766 for (int i = 0; i < p.Length; ++i) {
4767 if (p [i] != Parameter)
4768 continue;
4771 // Don't capture local parameters
4773 if (b == ec.CurrentBlock.Toplevel && !am.IsIterator)
4774 return true;
4776 if (IsRef) {
4777 ec.Report.Error (1628, loc,
4778 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4779 Name, am.ContainerType);
4782 if (pi.Parameter.HasAddressTaken)
4783 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4785 if (ec.IsVariableCapturingRequired && !b.Toplevel.IsExpressionTree) {
4786 AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
4787 storey.CaptureParameter (ec, this);
4790 return true;
4793 b = b.Parent;
4796 return true;
4799 public override int GetHashCode ()
4801 return Name.GetHashCode ();
4804 public override bool Equals (object obj)
4806 ParameterReference pr = obj as ParameterReference;
4807 if (pr == null)
4808 return false;
4810 return Name == pr.Name;
4813 public override void AddressOf (EmitContext ec, AddressOp mode)
4816 // ParameterReferences might already be a reference
4818 if (IsRef) {
4819 EmitLoad (ec);
4820 return;
4823 base.AddressOf (ec, mode);
4826 protected override void CloneTo (CloneContext clonectx, Expression target)
4828 // Nothing to clone
4831 public override Expression CreateExpressionTree (ResolveContext ec)
4833 HoistedVariable hv = GetHoistedVariable (ec);
4834 if (hv != null)
4835 return hv.CreateExpressionTree ();
4837 return Parameter.ExpressionTreeVariableReference ();
4841 // Notice that for ref/out parameters, the type exposed is not the
4842 // same type exposed externally.
4844 // for "ref int a":
4845 // externally we expose "int&"
4846 // here we expose "int".
4848 // We record this in "is_ref". This means that the type system can treat
4849 // the type as it is expected, but when we generate the code, we generate
4850 // the alternate kind of code.
4852 protected override Expression DoResolve (ResolveContext ec)
4854 if (!DoResolveBase (ec))
4855 return null;
4857 // HACK: Variables are not captured in probing mode
4858 if (ec.IsInProbingMode)
4859 return this;
4861 if (HasOutModifier && ec.DoFlowAnalysis &&
4862 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4863 return null;
4865 return this;
4868 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4870 if (!DoResolveBase (ec))
4871 return null;
4873 // HACK: parameters are not captured when probing is on
4874 if (!ec.IsInProbingMode)
4875 SetAssigned (ec);
4877 return this;
4880 static public void EmitLdArg (ILGenerator ig, int x)
4882 switch (x) {
4883 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4884 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4885 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4886 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4887 default:
4888 if (x > byte.MaxValue)
4889 ig.Emit (OpCodes.Ldarg, x);
4890 else
4891 ig.Emit (OpCodes.Ldarg_S, (byte) x);
4892 break;
4897 /// <summary>
4898 /// Invocation of methods or delegates.
4899 /// </summary>
4900 public class Invocation : ExpressionStatement
4902 protected Arguments arguments;
4903 protected Expression expr;
4904 protected MethodGroupExpr mg;
4905 bool arguments_resolved;
4908 // arguments is an ArrayList, but we do not want to typecast,
4909 // as it might be null.
4911 public Invocation (Expression expr, Arguments arguments)
4913 SimpleName sn = expr as SimpleName;
4914 if (sn != null)
4915 this.expr = sn.GetMethodGroup ();
4916 else
4917 this.expr = expr;
4919 this.arguments = arguments;
4920 if (expr != null)
4921 loc = expr.Location;
4924 public Invocation (Expression expr, Arguments arguments, bool arguments_resolved)
4925 : this (expr, arguments)
4927 this.arguments_resolved = arguments_resolved;
4930 public override Expression CreateExpressionTree (ResolveContext ec)
4932 Expression instance = mg.IsInstance ?
4933 mg.InstanceExpression.CreateExpressionTree (ec) :
4934 new NullLiteral (loc);
4936 var args = Arguments.CreateForExpressionTree (ec, arguments,
4937 instance,
4938 mg.CreateExpressionTree (ec));
4940 if (mg.IsBase)
4941 MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
4943 return CreateExpressionFactoryCall (ec, "Call", args);
4946 protected override Expression DoResolve (ResolveContext ec)
4948 Expression member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4949 if (member_expr == 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 = member_expr.Type;
4960 mg = member_expr as MethodGroupExpr;
4962 bool dynamic_member = TypeManager.IsDynamicType (expr_type);
4964 if (!dynamic_member) {
4965 Expression invoke = null;
4967 if (mg == null) {
4968 if (expr_type != null && TypeManager.IsDelegateType (expr_type)) {
4969 invoke = new DelegateInvocation (member_expr, arguments, loc);
4970 invoke = invoke.Resolve (ec);
4971 if (invoke == null || !dynamic_arg)
4972 return invoke;
4973 } else {
4974 MemberExpr me = member_expr as MemberExpr;
4975 if (me == null) {
4976 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
4977 return null;
4980 mg = ec.LookupExtensionMethod (me.Type, me.Name, loc);
4981 if (mg == null) {
4982 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4983 member_expr.GetSignatureForError ());
4984 return null;
4987 ((ExtensionMethodGroupExpr) mg).ExtensionExpression = me.InstanceExpression;
4991 if (invoke == null) {
4992 mg = DoResolveOverload (ec);
4993 if (mg == null)
4994 return null;
4998 if (dynamic_arg || dynamic_member)
4999 return DoResolveDynamic (ec, member_expr);
5001 var method = mg.BestCandidate;
5002 if (method != null) {
5003 type = TypeManager.TypeToCoreType (method.ReturnType);
5005 // TODO: this is a copy of mg.ResolveMemberAccess method
5006 Expression iexpr = mg.InstanceExpression;
5007 if (method.IsStatic) {
5008 if (iexpr == null ||
5009 iexpr is This || iexpr is EmptyExpression ||
5010 mg.IdenticalTypeName) {
5011 mg.InstanceExpression = null;
5012 } else {
5013 MemberExpr.error176 (ec, loc, mg.GetSignatureForError ());
5014 return null;
5016 } else {
5017 if (iexpr == null || iexpr == EmptyExpression.Null) {
5018 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
5024 // Only base will allow this invocation to happen.
5026 if (mg.IsBase && method.IsAbstract){
5027 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature (method));
5028 return null;
5031 if (arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
5032 if (mg.IsBase)
5033 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5034 else
5035 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5036 return null;
5039 IsSpecialMethodInvocation (ec, method, loc);
5041 if (mg.InstanceExpression != null)
5042 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
5044 eclass = ExprClass.Value;
5045 return this;
5048 Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
5050 Arguments args;
5051 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
5052 if (dmb != null) {
5053 args = dmb.Arguments;
5054 if (arguments != null)
5055 args.AddRange (arguments);
5056 } else if (mg == null) {
5057 if (arguments == null)
5058 args = new Arguments (1);
5059 else
5060 args = arguments;
5062 args.Insert (0, new Argument (memberExpr));
5063 this.expr = null;
5064 } else {
5065 if (mg.IsBase) {
5066 ec.Report.Error (1971, loc,
5067 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
5068 mg.Name);
5069 return null;
5072 args = arguments;
5074 if (mg.IsStatic != mg.IsInstance) {
5075 if (args == null)
5076 args = new Arguments (1);
5078 if (mg.IsStatic) {
5079 args.Insert (0, new Argument (new TypeOf (new TypeExpression (mg.DeclaringType, loc), loc).Resolve (ec), Argument.AType.DynamicTypeName));
5080 } else {
5081 MemberAccess ma = expr as MemberAccess;
5082 if (ma != null)
5083 args.Insert (0, new Argument (ma.Left.Resolve (ec)));
5084 else
5085 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5090 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5093 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5095 return mg.OverloadResolve (ec, ref arguments, false, loc);
5098 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
5100 if (!TypeManager.IsSpecialMethod (method.MetaInfo))
5101 return false;
5103 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName))
5104 return false;
5106 ec.Report.SymbolRelatedToPreviousError (method.MetaInfo);
5107 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5108 TypeManager.CSharpSignature (method.MetaInfo, true));
5110 return true;
5113 static Type[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
5115 AParametersCollection pd = mb.Parameters;
5117 Argument a = arguments [pd.Count - 1];
5118 Arglist list = (Arglist) a.Expr;
5120 return list.ArgumentTypes;
5123 /// <summary>
5124 /// This checks the ConditionalAttribute on the method
5125 /// </summary>
5126 public static bool IsMethodExcluded (MethodSpec method, Location loc)
5128 if (method.IsConstructor)
5129 return false;
5131 var mb = TypeManager.DropGenericMethodArguments (method.MetaInfo);
5132 if (TypeManager.IsBeingCompiled (mb)) {
5133 IMethodData md = TypeManager.GetMethod (mb);
5134 if (md != null)
5135 return md.IsExcluded ();
5137 // For some methods (generated by delegate class) GetMethod returns null
5138 // because they are not included in builder_to_method table
5139 return false;
5142 return AttributeTester.IsConditionalMethodExcluded (mb, loc);
5145 /// <remarks>
5146 /// is_base tells whether we want to force the use of the `call'
5147 /// opcode instead of using callvirt. Call is required to call
5148 /// a specific method, while callvirt will always use the most
5149 /// recent method in the vtable.
5151 /// is_static tells whether this is an invocation on a static method
5153 /// instance_expr is an expression that represents the instance
5154 /// it must be non-null if is_static is false.
5156 /// method is the method to invoke.
5158 /// Arguments is the list of arguments to pass to the method or constructor.
5159 /// </remarks>
5160 public static void EmitCall (EmitContext ec, bool is_base,
5161 Expression instance_expr,
5162 MethodSpec method, Arguments Arguments, Location loc)
5164 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
5167 // `dup_args' leaves an extra copy of the arguments on the stack
5168 // `omit_args' does not leave any arguments at all.
5169 // So, basically, you could make one call with `dup_args' set to true,
5170 // and then another with `omit_args' set to true, and the two calls
5171 // would have the same set of arguments. However, each argument would
5172 // only have been evaluated once.
5173 public static void EmitCall (EmitContext ec, bool is_base,
5174 Expression instance_expr,
5175 MethodSpec method, Arguments Arguments, Location loc,
5176 bool dup_args, bool omit_args)
5178 ILGenerator ig = ec.ig;
5179 bool struct_call = false;
5180 bool this_call = false;
5181 LocalTemporary this_arg = null;
5183 Type decl_type = method.DeclaringType;
5185 if (IsMethodExcluded (method, loc))
5186 return;
5188 bool is_static = method.IsStatic;
5189 if (!is_static){
5190 this_call = instance_expr is This;
5191 if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type))
5192 struct_call = true;
5195 // If this is ourselves, push "this"
5197 if (!omit_args) {
5198 Type t = null;
5199 Type iexpr_type = instance_expr.Type;
5202 // Push the instance expression
5204 if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
5206 // Special case: calls to a function declared in a
5207 // reference-type with a value-type argument need
5208 // to have their value boxed.
5209 if (TypeManager.IsStruct (decl_type) ||
5210 TypeManager.IsGenericParameter (iexpr_type)) {
5212 // If the expression implements IMemoryLocation, then
5213 // we can optimize and use AddressOf on the
5214 // return.
5216 // If not we have to use some temporary storage for
5217 // it.
5218 if (instance_expr is IMemoryLocation) {
5219 ((IMemoryLocation)instance_expr).
5220 AddressOf (ec, AddressOp.LoadStore);
5221 } else {
5222 LocalTemporary temp = new LocalTemporary (iexpr_type);
5223 instance_expr.Emit (ec);
5224 temp.Store (ec);
5225 temp.AddressOf (ec, AddressOp.Load);
5228 // avoid the overhead of doing this all the time.
5229 if (dup_args)
5230 t = TypeManager.GetReferenceType (iexpr_type);
5231 } else {
5232 instance_expr.Emit (ec);
5234 // FIXME: should use instance_expr is IMemoryLocation + constraint.
5235 // to help JIT to produce better code
5236 ig.Emit (OpCodes.Box, instance_expr.Type);
5237 t = TypeManager.object_type;
5239 } else {
5240 instance_expr.Emit (ec);
5241 t = instance_expr.Type;
5244 if (dup_args) {
5245 ig.Emit (OpCodes.Dup);
5246 if (Arguments != null && Arguments.Count != 0) {
5247 this_arg = new LocalTemporary (t);
5248 this_arg.Store (ec);
5254 if (!omit_args && Arguments != null)
5255 Arguments.Emit (ec, dup_args, this_arg);
5257 OpCode call_op;
5258 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
5259 call_op = OpCodes.Call;
5260 } else {
5261 call_op = OpCodes.Callvirt;
5263 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5264 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5267 if ((method.MetaInfo.CallingConvention & CallingConventions.VarArgs) != 0) {
5268 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5269 ig.EmitCall (call_op, (MethodInfo) method.MetaInfo, varargs_types);
5270 return;
5274 // If you have:
5275 // this.DoFoo ();
5276 // and DoFoo is not virtual, you can omit the callvirt,
5277 // because you don't need the null checking behavior.
5279 if (method.IsConstructor)
5280 ig.Emit (call_op, (ConstructorInfo) method.MetaInfo);
5281 else
5282 ig.Emit (call_op, (MethodInfo) method.MetaInfo);
5285 public override void Emit (EmitContext ec)
5287 mg.EmitCall (ec, arguments);
5290 public override void EmitStatement (EmitContext ec)
5292 Emit (ec);
5295 // Pop the return value if there is one
5297 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5298 ec.ig.Emit (OpCodes.Pop);
5301 protected override void CloneTo (CloneContext clonectx, Expression t)
5303 Invocation target = (Invocation) t;
5305 if (arguments != null)
5306 target.arguments = arguments.Clone (clonectx);
5308 target.expr = expr.Clone (clonectx);
5311 public override SLE.Expression MakeExpression (BuilderContext ctx)
5313 return MakeExpression (ctx, mg.InstanceExpression, (MethodSpec) mg, arguments);
5316 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
5318 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5319 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.MetaInfo, Arguments.MakeExpression (args, ctx));
5322 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5324 mg.MutateHoistedGenericType (storey);
5325 type = storey.MutateType (type);
5326 if (arguments != null) {
5327 arguments.MutateHoistedGenericType (storey);
5332 /// <summary>
5333 /// Implements the new expression
5334 /// </summary>
5335 public class New : ExpressionStatement, IMemoryLocation {
5336 protected Arguments Arguments;
5339 // During bootstrap, it contains the RequestedType,
5340 // but if `type' is not null, it *might* contain a NewDelegate
5341 // (because of field multi-initialization)
5343 protected Expression RequestedType;
5345 protected MethodGroupExpr method;
5347 bool is_type_parameter;
5349 public New (Expression requested_type, Arguments arguments, Location l)
5351 RequestedType = requested_type;
5352 Arguments = arguments;
5353 loc = l;
5356 /// <summary>
5357 /// Converts complex core type syntax like 'new int ()' to simple constant
5358 /// </summary>
5359 public static Constant Constantify (Type t)
5361 if (t == TypeManager.int32_type)
5362 return new IntConstant (0, Location.Null);
5363 if (t == TypeManager.uint32_type)
5364 return new UIntConstant (0, Location.Null);
5365 if (t == TypeManager.int64_type)
5366 return new LongConstant (0, Location.Null);
5367 if (t == TypeManager.uint64_type)
5368 return new ULongConstant (0, Location.Null);
5369 if (t == TypeManager.float_type)
5370 return new FloatConstant (0, Location.Null);
5371 if (t == TypeManager.double_type)
5372 return new DoubleConstant (0, Location.Null);
5373 if (t == TypeManager.short_type)
5374 return new ShortConstant (0, Location.Null);
5375 if (t == TypeManager.ushort_type)
5376 return new UShortConstant (0, Location.Null);
5377 if (t == TypeManager.sbyte_type)
5378 return new SByteConstant (0, Location.Null);
5379 if (t == TypeManager.byte_type)
5380 return new ByteConstant (0, Location.Null);
5381 if (t == TypeManager.char_type)
5382 return new CharConstant ('\0', Location.Null);
5383 if (t == TypeManager.bool_type)
5384 return new BoolConstant (false, Location.Null);
5385 if (t == TypeManager.decimal_type)
5386 return new DecimalConstant (0, Location.Null);
5387 if (TypeManager.IsEnumType (t))
5388 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5389 if (TypeManager.IsNullableType (t))
5390 return Nullable.LiftedNull.Create (t, Location.Null);
5392 return null;
5396 // Checks whether the type is an interface that has the
5397 // [ComImport, CoClass] attributes and must be treated
5398 // specially
5400 public Expression CheckComImport (ResolveContext ec)
5402 if (!type.IsInterface)
5403 return null;
5406 // Turn the call into:
5407 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5409 Type real_class = AttributeTester.GetCoClassAttribute (type);
5410 if (real_class == null)
5411 return null;
5413 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5414 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5415 return cast.Resolve (ec);
5418 public override Expression CreateExpressionTree (ResolveContext ec)
5420 Arguments args;
5421 if (method == null) {
5422 args = new Arguments (1);
5423 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5424 } else {
5425 args = Arguments.CreateForExpressionTree (ec,
5426 Arguments,
5427 method.CreateExpressionTree (ec));
5430 return CreateExpressionFactoryCall (ec, "New", args);
5433 protected override Expression DoResolve (ResolveContext ec)
5436 // The New DoResolve might be called twice when initializing field
5437 // expressions (see EmitFieldInitializers, the call to
5438 // GetInitializerExpression will perform a resolve on the expression,
5439 // and later the assign will trigger another resolution
5441 // This leads to bugs (#37014)
5443 if (type != null){
5444 if (RequestedType is NewDelegate)
5445 return RequestedType;
5446 return this;
5449 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5450 if (texpr == null)
5451 return null;
5453 type = texpr.Type;
5455 if (type.IsPointer) {
5456 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5457 TypeManager.CSharpName (type));
5458 return null;
5461 if (Arguments == null) {
5462 Constant c = Constantify (type);
5463 if (c != null)
5464 return ReducedExpression.Create (c.Resolve (ec), this);
5467 if (TypeManager.IsDelegateType (type)) {
5468 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5471 if (TypeManager.IsGenericParameter (type)) {
5472 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5474 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5475 ec.Report.Error (304, loc,
5476 "Cannot create an instance of the variable type '{0}' because it doesn't have the new() constraint",
5477 TypeManager.CSharpName (type));
5478 return null;
5481 if ((Arguments != null) && (Arguments.Count != 0)) {
5482 ec.Report.Error (417, loc,
5483 "`{0}': cannot provide arguments when creating an instance of a variable type",
5484 TypeManager.CSharpName (type));
5485 return null;
5488 if (TypeManager.activator_create_instance == null) {
5489 Type activator_type = TypeManager.CoreLookupType (ec.Compiler, "System", "Activator", MemberKind.Class, true);
5490 if (activator_type != null) {
5491 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5492 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5496 is_type_parameter = true;
5497 eclass = ExprClass.Value;
5498 return this;
5501 if (type.IsAbstract && type.IsSealed) {
5502 ec.Report.SymbolRelatedToPreviousError (type);
5503 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5504 return null;
5507 if (type.IsInterface || type.IsAbstract){
5508 if (!TypeManager.IsGenericType (type)) {
5509 RequestedType = CheckComImport (ec);
5510 if (RequestedType != null)
5511 return RequestedType;
5514 ec.Report.SymbolRelatedToPreviousError (type);
5515 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5516 return null;
5519 bool is_struct = TypeManager.IsStruct (type);
5520 eclass = ExprClass.Value;
5523 // SRE returns a match for .ctor () on structs (the object constructor),
5524 // so we have to manually ignore it.
5526 if (is_struct && Arguments == null)
5527 return this;
5529 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5530 Expression ml = MemberLookupFinal (ec, type, type, ConstructorInfo.ConstructorName,
5531 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5533 bool dynamic;
5534 if (Arguments != null) {
5535 Arguments.Resolve (ec, out dynamic);
5536 } else {
5537 dynamic = false;
5540 if (ml == null)
5541 return null;
5543 method = ml as MethodGroupExpr;
5544 if (method == null) {
5545 ml.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5546 return null;
5549 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5550 if (method == null)
5551 return null;
5553 if (dynamic) {
5554 Arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5555 return new DynamicConstructorBinder (type, Arguments, loc).Resolve (ec);
5558 return this;
5561 bool DoEmitTypeParameter (EmitContext ec)
5563 ILGenerator ig = ec.ig;
5565 MethodInfo ci = (MethodInfo) TypeManager.activator_create_instance.MetaInfo;
5566 ci = ci.MakeGenericMethod (new Type [] { type });
5568 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5569 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5570 ig.Emit (OpCodes.Call, ci);
5571 return true;
5574 // Allow DoEmit() to be called multiple times.
5575 // We need to create a new LocalTemporary each time since
5576 // you can't share LocalBuilders among ILGeneators.
5577 LocalTemporary temp = new LocalTemporary (type);
5579 Label label_activator = ig.DefineLabel ();
5580 Label label_end = ig.DefineLabel ();
5582 temp.AddressOf (ec, AddressOp.Store);
5583 ig.Emit (OpCodes.Initobj, type);
5585 temp.Emit (ec);
5586 ig.Emit (OpCodes.Box, type);
5587 ig.Emit (OpCodes.Brfalse, label_activator);
5589 temp.AddressOf (ec, AddressOp.Store);
5590 ig.Emit (OpCodes.Initobj, type);
5591 temp.Emit (ec);
5592 ig.Emit (OpCodes.Br_S, label_end);
5594 ig.MarkLabel (label_activator);
5596 ig.Emit (OpCodes.Call, ci);
5597 ig.MarkLabel (label_end);
5598 return true;
5602 // This Emit can be invoked in two contexts:
5603 // * As a mechanism that will leave a value on the stack (new object)
5604 // * As one that wont (init struct)
5606 // If we are dealing with a ValueType, we have a few
5607 // situations to deal with:
5609 // * The target is a ValueType, and we have been provided
5610 // the instance (this is easy, we are being assigned).
5612 // * The target of New is being passed as an argument,
5613 // to a boxing operation or a function that takes a
5614 // ValueType.
5616 // In this case, we need to create a temporary variable
5617 // that is the argument of New.
5619 // Returns whether a value is left on the stack
5621 // *** Implementation note ***
5623 // To benefit from this optimization, each assignable expression
5624 // has to manually cast to New and call this Emit.
5626 // TODO: It's worth to implement it for arrays and fields
5628 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5630 bool is_value_type = TypeManager.IsValueType (type);
5631 ILGenerator ig = ec.ig;
5632 VariableReference vr = target as VariableReference;
5634 if (target != null && is_value_type && (vr != null || method == null)) {
5635 target.AddressOf (ec, AddressOp.Store);
5636 } else if (vr != null && vr.IsRef) {
5637 vr.EmitLoad (ec);
5640 if (Arguments != null)
5641 Arguments.Emit (ec);
5643 if (is_value_type) {
5644 if (method == null) {
5645 ig.Emit (OpCodes.Initobj, type);
5646 return false;
5649 if (vr != null) {
5650 ig.Emit (OpCodes.Call, (ConstructorInfo) method.BestCandidate.MetaInfo);
5651 return false;
5655 if (is_type_parameter)
5656 return DoEmitTypeParameter (ec);
5658 ConstructorInfo ci = (ConstructorInfo) method.BestCandidate.MetaInfo;
5659 #if MS_COMPATIBLE
5660 if (TypeManager.IsGenericType (type) && type.IsGenericTypeDefinition)
5661 ci = TypeBuilder.GetConstructor (type, ci);
5662 #endif
5664 ig.Emit (OpCodes.Newobj, ci);
5665 return true;
5668 public override void Emit (EmitContext ec)
5670 LocalTemporary v = null;
5671 if (method == null && TypeManager.IsValueType (type)) {
5672 // TODO: Use temporary variable from pool
5673 v = new LocalTemporary (type);
5676 if (!Emit (ec, v))
5677 v.Emit (ec);
5680 public override void EmitStatement (EmitContext ec)
5682 LocalTemporary v = null;
5683 if (method == null && TypeManager.IsValueType (type)) {
5684 // TODO: Use temporary variable from pool
5685 v = new LocalTemporary (type);
5688 if (Emit (ec, v))
5689 ec.ig.Emit (OpCodes.Pop);
5692 public virtual bool HasInitializer {
5693 get {
5694 return false;
5698 public void AddressOf (EmitContext ec, AddressOp mode)
5700 EmitAddressOf (ec, mode);
5703 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5705 LocalTemporary value_target = new LocalTemporary (type);
5707 if (is_type_parameter) {
5708 DoEmitTypeParameter (ec);
5709 value_target.Store (ec);
5710 value_target.AddressOf (ec, mode);
5711 return value_target;
5714 if (!TypeManager.IsStruct (type)){
5716 // We throw an exception. So far, I believe we only need to support
5717 // value types:
5718 // foreach (int j in new StructType ())
5719 // see bug 42390
5721 throw new Exception ("AddressOf should not be used for classes");
5724 value_target.AddressOf (ec, AddressOp.Store);
5726 if (method == null) {
5727 ec.ig.Emit (OpCodes.Initobj, type);
5728 } else {
5729 if (Arguments != null)
5730 Arguments.Emit (ec);
5732 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method.BestCandidate.MetaInfo);
5735 value_target.AddressOf (ec, mode);
5736 return value_target;
5739 protected override void CloneTo (CloneContext clonectx, Expression t)
5741 New target = (New) t;
5743 target.RequestedType = RequestedType.Clone (clonectx);
5744 if (Arguments != null){
5745 target.Arguments = Arguments.Clone (clonectx);
5749 public override SLE.Expression MakeExpression (BuilderContext ctx)
5751 return SLE.Expression.New ((ConstructorInfo) method.BestCandidate.MetaInfo, Arguments.MakeExpression (Arguments, ctx));
5754 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5756 if (method != null) {
5757 method.MutateHoistedGenericType (storey);
5758 if (Arguments != null) {
5759 Arguments.MutateHoistedGenericType (storey);
5763 type = storey.MutateType (type);
5767 public class ArrayInitializer : ShimExpression
5769 List<Expression> elements;
5771 public ArrayInitializer (List<Expression> init, Location loc)
5772 : base (null)
5774 elements = init;
5777 public ArrayInitializer (int count, Location loc)
5778 : base (null)
5780 elements = new List<Expression> (count);
5783 public ArrayInitializer (Location loc)
5784 : this (4, loc)
5788 public void Add (Expression expr)
5790 elements.Add (expr);
5793 protected override void CloneTo (CloneContext clonectx, Expression t)
5795 var target = (ArrayInitializer) t;
5797 target.elements = new List<Expression> (elements.Count);
5798 foreach (var element in elements)
5799 target.elements.Add (element.Clone (clonectx));
5801 base.CloneTo (clonectx, t);
5804 public int Count {
5805 get { return elements.Count; }
5808 protected override Expression DoResolve (ResolveContext rc)
5810 throw new NotImplementedException ();
5813 public Expression this [int index] {
5814 get { return elements [index]; }
5818 /// <summary>
5819 /// 14.5.10.2: Represents an array creation expression.
5820 /// </summary>
5822 /// <remarks>
5823 /// There are two possible scenarios here: one is an array creation
5824 /// expression that specifies the dimensions and optionally the
5825 /// initialization data and the other which does not need dimensions
5826 /// specified but where initialization data is mandatory.
5827 /// </remarks>
5828 class ArrayCreation : Expression
5830 FullNamedExpression requested_base_type;
5831 ArrayInitializer initializers;
5834 // The list of Argument types.
5835 // This is used to construct the `newarray' or constructor signature
5837 protected List<Expression> arguments;
5839 protected Type array_element_type;
5840 bool expect_initializers = false;
5841 int num_arguments = 0;
5842 protected int dimensions;
5843 protected readonly string rank;
5844 Expression first_emit;
5845 LocalTemporary first_emit_temp;
5847 protected List<Expression> array_data;
5849 Dictionary<int, int> bounds;
5851 // The number of constants in array initializers
5852 int const_initializers_count;
5853 bool only_constant_initializers;
5855 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, string rank, ArrayInitializer initializers, Location l)
5857 this.requested_base_type = requested_base_type;
5858 this.initializers = initializers;
5859 this.rank = rank;
5860 loc = l;
5862 arguments = new List<Expression> (exprs);
5863 num_arguments = arguments.Count;
5866 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayInitializer initializers, Location l)
5868 this.requested_base_type = requested_base_type;
5869 this.initializers = initializers;
5870 this.rank = rank;
5871 loc = l;
5873 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5875 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5877 //dimensions = tmp.Length - 1;
5878 expect_initializers = true;
5881 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
5883 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
5886 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
5888 if (specified_dims) {
5889 Expression a = arguments [idx];
5890 a = a.Resolve (ec);
5891 if (a == null)
5892 return false;
5894 Constant c = a as Constant;
5895 if (c != null) {
5896 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Location);
5899 if (c == null) {
5900 ec.Report.Error (150, a.Location, "A constant value is expected");
5901 return false;
5904 int value = (int) c.GetValue ();
5906 if (value != probe.Count) {
5907 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value);
5908 return false;
5911 bounds [idx] = value;
5914 only_constant_initializers = true;
5915 for (int i = 0; i < probe.Count; ++i) {
5916 var o = probe [i];
5917 if (o is ArrayInitializer) {
5918 var sub_probe = o as ArrayInitializer;
5919 if (idx + 1 >= dimensions){
5920 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5921 return false;
5924 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
5925 if (!ret)
5926 return false;
5927 } else if (child_bounds > 1) {
5928 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
5929 } else {
5930 Expression element = ResolveArrayElement (ec, o);
5931 if (element == null)
5932 continue;
5934 // Initializers with the default values can be ignored
5935 Constant c = element as Constant;
5936 if (c != null) {
5937 if (c.IsDefaultInitializer (array_element_type)) {
5938 element = null;
5940 else {
5941 ++const_initializers_count;
5943 } else {
5944 only_constant_initializers = false;
5947 array_data.Add (element);
5951 return true;
5954 public override Expression CreateExpressionTree (ResolveContext ec)
5956 Arguments args;
5958 if (array_data == null) {
5959 args = new Arguments (arguments.Count + 1);
5960 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5961 foreach (Expression a in arguments)
5962 args.Add (new Argument (a.CreateExpressionTree (ec)));
5964 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
5967 if (dimensions > 1) {
5968 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5969 return null;
5972 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
5973 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5974 if (array_data != null) {
5975 for (int i = 0; i < array_data.Count; ++i) {
5976 Expression e = array_data [i];
5977 if (e == null)
5978 e = Convert.ImplicitConversion (ec, initializers [i], array_element_type, loc);
5980 args.Add (new Argument (e.CreateExpressionTree (ec)));
5984 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
5987 public void UpdateIndices ()
5989 int i = 0;
5990 for (var probe = initializers; probe != null;) {
5991 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
5992 Expression e = new IntConstant (probe.Count, Location.Null);
5993 arguments.Add (e);
5995 bounds [i++] = probe.Count;
5997 probe = (ArrayInitializer) probe[0];
5999 } else {
6000 Expression e = new IntConstant (probe.Count, Location.Null);
6001 arguments.Add (e);
6003 bounds [i++] = probe.Count;
6004 return;
6009 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
6011 element = element.Resolve (ec);
6012 if (element == null)
6013 return null;
6015 if (element is CompoundAssign.TargetExpression) {
6016 if (first_emit != null)
6017 throw new InternalErrorException ("Can only handle one mutator at a time");
6018 first_emit = element;
6019 element = first_emit_temp = new LocalTemporary (element.Type);
6022 return Convert.ImplicitConversionRequired (
6023 ec, element, array_element_type, loc);
6026 protected bool ResolveInitializers (ResolveContext ec)
6028 if (initializers == null) {
6029 return !expect_initializers;
6033 // We use this to store all the date values in the order in which we
6034 // will need to store them in the byte blob later
6036 array_data = new List<Expression> ();
6037 bounds = new Dictionary<int, int> ();
6039 if (arguments != null)
6040 return CheckIndices (ec, initializers, 0, true, dimensions);
6042 arguments = new List<Expression> ();
6044 if (!CheckIndices (ec, initializers, 0, false, dimensions))
6045 return false;
6047 UpdateIndices ();
6049 return true;
6053 // Resolved the type of the array
6055 bool ResolveArrayType (ResolveContext ec)
6057 if (requested_base_type is VarExpr) {
6058 ec.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6059 return false;
6062 StringBuilder array_qualifier = new StringBuilder (rank);
6065 // `In the first form allocates an array instace of the type that results
6066 // from deleting each of the individual expression from the expression list'
6068 if (num_arguments > 0) {
6069 array_qualifier.Append ("[");
6070 for (int i = num_arguments-1; i > 0; i--)
6071 array_qualifier.Append (",");
6072 array_qualifier.Append ("]");
6076 // Lookup the type
6078 TypeExpr array_type_expr;
6079 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6080 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6081 if (array_type_expr == null)
6082 return false;
6084 type = array_type_expr.Type;
6085 if (!type.IsArray) {
6086 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6087 return false;
6090 array_element_type = TypeManager.GetElementType (type);
6091 dimensions = type.GetArrayRank ();
6093 return true;
6096 protected override Expression DoResolve (ResolveContext ec)
6098 if (type != null)
6099 return this;
6101 if (!ResolveArrayType (ec))
6102 return null;
6105 // First step is to validate the initializers and fill
6106 // in any missing bits
6108 if (!ResolveInitializers (ec))
6109 return null;
6111 for (int i = 0; i < arguments.Count; ++i) {
6112 Expression e = arguments[i].Resolve (ec);
6113 if (e == null)
6114 continue;
6116 arguments [i] = ConvertExpressionToArrayIndex (ec, e);
6119 eclass = ExprClass.Value;
6120 return this;
6123 MethodInfo GetArrayMethod (EmitContext ec, int arguments)
6125 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
6127 Type[] arg_types = new Type[arguments];
6128 for (int i = 0; i < arguments; i++)
6129 arg_types[i] = TypeManager.int32_type;
6131 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6132 arg_types);
6134 if (mi == null) {
6135 ec.Report.Error (-6, "New invocation: Can not find a constructor for " +
6136 "this argument list");
6137 return null;
6140 return mi;
6143 byte [] MakeByteBlob ()
6145 int factor;
6146 byte [] data;
6147 byte [] element;
6148 int count = array_data.Count;
6150 Type element_type = array_element_type;
6151 if (TypeManager.IsEnumType (element_type))
6152 element_type = TypeManager.GetEnumUnderlyingType (element_type);
6154 factor = GetTypeSize (element_type);
6155 if (factor == 0)
6156 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6158 data = new byte [(count * factor + 3) & ~3];
6159 int idx = 0;
6161 for (int i = 0; i < count; ++i) {
6162 object v = array_data [i];
6164 if (v is EnumConstant)
6165 v = ((EnumConstant) v).Child;
6167 if (v is Constant && !(v is StringConstant))
6168 v = ((Constant) v).GetValue ();
6169 else {
6170 idx += factor;
6171 continue;
6174 if (element_type == TypeManager.int64_type){
6175 if (!(v is Expression)){
6176 long val = (long) v;
6178 for (int j = 0; j < factor; ++j) {
6179 data [idx + j] = (byte) (val & 0xFF);
6180 val = (val >> 8);
6183 } else if (element_type == TypeManager.uint64_type){
6184 if (!(v is Expression)){
6185 ulong val = (ulong) v;
6187 for (int j = 0; j < factor; ++j) {
6188 data [idx + j] = (byte) (val & 0xFF);
6189 val = (val >> 8);
6192 } else if (element_type == TypeManager.float_type) {
6193 if (!(v is Expression)){
6194 element = BitConverter.GetBytes ((float) v);
6196 for (int j = 0; j < factor; ++j)
6197 data [idx + j] = element [j];
6198 if (!BitConverter.IsLittleEndian)
6199 System.Array.Reverse (data, idx, 4);
6201 } else if (element_type == TypeManager.double_type) {
6202 if (!(v is Expression)){
6203 element = BitConverter.GetBytes ((double) v);
6205 for (int j = 0; j < factor; ++j)
6206 data [idx + j] = element [j];
6208 // FIXME: Handle the ARM float format.
6209 if (!BitConverter.IsLittleEndian)
6210 System.Array.Reverse (data, idx, 8);
6212 } else if (element_type == TypeManager.char_type){
6213 if (!(v is Expression)){
6214 int val = (int) ((char) v);
6216 data [idx] = (byte) (val & 0xff);
6217 data [idx+1] = (byte) (val >> 8);
6219 } else if (element_type == TypeManager.short_type){
6220 if (!(v is Expression)){
6221 int val = (int) ((short) v);
6223 data [idx] = (byte) (val & 0xff);
6224 data [idx+1] = (byte) (val >> 8);
6226 } else if (element_type == TypeManager.ushort_type){
6227 if (!(v is Expression)){
6228 int val = (int) ((ushort) v);
6230 data [idx] = (byte) (val & 0xff);
6231 data [idx+1] = (byte) (val >> 8);
6233 } else if (element_type == TypeManager.int32_type) {
6234 if (!(v is Expression)){
6235 int val = (int) v;
6237 data [idx] = (byte) (val & 0xff);
6238 data [idx+1] = (byte) ((val >> 8) & 0xff);
6239 data [idx+2] = (byte) ((val >> 16) & 0xff);
6240 data [idx+3] = (byte) (val >> 24);
6242 } else if (element_type == TypeManager.uint32_type) {
6243 if (!(v is Expression)){
6244 uint val = (uint) v;
6246 data [idx] = (byte) (val & 0xff);
6247 data [idx+1] = (byte) ((val >> 8) & 0xff);
6248 data [idx+2] = (byte) ((val >> 16) & 0xff);
6249 data [idx+3] = (byte) (val >> 24);
6251 } else if (element_type == TypeManager.sbyte_type) {
6252 if (!(v is Expression)){
6253 sbyte val = (sbyte) v;
6254 data [idx] = (byte) val;
6256 } else if (element_type == TypeManager.byte_type) {
6257 if (!(v is Expression)){
6258 byte val = (byte) v;
6259 data [idx] = (byte) val;
6261 } else if (element_type == TypeManager.bool_type) {
6262 if (!(v is Expression)){
6263 bool val = (bool) v;
6264 data [idx] = (byte) (val ? 1 : 0);
6266 } else if (element_type == TypeManager.decimal_type){
6267 if (!(v is Expression)){
6268 int [] bits = Decimal.GetBits ((decimal) v);
6269 int p = idx;
6271 // FIXME: For some reason, this doesn't work on the MS runtime.
6272 int [] nbits = new int [4];
6273 nbits [0] = bits [3];
6274 nbits [1] = bits [2];
6275 nbits [2] = bits [0];
6276 nbits [3] = bits [1];
6278 for (int j = 0; j < 4; j++){
6279 data [p++] = (byte) (nbits [j] & 0xff);
6280 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6281 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6282 data [p++] = (byte) (nbits [j] >> 24);
6285 } else {
6286 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6289 idx += factor;
6292 return data;
6295 #if NET_4_0
6296 public override SLE.Expression MakeExpression (BuilderContext ctx)
6298 var initializers = new SLE.Expression [array_data.Count];
6299 for (var i = 0; i < initializers.Length; i++) {
6300 if (array_data [i] == null)
6301 initializers [i] = SLE.Expression.Default (array_element_type);
6302 else
6303 initializers [i] = array_data [i].MakeExpression (ctx);
6306 return SLE.Expression.NewArrayInit (array_element_type, initializers);
6308 #endif
6310 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6312 array_element_type = storey.MutateType (array_element_type);
6313 type = storey.MutateType (type);
6314 if (arguments != null) {
6315 foreach (Expression e in arguments)
6316 e.MutateHoistedGenericType (storey);
6319 if (array_data != null) {
6320 foreach (Expression e in array_data) {
6321 // Don't mutate values optimized away
6322 if (e == null)
6323 continue;
6325 e.MutateHoistedGenericType (storey);
6331 // Emits the initializers for the array
6333 void EmitStaticInitializers (EmitContext ec)
6335 // FIXME: This should go to Resolve !
6336 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6337 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6338 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6339 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6340 if (TypeManager.void_initializearray_array_fieldhandle == null)
6341 return;
6345 // First, the static data
6347 FieldBuilder fb;
6348 ILGenerator ig = ec.ig;
6350 byte [] data = MakeByteBlob ();
6352 fb = RootContext.MakeStaticData (data);
6354 ig.Emit (OpCodes.Dup);
6355 ig.Emit (OpCodes.Ldtoken, fb);
6356 ig.Emit (OpCodes.Call, (MethodInfo) TypeManager.void_initializearray_array_fieldhandle.MetaInfo);
6360 // Emits pieces of the array that can not be computed at compile
6361 // time (variables and string locations).
6363 // This always expect the top value on the stack to be the array
6365 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6367 ILGenerator ig = ec.ig;
6368 int dims = bounds.Count;
6369 int [] current_pos = new int [dims];
6371 MethodInfo set = null;
6373 if (dims != 1){
6374 Type [] args = new Type [dims + 1];
6376 for (int j = 0; j < dims; j++)
6377 args [j] = TypeManager.int32_type;
6378 args [dims] = array_element_type;
6380 set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
6381 type, "Set",
6382 CallingConventions.HasThis | CallingConventions.Standard,
6383 TypeManager.void_type, args);
6386 for (int i = 0; i < array_data.Count; i++){
6388 Expression e = array_data [i];
6390 // Constant can be initialized via StaticInitializer
6391 if (e != null && !(!emitConstants && e is Constant)) {
6392 Type etype = e.Type;
6394 ig.Emit (OpCodes.Dup);
6396 for (int idx = 0; idx < dims; idx++)
6397 IntConstant.EmitInt (ig, current_pos [idx]);
6400 // If we are dealing with a struct, get the
6401 // address of it, so we can store it.
6403 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6404 (!TypeManager.IsBuiltinOrEnum (etype) ||
6405 etype == TypeManager.decimal_type)) {
6407 ig.Emit (OpCodes.Ldelema, etype);
6410 e.Emit (ec);
6412 if (dims == 1) {
6413 bool is_stobj, has_type_arg;
6414 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6415 if (is_stobj)
6416 ig.Emit (OpCodes.Stobj, etype);
6417 else if (has_type_arg)
6418 ig.Emit (op, etype);
6419 else
6420 ig.Emit (op);
6421 } else
6422 ig.Emit (OpCodes.Call, set);
6427 // Advance counter
6429 for (int j = dims - 1; j >= 0; j--){
6430 current_pos [j]++;
6431 if (current_pos [j] < bounds [j])
6432 break;
6433 current_pos [j] = 0;
6438 public override void Emit (EmitContext ec)
6440 ILGenerator ig = ec.ig;
6442 if (first_emit != null) {
6443 first_emit.Emit (ec);
6444 first_emit_temp.Store (ec);
6447 foreach (Expression e in arguments)
6448 e.Emit (ec);
6450 if (arguments.Count == 1)
6451 ig.Emit (OpCodes.Newarr, TypeManager.TypeToReflectionType (array_element_type));
6452 else {
6453 ig.Emit (OpCodes.Newobj, GetArrayMethod (ec, arguments.Count));
6456 if (initializers == null)
6457 return;
6459 // Emit static initializer for arrays which have contain more than 2 items and
6460 // the static initializer will initialize at least 25% of array values.
6461 // NOTE: const_initializers_count does not contain default constant values.
6462 if (const_initializers_count > 2 && const_initializers_count * 4 > (array_data.Count) &&
6463 (TypeManager.IsPrimitiveType (array_element_type) || TypeManager.IsEnumType (array_element_type))) {
6464 EmitStaticInitializers (ec);
6466 if (!only_constant_initializers)
6467 EmitDynamicInitializers (ec, false);
6468 } else {
6469 EmitDynamicInitializers (ec, true);
6472 if (first_emit_temp != null)
6473 first_emit_temp.Release (ec);
6476 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
6478 if (arguments.Count != 1) {
6479 // ec.Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6480 return base.GetAttributableValue (ec, null, out value);
6483 if (array_data == null) {
6484 Expression arg = arguments [0];
6485 object arg_value;
6486 if (arg.GetAttributableValue (ec, arg.Type, out arg_value) && arg_value is int && (int)arg_value == 0) {
6487 value = Array.CreateInstance (array_element_type, 0);
6488 return true;
6491 // ec.Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6492 return base.GetAttributableValue (ec, null, out value);
6495 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6496 object element_value;
6497 for (int i = 0; i < ret.Length; ++i)
6499 Expression e = array_data [i];
6501 // Is null when an initializer is optimized (value == predefined value)
6502 if (e == null)
6503 continue;
6505 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6506 value = null;
6507 return false;
6509 ret.SetValue (element_value, i);
6511 value = ret;
6512 return true;
6515 protected override void CloneTo (CloneContext clonectx, Expression t)
6517 ArrayCreation target = (ArrayCreation) t;
6519 if (requested_base_type != null)
6520 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6522 if (arguments != null){
6523 target.arguments = new List<Expression> (arguments.Count);
6524 foreach (Expression e in arguments)
6525 target.arguments.Add (e.Clone (clonectx));
6528 if (initializers != null)
6529 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
6534 // Represents an implicitly typed array epxression
6536 class ImplicitlyTypedArrayCreation : ArrayCreation
6538 public ImplicitlyTypedArrayCreation (string rank, ArrayInitializer initializers, Location loc)
6539 : base (null, rank, initializers, loc)
6541 if (rank.Length > 2) {
6542 while (rank [++dimensions] == ',');
6543 } else {
6544 dimensions = 1;
6548 protected override Expression DoResolve (ResolveContext ec)
6550 if (type != null)
6551 return this;
6553 if (!ResolveInitializers (ec))
6554 return null;
6556 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6557 array_element_type == TypeManager.void_type || array_element_type == InternalType.AnonymousMethod ||
6558 array_element_type == InternalType.MethodGroup ||
6559 arguments.Count != dimensions) {
6560 Error_NoBestType (ec);
6561 return null;
6565 // At this point we found common base type for all initializer elements
6566 // but we have to be sure that all static initializer elements are of
6567 // same type
6569 UnifyInitializerElement (ec);
6571 type = TypeManager.GetConstructedType (array_element_type, rank);
6572 eclass = ExprClass.Value;
6573 return this;
6576 void Error_NoBestType (ResolveContext ec)
6578 ec.Report.Error (826, loc,
6579 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6583 // Converts static initializer only
6585 void UnifyInitializerElement (ResolveContext ec)
6587 for (int i = 0; i < array_data.Count; ++i) {
6588 Expression e = (Expression)array_data[i];
6589 if (e != null)
6590 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6594 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6596 element = element.Resolve (ec);
6597 if (element == null)
6598 return null;
6600 if (array_element_type == null) {
6601 if (element.Type != TypeManager.null_type)
6602 array_element_type = element.Type;
6604 return element;
6607 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6608 return element;
6611 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6612 array_element_type = element.Type;
6613 return element;
6616 Error_NoBestType (ec);
6617 return null;
6621 public sealed class CompilerGeneratedThis : This
6623 public static This Instance = new CompilerGeneratedThis ();
6625 private CompilerGeneratedThis ()
6626 : base (Location.Null)
6630 public CompilerGeneratedThis (Type type, Location loc)
6631 : base (loc)
6633 this.type = type;
6636 protected override Expression DoResolve (ResolveContext ec)
6638 eclass = ExprClass.Variable;
6639 if (type == null)
6640 type = ec.CurrentType;
6642 is_struct = type.IsValueType;
6643 return this;
6646 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6648 return null;
6652 /// <summary>
6653 /// Represents the `this' construct
6654 /// </summary>
6656 public class This : VariableReference
6658 sealed class ThisVariable : ILocalVariable
6660 public static readonly ILocalVariable Instance = new ThisVariable ();
6662 public void Emit (EmitContext ec)
6664 ec.ig.Emit (OpCodes.Ldarg_0);
6667 public void EmitAssign (EmitContext ec)
6669 throw new InvalidOperationException ();
6672 public void EmitAddressOf (EmitContext ec)
6674 ec.ig.Emit (OpCodes.Ldarg_0);
6678 Block block;
6679 VariableInfo variable_info;
6680 protected bool is_struct;
6682 public This (Block block, Location loc)
6684 this.loc = loc;
6685 this.block = block;
6688 public This (Location loc)
6690 this.loc = loc;
6693 public override VariableInfo VariableInfo {
6694 get { return variable_info; }
6697 public override bool IsFixed {
6698 get { return false; }
6701 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6703 if (ae == null)
6704 return null;
6706 AnonymousMethodStorey storey = ae.Storey;
6707 while (storey != null) {
6708 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6709 if (temp == null)
6710 return storey.HoistedThis;
6712 storey = temp;
6715 return null;
6718 public override bool IsRef {
6719 get { return is_struct; }
6722 protected override ILocalVariable Variable {
6723 get { return ThisVariable.Instance; }
6726 public static bool IsThisAvailable (ResolveContext ec)
6728 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
6729 return false;
6731 if (ec.CurrentAnonymousMethod == null)
6732 return true;
6734 if (ec.CurrentType.IsValueType && ec.CurrentIterator == null)
6735 return false;
6737 return true;
6740 public bool ResolveBase (ResolveContext ec)
6742 eclass = ExprClass.Variable;
6743 type = ec.CurrentType;
6745 if (!IsThisAvailable (ec)) {
6746 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6747 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6748 } else if (ec.CurrentAnonymousMethod != null) {
6749 ec.Report.Error (1673, loc,
6750 "Anonymous methods inside structs cannot access instance members of `this'. " +
6751 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6752 } else {
6753 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6757 is_struct = type.IsValueType;
6759 if (block != null) {
6760 if (block.Toplevel.ThisVariable != null)
6761 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6763 AnonymousExpression am = ec.CurrentAnonymousMethod;
6764 if (am != null && ec.IsVariableCapturingRequired) {
6765 am.SetHasThisAccess ();
6769 return true;
6773 // Called from Invocation to check if the invocation is correct
6775 public override void CheckMarshalByRefAccess (ResolveContext ec)
6777 if ((variable_info != null) && !(TypeManager.IsStruct (type) && ec.OmitStructFlowAnalysis) &&
6778 !variable_info.IsAssigned (ec)) {
6779 ec.Report.Error (188, loc,
6780 "The `this' object cannot be used before all of its fields are assigned to");
6781 variable_info.SetAssigned (ec);
6785 public override Expression CreateExpressionTree (ResolveContext ec)
6787 Arguments args = new Arguments (1);
6788 args.Add (new Argument (this));
6790 // Use typeless constant for ldarg.0 to save some
6791 // space and avoid problems with anonymous stories
6792 return CreateExpressionFactoryCall (ec, "Constant", args);
6795 protected override Expression DoResolve (ResolveContext ec)
6797 ResolveBase (ec);
6798 return this;
6801 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6803 if (!ResolveBase (ec))
6804 return null;
6806 if (variable_info != null)
6807 variable_info.SetAssigned (ec);
6809 if (ec.CurrentType.IsClass){
6810 if (right_side == EmptyExpression.UnaryAddress)
6811 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6812 else if (right_side == EmptyExpression.OutAccess.Instance)
6813 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6814 else
6815 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6818 return this;
6821 public override int GetHashCode()
6823 return block.GetHashCode ();
6826 public override string Name {
6827 get { return "this"; }
6830 public override bool Equals (object obj)
6832 This t = obj as This;
6833 if (t == null)
6834 return false;
6836 return block == t.block;
6839 protected override void CloneTo (CloneContext clonectx, Expression t)
6841 This target = (This) t;
6843 target.block = clonectx.LookupBlock (block);
6846 public override void SetHasAddressTaken ()
6848 // Nothing
6852 /// <summary>
6853 /// Represents the `__arglist' construct
6854 /// </summary>
6855 public class ArglistAccess : Expression
6857 public ArglistAccess (Location loc)
6859 this.loc = loc;
6862 public override Expression CreateExpressionTree (ResolveContext ec)
6864 throw new NotSupportedException ("ET");
6867 protected override Expression DoResolve (ResolveContext ec)
6869 eclass = ExprClass.Variable;
6870 type = TypeManager.runtime_argument_handle_type;
6872 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.Toplevel.Parameters.HasArglist) {
6873 ec.Report.Error (190, loc,
6874 "The __arglist construct is valid only within a variable argument method");
6877 return this;
6880 public override void Emit (EmitContext ec)
6882 ec.ig.Emit (OpCodes.Arglist);
6885 protected override void CloneTo (CloneContext clonectx, Expression target)
6887 // nothing.
6891 /// <summary>
6892 /// Represents the `__arglist (....)' construct
6893 /// </summary>
6894 class Arglist : Expression
6896 Arguments Arguments;
6898 public Arglist (Location loc)
6899 : this (null, loc)
6903 public Arglist (Arguments args, Location l)
6905 Arguments = args;
6906 loc = l;
6909 public Type[] ArgumentTypes {
6910 get {
6911 if (Arguments == null)
6912 return Type.EmptyTypes;
6914 Type[] retval = new Type [Arguments.Count];
6915 for (int i = 0; i < retval.Length; i++)
6916 retval [i] = Arguments [i].Expr.Type;
6918 return retval;
6922 public override Expression CreateExpressionTree (ResolveContext ec)
6924 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6925 return null;
6928 protected override Expression DoResolve (ResolveContext ec)
6930 eclass = ExprClass.Variable;
6931 type = InternalType.Arglist;
6932 if (Arguments != null) {
6933 bool dynamic; // Can be ignored as there is always only 1 overload
6934 Arguments.Resolve (ec, out dynamic);
6937 return this;
6940 public override void Emit (EmitContext ec)
6942 if (Arguments != null)
6943 Arguments.Emit (ec);
6946 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6948 if (Arguments != null)
6949 Arguments.MutateHoistedGenericType (storey);
6952 protected override void CloneTo (CloneContext clonectx, Expression t)
6954 Arglist target = (Arglist) t;
6956 if (Arguments != null)
6957 target.Arguments = Arguments.Clone (clonectx);
6961 /// <summary>
6962 /// Implements the typeof operator
6963 /// </summary>
6964 public class TypeOf : Expression {
6965 Expression QueriedType;
6966 protected Type typearg;
6968 public TypeOf (Expression queried_type, Location l)
6970 QueriedType = queried_type;
6971 loc = l;
6974 public override Expression CreateExpressionTree (ResolveContext ec)
6976 Arguments args = new Arguments (2);
6977 args.Add (new Argument (this));
6978 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6979 return CreateExpressionFactoryCall (ec, "Constant", args);
6982 protected override Expression DoResolve (ResolveContext ec)
6984 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6985 if (texpr == null)
6986 return null;
6988 typearg = texpr.Type;
6990 if (typearg == TypeManager.void_type) {
6991 ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6992 } else if (typearg.IsPointer && !ec.IsUnsafe){
6993 UnsafeError (ec, loc);
6994 } else if (texpr is DynamicTypeExpr) {
6995 ec.Report.Error (1962, QueriedType.Location,
6996 "The typeof operator cannot be used on the dynamic type");
6999 type = TypeManager.type_type;
7001 return DoResolveBase ();
7004 protected Expression DoResolveBase ()
7006 if (TypeManager.system_type_get_type_from_handle == null) {
7007 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
7008 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
7011 // Even though what is returned is a type object, it's treated as a value by the compiler.
7012 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7013 eclass = ExprClass.Value;
7014 return this;
7017 public override void Emit (EmitContext ec)
7019 ec.ig.Emit (OpCodes.Ldtoken, TypeManager.TypeToReflectionType (typearg));
7020 ec.ig.Emit (OpCodes.Call, (MethodInfo) TypeManager.system_type_get_type_from_handle.MetaInfo);
7023 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
7025 if (TypeManager.ContainsGenericParameters (typearg) &&
7026 !TypeManager.IsGenericTypeDefinition (typearg)) {
7027 ec.Report.SymbolRelatedToPreviousError (typearg);
7028 ec.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7029 TypeManager.CSharpName (typearg));
7030 value = null;
7031 return false;
7034 if (value_type == TypeManager.object_type) {
7035 value = (object)typearg;
7036 return true;
7038 value = typearg;
7039 return true;
7042 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7044 if (!TypeManager.IsGenericTypeDefinition (typearg))
7045 typearg = storey.MutateType (typearg);
7048 public Type TypeArgument {
7049 get {
7050 return typearg;
7054 protected override void CloneTo (CloneContext clonectx, Expression t)
7056 TypeOf target = (TypeOf) t;
7057 if (QueriedType != null)
7058 target.QueriedType = QueriedType.Clone (clonectx);
7062 /// <summary>
7063 /// Implements the `typeof (void)' operator
7064 /// </summary>
7065 public class TypeOfVoid : TypeOf {
7066 public TypeOfVoid (Location l) : base (null, l)
7068 loc = l;
7071 protected override Expression DoResolve (ResolveContext ec)
7073 type = TypeManager.type_type;
7074 typearg = TypeManager.void_type;
7076 return DoResolveBase ();
7080 class TypeOfMethod : TypeOfMember<MethodSpec>
7082 public TypeOfMethod (MethodSpec method, Location loc)
7083 : base (method, loc)
7087 protected override Expression DoResolve (ResolveContext ec)
7089 if (member.IsConstructor) {
7090 type = TypeManager.ctorinfo_type;
7091 if (type == null)
7092 type = TypeManager.ctorinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", "ConstructorInfo", MemberKind.Class, true);
7093 } else {
7094 type = TypeManager.methodinfo_type;
7095 if (type == null)
7096 type = TypeManager.methodinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", "MethodInfo", MemberKind.Class, true);
7099 return base.DoResolve (ec);
7102 public override void Emit (EmitContext ec)
7104 if (member.IsConstructor)
7105 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) member.MetaInfo);
7106 else
7107 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) member.MetaInfo);
7109 base.Emit (ec);
7110 ec.ig.Emit (OpCodes.Castclass, type);
7113 protected override string GetMethodName {
7114 get { return "GetMethodFromHandle"; }
7117 protected override string RuntimeHandleName {
7118 get { return "RuntimeMethodHandle"; }
7121 protected override MethodSpec TypeFromHandle {
7122 get {
7123 return TypeManager.methodbase_get_type_from_handle;
7125 set {
7126 TypeManager.methodbase_get_type_from_handle = value;
7130 protected override MethodSpec TypeFromHandleGeneric {
7131 get {
7132 return TypeManager.methodbase_get_type_from_handle_generic;
7134 set {
7135 TypeManager.methodbase_get_type_from_handle_generic = value;
7139 protected override string TypeName {
7140 get { return "MethodBase"; }
7144 abstract class TypeOfMember<T> : Expression where T : MemberSpec
7146 protected readonly T member;
7148 protected TypeOfMember (T member, Location loc)
7150 this.member = member;
7151 this.loc = loc;
7154 public override Expression CreateExpressionTree (ResolveContext ec)
7156 Arguments args = new Arguments (2);
7157 args.Add (new Argument (this));
7158 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7159 return CreateExpressionFactoryCall (ec, "Constant", args);
7162 protected override Expression DoResolve (ResolveContext ec)
7164 bool is_generic = TypeManager.IsGenericType (member.DeclaringType);
7165 var mi = is_generic ? TypeFromHandleGeneric : TypeFromHandle;
7167 if (mi == null) {
7168 Type t = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", TypeName, MemberKind.Class, true);
7169 Type handle_type = TypeManager.CoreLookupType (ec.Compiler, "System", RuntimeHandleName, MemberKind.Class, true);
7171 if (t == null || handle_type == null)
7172 return null;
7174 mi = TypeManager.GetPredefinedMethod (t, GetMethodName, loc,
7175 is_generic ?
7176 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7177 new Type[] { handle_type } );
7179 if (is_generic)
7180 TypeFromHandleGeneric = mi;
7181 else
7182 TypeFromHandle = mi;
7185 eclass = ExprClass.Value;
7186 return this;
7189 public override void Emit (EmitContext ec)
7191 bool is_generic = TypeManager.IsGenericType (member.DeclaringType);
7192 MethodSpec mi;
7193 if (is_generic) {
7194 mi = TypeFromHandleGeneric;
7195 ec.ig.Emit (OpCodes.Ldtoken, member.DeclaringType);
7196 } else {
7197 mi = TypeFromHandle;
7200 ec.ig.Emit (OpCodes.Call, (MethodInfo) mi.MetaInfo);
7203 protected abstract string GetMethodName { get; }
7204 protected abstract string RuntimeHandleName { get; }
7205 protected abstract MethodSpec TypeFromHandle { get; set; }
7206 protected abstract MethodSpec TypeFromHandleGeneric { get; set; }
7207 protected abstract string TypeName { get; }
7210 class TypeOfField : TypeOfMember<FieldSpec>
7212 public TypeOfField (FieldSpec field, Location loc)
7213 : base (field, loc)
7217 protected override Expression DoResolve (ResolveContext ec)
7219 if (TypeManager.fieldinfo_type == null)
7220 TypeManager.fieldinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", TypeName, MemberKind.Class, true);
7222 type = TypeManager.fieldinfo_type;
7223 return base.DoResolve (ec);
7226 public override void Emit (EmitContext ec)
7228 ec.ig.Emit (OpCodes.Ldtoken, member.MetaInfo);
7229 base.Emit (ec);
7232 protected override string GetMethodName {
7233 get { return "GetFieldFromHandle"; }
7236 protected override string RuntimeHandleName {
7237 get { return "RuntimeFieldHandle"; }
7240 protected override MethodSpec TypeFromHandle {
7241 get {
7242 return TypeManager.fieldinfo_get_field_from_handle;
7244 set {
7245 TypeManager.fieldinfo_get_field_from_handle = value;
7249 protected override MethodSpec TypeFromHandleGeneric {
7250 get {
7251 return TypeManager.fieldinfo_get_field_from_handle_generic;
7253 set {
7254 TypeManager.fieldinfo_get_field_from_handle_generic = value;
7258 protected override string TypeName {
7259 get { return "FieldInfo"; }
7263 /// <summary>
7264 /// Implements the sizeof expression
7265 /// </summary>
7266 public class SizeOf : Expression {
7267 readonly Expression QueriedType;
7268 Type type_queried;
7270 public SizeOf (Expression queried_type, Location l)
7272 this.QueriedType = queried_type;
7273 loc = l;
7276 public override Expression CreateExpressionTree (ResolveContext ec)
7278 Error_PointerInsideExpressionTree (ec);
7279 return null;
7282 protected override Expression DoResolve (ResolveContext ec)
7284 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7285 if (texpr == null)
7286 return null;
7288 type_queried = texpr.Type;
7289 if (TypeManager.IsEnumType (type_queried))
7290 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7292 int size_of = GetTypeSize (type_queried);
7293 if (size_of > 0) {
7294 return new IntConstant (size_of, loc).Resolve (ec);
7297 if (!TypeManager.VerifyUnmanaged (ec.Compiler, type_queried, loc)){
7298 return null;
7301 if (!ec.IsUnsafe) {
7302 ec.Report.Error (233, loc,
7303 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7304 TypeManager.CSharpName (type_queried));
7307 type = TypeManager.int32_type;
7308 eclass = ExprClass.Value;
7309 return this;
7312 public override void Emit (EmitContext ec)
7314 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7317 protected override void CloneTo (CloneContext clonectx, Expression t)
7322 /// <summary>
7323 /// Implements the qualified-alias-member (::) expression.
7324 /// </summary>
7325 public class QualifiedAliasMember : MemberAccess
7327 readonly string alias;
7328 public static readonly string GlobalAlias = "global";
7330 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7331 : base (null, identifier, targs, l)
7333 this.alias = alias;
7336 public QualifiedAliasMember (string alias, string identifier, Location l)
7337 : base (null, identifier, l)
7339 this.alias = alias;
7342 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7344 if (alias == GlobalAlias) {
7345 expr = GlobalRootNamespace.Instance;
7346 return base.ResolveAsTypeStep (ec, silent);
7349 int errors = ec.Compiler.Report.Errors;
7350 expr = ec.LookupNamespaceAlias (alias);
7351 if (expr == null) {
7352 if (errors == ec.Compiler.Report.Errors)
7353 ec.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7354 return null;
7357 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7358 if (fne == null)
7359 return null;
7361 if (expr.eclass == ExprClass.Type) {
7362 if (!silent) {
7363 ec.Compiler.Report.Error (431, loc,
7364 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7366 return null;
7369 return fne;
7372 protected override Expression DoResolve (ResolveContext ec)
7374 return ResolveAsTypeStep (ec, false);
7377 protected override void Error_IdentifierNotFound (IMemberContext rc, FullNamedExpression expr_type, string identifier)
7379 rc.Compiler.Report.Error (687, loc,
7380 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7381 GetSignatureForError ());
7384 public override string GetSignatureForError ()
7386 string name = Name;
7387 if (targs != null) {
7388 name = TypeManager.RemoveGenericArity (Name) + "<" +
7389 targs.GetSignatureForError () + ">";
7392 return alias + "::" + name;
7395 protected override void CloneTo (CloneContext clonectx, Expression t)
7397 // Nothing
7401 /// <summary>
7402 /// Implements the member access expression
7403 /// </summary>
7404 public class MemberAccess : ATypeNameExpression {
7405 protected Expression expr;
7407 public MemberAccess (Expression expr, string id)
7408 : base (id, expr.Location)
7410 this.expr = expr;
7413 public MemberAccess (Expression expr, string identifier, Location loc)
7414 : base (identifier, loc)
7416 this.expr = expr;
7419 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7420 : base (identifier, args, loc)
7422 this.expr = expr;
7425 Expression DoResolve (ResolveContext ec, Expression right_side)
7427 if (type != null)
7428 throw new Exception ();
7431 // Resolve the expression with flow analysis turned off, we'll do the definite
7432 // assignment checks later. This is because we don't know yet what the expression
7433 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7434 // definite assignment check on the actual field and not on the whole struct.
7437 SimpleName original = expr as SimpleName;
7438 Expression expr_resolved;
7439 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
7440 expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.Intermediate);
7443 if (expr_resolved == null)
7444 return null;
7446 string LookupIdentifier = MemberName.MakeName (Name, targs);
7448 Namespace ns = expr_resolved as Namespace;
7449 if (ns != null) {
7450 FullNamedExpression retval = ns.Lookup (ec.Compiler, LookupIdentifier, loc);
7452 if (retval == null)
7453 ns.Error_NamespaceDoesNotExist (loc, LookupIdentifier, ec);
7454 else if (targs != null)
7455 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
7457 return retval;
7460 Type expr_type = expr_resolved.Type;
7461 if (TypeManager.IsDynamicType (expr_type)) {
7462 Arguments args = new Arguments (1);
7463 args.Add (new Argument (expr_resolved.Resolve (ec)));
7464 expr = new DynamicMemberBinder (Name, args, loc);
7465 if (right_side != null)
7466 return expr.DoResolveLValue (ec, right_side);
7468 return expr.Resolve (ec);
7471 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7472 expr_type == TypeManager.null_type || expr_type == InternalType.AnonymousMethod) {
7473 Unary.Error_OperatorCannotBeApplied (ec, loc, ".", expr_type);
7474 return null;
7477 Constant c = expr_resolved as Constant;
7478 if (c != null && c.GetValue () == null) {
7479 ec.Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7480 "System.NullReferenceException");
7483 if (targs != null) {
7484 if (!targs.Resolve (ec))
7485 return null;
7488 Expression member_lookup;
7489 member_lookup = MemberLookup (ec.Compiler,
7490 ec.CurrentType, expr_type, expr_type, Name, loc);
7492 if (member_lookup == null && targs != null) {
7493 member_lookup = MemberLookup (ec.Compiler,
7494 ec.CurrentType, expr_type, expr_type, LookupIdentifier, loc);
7497 if (member_lookup == null) {
7498 ExprClass expr_eclass = expr_resolved.eclass;
7501 // Extension methods are not allowed on all expression types
7503 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7504 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7505 expr_eclass == ExprClass.EventAccess) {
7506 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
7507 if (ex_method_lookup != null) {
7508 ex_method_lookup.ExtensionExpression = expr_resolved;
7510 if (targs != null) {
7511 ex_method_lookup.SetTypeArguments (ec, targs);
7514 return ex_method_lookup.Resolve (ec);
7518 expr = expr_resolved;
7519 member_lookup = Error_MemberLookupFailed (ec,
7520 ec.CurrentType, expr_type, expr_type, Name, null,
7521 AllMemberTypes, AllBindingFlags);
7522 if (member_lookup == null)
7523 return null;
7526 TypeExpr texpr = member_lookup as TypeExpr;
7527 if (texpr != null) {
7528 if (!(expr_resolved is TypeExpr) &&
7529 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7530 ec.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7531 Name, member_lookup.GetSignatureForError ());
7532 return null;
7535 if (!texpr.CheckAccessLevel (ec.MemberContext)) {
7536 ec.Report.SymbolRelatedToPreviousError (member_lookup.Type);
7537 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type), ec.Report);
7538 return null;
7541 GenericTypeExpr ct = expr_resolved as GenericTypeExpr;
7542 if (ct != null) {
7544 // When looking up a nested type in a generic instance
7545 // via reflection, we always get a generic type definition
7546 // and not a generic instance - so we have to do this here.
7548 // See gtest-172-lib.cs and gtest-172.cs for an example.
7551 TypeArguments nested_targs;
7552 if (HasTypeArguments) {
7553 nested_targs = ct.TypeArguments.Clone ();
7554 nested_targs.Add (targs);
7555 } else {
7556 nested_targs = ct.TypeArguments;
7559 ct = new GenericTypeExpr (member_lookup.Type, nested_targs, loc);
7561 return ct.ResolveAsTypeStep (ec, false);
7564 return member_lookup;
7567 MemberExpr me = (MemberExpr) member_lookup;
7568 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7569 if (me == null)
7570 return null;
7572 if (targs != null) {
7573 me.SetTypeArguments (ec, targs);
7576 if (original != null && (!TypeManager.IsValueType (expr_type) || me is PropertyExpr)) {
7577 if (me.IsInstance) {
7578 LocalVariableReference var = expr_resolved as LocalVariableReference;
7579 if (var != null && !var.VerifyAssigned (ec))
7580 return null;
7584 // The following DoResolve/DoResolveLValue will do the definite assignment
7585 // check.
7587 if (right_side != null)
7588 return me.DoResolveLValue (ec, right_side);
7589 else
7590 return me.Resolve (ec);
7593 protected override Expression DoResolve (ResolveContext ec)
7595 return DoResolve (ec, null);
7598 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7600 return DoResolve (ec, right_side);
7603 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7605 return ResolveNamespaceOrType (ec, silent);
7608 public FullNamedExpression ResolveNamespaceOrType (IMemberContext rc, bool silent)
7610 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7612 if (expr_resolved == null)
7613 return null;
7615 string LookupIdentifier = MemberName.MakeName (Name, targs);
7617 Namespace ns = expr_resolved as Namespace;
7618 if (ns != null) {
7619 FullNamedExpression retval = ns.Lookup (rc.Compiler, LookupIdentifier, loc);
7621 if (retval == null && !silent)
7622 ns.Error_NamespaceDoesNotExist (loc, LookupIdentifier, rc);
7623 else if (targs != null)
7624 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7626 return retval;
7629 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7630 if (tnew_expr == null)
7631 return null;
7633 Type expr_type = tnew_expr.Type;
7634 if (TypeManager.IsGenericParameter (expr_type)) {
7635 rc.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7636 tnew_expr.GetSignatureForError ());
7637 return null;
7640 Expression member_lookup = MemberLookup (rc.Compiler,
7641 rc.CurrentType, expr_type, expr_type, LookupIdentifier,
7642 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7643 if (member_lookup == null) {
7644 if (silent)
7645 return null;
7647 Error_IdentifierNotFound (rc, expr_resolved, LookupIdentifier);
7648 return null;
7651 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7652 if (texpr == null)
7653 return null;
7655 TypeArguments the_args = targs;
7656 Type declaring_type = texpr.Type.DeclaringType;
7657 if (TypeManager.HasGenericArguments (declaring_type) && !TypeManager.IsGenericTypeDefinition (expr_type)) {
7658 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7659 expr_type = expr_type.BaseType;
7662 TypeArguments new_args = new TypeArguments ();
7663 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7664 new_args.Add (new TypeExpression (TypeManager.TypeToCoreType (decl), loc));
7666 if (targs != null)
7667 new_args.Add (targs);
7669 the_args = new_args;
7672 if (the_args != null) {
7673 GenericTypeExpr ctype = new GenericTypeExpr (texpr.Type, the_args, loc);
7674 return ctype.ResolveAsTypeStep (rc, false);
7677 return texpr;
7680 protected virtual void Error_IdentifierNotFound (IMemberContext rc, FullNamedExpression expr_type, string identifier)
7682 Expression member_lookup = MemberLookup (rc.Compiler,
7683 rc.CurrentType, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7684 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7686 if (member_lookup != null) {
7687 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7688 if (expr_type == null)
7689 return;
7691 expr_type.Error_TypeArgumentsCannotBeUsed (rc.Compiler.Report, loc);
7692 return;
7695 member_lookup = MemberLookup (rc.Compiler,
7696 rc.CurrentType, expr_type.Type, expr_type.Type, identifier,
7697 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7699 if (member_lookup == null) {
7700 rc.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7701 Name, expr_type.GetSignatureForError ());
7702 } else {
7703 // TODO: Report.SymbolRelatedToPreviousError
7704 member_lookup.Error_UnexpectedKind (rc.Compiler.Report, null, "type", loc);
7708 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
7710 if (RootContext.Version > LanguageVersion.ISO_2 && !ec.Compiler.IsRuntimeBinder &&
7711 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7712 ec.Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7713 "extension method `{1}' of type `{0}' could be found " +
7714 "(are you missing a using directive or an assembly reference?)",
7715 TypeManager.CSharpName (type), name);
7716 return;
7719 base.Error_TypeDoesNotContainDefinition (ec, type, name);
7722 public override string GetSignatureForError ()
7724 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7727 public Expression Left {
7728 get {
7729 return expr;
7733 protected override void CloneTo (CloneContext clonectx, Expression t)
7735 MemberAccess target = (MemberAccess) t;
7737 target.expr = expr.Clone (clonectx);
7741 /// <summary>
7742 /// Implements checked expressions
7743 /// </summary>
7744 public class CheckedExpr : Expression {
7746 public Expression Expr;
7748 public CheckedExpr (Expression e, Location l)
7750 Expr = e;
7751 loc = l;
7754 public override Expression CreateExpressionTree (ResolveContext ec)
7756 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7757 return Expr.CreateExpressionTree (ec);
7760 protected override Expression DoResolve (ResolveContext ec)
7762 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7763 Expr = Expr.Resolve (ec);
7765 if (Expr == null)
7766 return null;
7768 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7769 return Expr;
7771 eclass = Expr.eclass;
7772 type = Expr.Type;
7773 return this;
7776 public override void Emit (EmitContext ec)
7778 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7779 Expr.Emit (ec);
7782 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7784 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7785 Expr.EmitBranchable (ec, target, on_true);
7788 public override SLE.Expression MakeExpression (BuilderContext ctx)
7790 using (ctx.With (BuilderContext.Options.AllCheckStateFlags, true)) {
7791 return Expr.MakeExpression (ctx);
7795 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7797 Expr.MutateHoistedGenericType (storey);
7800 protected override void CloneTo (CloneContext clonectx, Expression t)
7802 CheckedExpr target = (CheckedExpr) t;
7804 target.Expr = Expr.Clone (clonectx);
7808 /// <summary>
7809 /// Implements the unchecked expression
7810 /// </summary>
7811 public class UnCheckedExpr : Expression {
7813 public Expression Expr;
7815 public UnCheckedExpr (Expression e, Location l)
7817 Expr = e;
7818 loc = l;
7821 public override Expression CreateExpressionTree (ResolveContext ec)
7823 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7824 return Expr.CreateExpressionTree (ec);
7827 protected override Expression DoResolve (ResolveContext ec)
7829 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7830 Expr = Expr.Resolve (ec);
7832 if (Expr == null)
7833 return null;
7835 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7836 return Expr;
7838 eclass = Expr.eclass;
7839 type = Expr.Type;
7840 return this;
7843 public override void Emit (EmitContext ec)
7845 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7846 Expr.Emit (ec);
7849 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7851 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7852 Expr.EmitBranchable (ec, target, on_true);
7855 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7857 Expr.MutateHoistedGenericType (storey);
7860 protected override void CloneTo (CloneContext clonectx, Expression t)
7862 UnCheckedExpr target = (UnCheckedExpr) t;
7864 target.Expr = Expr.Clone (clonectx);
7868 /// <summary>
7869 /// An Element Access expression.
7871 /// During semantic analysis these are transformed into
7872 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7873 /// </summary>
7874 public class ElementAccess : Expression {
7875 public Arguments Arguments;
7876 public Expression Expr;
7878 public ElementAccess (Expression e, Arguments args)
7880 Expr = e;
7881 loc = e.Location;
7882 this.Arguments = args;
7885 public override Expression CreateExpressionTree (ResolveContext ec)
7887 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
7888 Expr.CreateExpressionTree (ec));
7890 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
7893 Expression MakePointerAccess (ResolveContext ec, Type t)
7895 if (Arguments.Count != 1){
7896 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
7897 return null;
7900 if (Arguments [0] is NamedArgument)
7901 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
7903 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), t, loc);
7904 return new Indirection (p, loc).Resolve (ec);
7907 protected override Expression DoResolve (ResolveContext ec)
7909 Expr = Expr.Resolve (ec);
7910 if (Expr == null)
7911 return null;
7914 // We perform some simple tests, and then to "split" the emit and store
7915 // code we create an instance of a different class, and return that.
7917 // I am experimenting with this pattern.
7919 Type t = Expr.Type;
7921 if (t == TypeManager.array_type){
7922 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7923 return null;
7926 if (t.IsArray)
7927 return (new ArrayAccess (this, loc)).Resolve (ec);
7928 if (t.IsPointer)
7929 return MakePointerAccess (ec, t);
7931 FieldExpr fe = Expr as FieldExpr;
7932 if (fe != null) {
7933 var ff = fe.Spec as FixedFieldSpec;
7934 if (ff != null) {
7935 return MakePointerAccess (ec, ff.ElementType);
7938 return (new IndexerAccess (this, loc)).Resolve (ec);
7941 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7943 Expr = Expr.Resolve (ec);
7944 if (Expr == null)
7945 return null;
7947 type = Expr.Type;
7948 if (type.IsArray)
7949 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7951 if (type.IsPointer)
7952 return MakePointerAccess (ec, type);
7954 if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
7955 Error_CannotModifyIntermediateExpressionValue (ec);
7957 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7960 public override void Emit (EmitContext ec)
7962 throw new Exception ("Should never be reached");
7965 public static void Error_NamedArgument (NamedArgument na, Report Report)
7967 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
7970 public override string GetSignatureForError ()
7972 return Expr.GetSignatureForError ();
7975 protected override void CloneTo (CloneContext clonectx, Expression t)
7977 ElementAccess target = (ElementAccess) t;
7979 target.Expr = Expr.Clone (clonectx);
7980 if (Arguments != null)
7981 target.Arguments = Arguments.Clone (clonectx);
7985 /// <summary>
7986 /// Implements array access
7987 /// </summary>
7988 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
7990 // Points to our "data" repository
7992 ElementAccess ea;
7994 LocalTemporary temp;
7996 bool prepared;
7998 public ArrayAccess (ElementAccess ea_data, Location l)
8000 ea = ea_data;
8001 loc = l;
8004 public override Expression CreateExpressionTree (ResolveContext ec)
8006 return ea.CreateExpressionTree (ec);
8009 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8011 return DoResolve (ec);
8014 protected override Expression DoResolve (ResolveContext ec)
8016 // dynamic is used per argument in ConvertExpressionToArrayIndex case
8017 bool dynamic;
8018 ea.Arguments.Resolve (ec, out dynamic);
8020 Type t = ea.Expr.Type;
8021 int rank = ea.Arguments.Count;
8022 if (t.GetArrayRank () != rank) {
8023 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8024 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
8025 return null;
8028 type = TypeManager.GetElementType (t);
8029 if (type.IsPointer && !ec.IsUnsafe) {
8030 UnsafeError (ec, ea.Location);
8033 foreach (Argument a in ea.Arguments) {
8034 if (a is NamedArgument)
8035 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
8037 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
8040 eclass = ExprClass.Variable;
8042 return this;
8045 /// <summary>
8046 /// Emits the right opcode to load an object of Type `t'
8047 /// from an array of T
8048 /// </summary>
8049 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
8051 if (rank > 1) {
8052 MethodInfo get = FetchGetMethod ();
8053 ig.Emit (OpCodes.Call, get);
8054 return;
8057 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
8058 ig.Emit (OpCodes.Ldelem_U1);
8059 else if (type == TypeManager.sbyte_type)
8060 ig.Emit (OpCodes.Ldelem_I1);
8061 else if (type == TypeManager.short_type)
8062 ig.Emit (OpCodes.Ldelem_I2);
8063 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
8064 ig.Emit (OpCodes.Ldelem_U2);
8065 else if (type == TypeManager.int32_type)
8066 ig.Emit (OpCodes.Ldelem_I4);
8067 else if (type == TypeManager.uint32_type)
8068 ig.Emit (OpCodes.Ldelem_U4);
8069 else if (type == TypeManager.uint64_type)
8070 ig.Emit (OpCodes.Ldelem_I8);
8071 else if (type == TypeManager.int64_type)
8072 ig.Emit (OpCodes.Ldelem_I8);
8073 else if (type == TypeManager.float_type)
8074 ig.Emit (OpCodes.Ldelem_R4);
8075 else if (type == TypeManager.double_type)
8076 ig.Emit (OpCodes.Ldelem_R8);
8077 else if (type == TypeManager.intptr_type)
8078 ig.Emit (OpCodes.Ldelem_I);
8079 else if (TypeManager.IsEnumType (type)){
8080 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
8081 } else if (TypeManager.IsStruct (type)){
8082 ig.Emit (OpCodes.Ldelema, type);
8083 ig.Emit (OpCodes.Ldobj, type);
8084 } else if (type.IsGenericParameter) {
8085 ig.Emit (OpCodes.Ldelem, type);
8086 } else if (type.IsPointer)
8087 ig.Emit (OpCodes.Ldelem_I);
8088 else
8089 ig.Emit (OpCodes.Ldelem_Ref);
8092 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8094 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8097 /// <summary>
8098 /// Returns the right opcode to store an object of Type `t'
8099 /// from an array of T.
8100 /// </summary>
8101 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8103 has_type_arg = false; is_stobj = false;
8104 t = TypeManager.TypeToCoreType (t);
8105 if (TypeManager.IsEnumType (t))
8106 t = TypeManager.GetEnumUnderlyingType (t);
8107 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8108 t == TypeManager.bool_type)
8109 return OpCodes.Stelem_I1;
8110 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8111 t == TypeManager.char_type)
8112 return OpCodes.Stelem_I2;
8113 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8114 return OpCodes.Stelem_I4;
8115 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8116 return OpCodes.Stelem_I8;
8117 else if (t == TypeManager.float_type)
8118 return OpCodes.Stelem_R4;
8119 else if (t == TypeManager.double_type)
8120 return OpCodes.Stelem_R8;
8121 else if (t == TypeManager.intptr_type) {
8122 has_type_arg = true;
8123 is_stobj = true;
8124 return OpCodes.Stobj;
8125 } else if (TypeManager.IsStruct (t)) {
8126 has_type_arg = true;
8127 is_stobj = true;
8128 return OpCodes.Stobj;
8129 } else if (t.IsGenericParameter) {
8130 has_type_arg = true;
8131 return OpCodes.Stelem;
8132 } else if (t.IsPointer)
8133 return OpCodes.Stelem_I;
8134 else
8135 return OpCodes.Stelem_Ref;
8138 MethodInfo FetchGetMethod ()
8140 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8141 int arg_count = ea.Arguments.Count;
8142 Type [] args = new Type [arg_count];
8143 MethodInfo get;
8145 for (int i = 0; i < arg_count; i++){
8146 //args [i++] = a.Type;
8147 args [i] = TypeManager.int32_type;
8150 get = mb.GetArrayMethod (
8151 ea.Expr.Type, "Get",
8152 CallingConventions.HasThis |
8153 CallingConventions.Standard,
8154 type, args);
8155 return get;
8159 MethodInfo FetchAddressMethod ()
8161 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8162 int arg_count = ea.Arguments.Count;
8163 Type [] args = new Type [arg_count];
8164 MethodInfo address;
8165 Type ret_type;
8167 ret_type = TypeManager.GetReferenceType (type);
8169 for (int i = 0; i < arg_count; i++){
8170 //args [i++] = a.Type;
8171 args [i] = TypeManager.int32_type;
8174 address = mb.GetArrayMethod (
8175 ea.Expr.Type, "Address",
8176 CallingConventions.HasThis |
8177 CallingConventions.Standard,
8178 ret_type, args);
8180 return address;
8184 // Load the array arguments into the stack.
8186 void LoadArrayAndArguments (EmitContext ec)
8188 ea.Expr.Emit (ec);
8190 for (int i = 0; i < ea.Arguments.Count; ++i) {
8191 ea.Arguments [i].Emit (ec);
8195 public void Emit (EmitContext ec, bool leave_copy)
8197 int rank = ea.Expr.Type.GetArrayRank ();
8198 ILGenerator ig = ec.ig;
8200 if (prepared) {
8201 LoadFromPtr (ig, this.type);
8202 } else {
8203 LoadArrayAndArguments (ec);
8204 EmitLoadOpcode (ig, type, rank);
8207 if (leave_copy) {
8208 ig.Emit (OpCodes.Dup);
8209 temp = new LocalTemporary (this.type);
8210 temp.Store (ec);
8214 public override void Emit (EmitContext ec)
8216 Emit (ec, false);
8219 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8221 int rank = ea.Expr.Type.GetArrayRank ();
8222 ILGenerator ig = ec.ig;
8223 Type t = source.Type;
8224 prepared = prepare_for_load;
8226 if (prepared) {
8227 AddressOf (ec, AddressOp.LoadStore);
8228 ec.ig.Emit (OpCodes.Dup);
8229 } else {
8230 LoadArrayAndArguments (ec);
8233 if (rank == 1) {
8234 bool is_stobj, has_type_arg;
8235 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8237 if (!prepared) {
8239 // The stobj opcode used by value types will need
8240 // an address on the stack, not really an array/array
8241 // pair
8243 if (is_stobj)
8244 ig.Emit (OpCodes.Ldelema, t);
8247 source.Emit (ec);
8248 if (leave_copy) {
8249 ec.ig.Emit (OpCodes.Dup);
8250 temp = new LocalTemporary (this.type);
8251 temp.Store (ec);
8254 if (prepared)
8255 StoreFromPtr (ig, t);
8256 else if (is_stobj)
8257 ig.Emit (OpCodes.Stobj, t);
8258 else if (has_type_arg)
8259 ig.Emit (op, t);
8260 else
8261 ig.Emit (op);
8262 } else {
8263 source.Emit (ec);
8264 if (leave_copy) {
8265 ec.ig.Emit (OpCodes.Dup);
8266 temp = new LocalTemporary (this.type);
8267 temp.Store (ec);
8270 if (prepared) {
8271 StoreFromPtr (ig, t);
8272 } else {
8273 int arg_count = ea.Arguments.Count;
8274 Type [] args = new Type [arg_count + 1];
8275 for (int i = 0; i < arg_count; i++) {
8276 //args [i++] = a.Type;
8277 args [i] = TypeManager.int32_type;
8279 args [arg_count] = type;
8281 MethodInfo set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
8282 ea.Expr.Type, "Set",
8283 CallingConventions.HasThis |
8284 CallingConventions.Standard,
8285 TypeManager.void_type, args);
8287 ig.Emit (OpCodes.Call, set);
8291 if (temp != null) {
8292 temp.Emit (ec);
8293 temp.Release (ec);
8297 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8299 if (!source.Emit (ec, this)) {
8300 if (leave_copy)
8301 throw new NotImplementedException ();
8303 return;
8306 throw new NotImplementedException ();
8309 public void AddressOf (EmitContext ec, AddressOp mode)
8311 int rank = ea.Expr.Type.GetArrayRank ();
8312 ILGenerator ig = ec.ig;
8314 LoadArrayAndArguments (ec);
8316 if (rank == 1){
8317 ig.Emit (OpCodes.Ldelema, type);
8318 } else {
8319 MethodInfo address = FetchAddressMethod ();
8320 ig.Emit (OpCodes.Call, address);
8324 #if NET_4_0
8325 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
8327 return SLE.Expression.ArrayAccess (
8328 ea.Expr.MakeExpression (ctx),
8329 Arguments.MakeExpression (ea.Arguments, ctx));
8331 #endif
8333 public override SLE.Expression MakeExpression (BuilderContext ctx)
8335 return SLE.Expression.ArrayIndex (
8336 ea.Expr.MakeExpression (ctx),
8337 Arguments.MakeExpression (ea.Arguments, ctx));
8340 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8342 type = storey.MutateType (type);
8343 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8347 /// <summary>
8348 /// Expressions that represent an indexer call.
8349 /// </summary>
8350 public class IndexerAccess : Expression, IDynamicAssign
8352 class IndexerMethodGroupExpr : MethodGroupExpr
8354 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8355 : base (null, loc)
8357 Methods = indexers.Methods.ToArray ();
8360 public override string Name {
8361 get {
8362 return "this";
8366 protected override int GetApplicableParametersCount (MethodSpec method, AParametersCollection parameters)
8369 // Here is the trick, decrease number of arguments by 1 when only
8370 // available property method is setter. This makes overload resolution
8371 // work correctly for indexers.
8374 if (method.Name [0] == 'g')
8375 return parameters.Count;
8377 return parameters.Count - 1;
8381 class Indexers
8383 // Contains either property getter or setter
8384 public List<MethodSpec> Methods;
8385 public List<PropertyInfo> Properties;
8387 Indexers ()
8391 void Append (Type caller_type, MemberInfo [] mi)
8393 if (mi == null)
8394 return;
8396 foreach (PropertyInfo property in mi) {
8397 MethodInfo accessor = property.GetGetMethod (true);
8398 if (accessor == null)
8399 accessor = property.GetSetMethod (true);
8401 if (Methods == null) {
8402 Methods = new List<MethodSpec> ();
8403 Properties = new List<PropertyInfo> ();
8406 Methods.Add (Import.CreateMethod (accessor));
8407 Properties.Add (property);
8411 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8413 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8415 return TypeManager.MemberLookup (
8416 caller_type, caller_type, lookup_type, MemberTypes.Property,
8417 BindingFlags.Public | BindingFlags.Instance |
8418 BindingFlags.DeclaredOnly, p_name, null);
8421 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8423 Indexers ix = new Indexers ();
8425 if (TypeManager.IsGenericParameter (lookup_type)) {
8426 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8427 if (gc == null)
8428 return ix;
8430 if (gc.HasClassConstraint) {
8431 Type class_contraint = gc.ClassConstraint;
8432 while (class_contraint != TypeManager.object_type && class_contraint != null) {
8433 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, class_contraint));
8434 class_contraint = class_contraint.BaseType;
8438 Type[] ifaces = gc.InterfaceConstraints;
8439 foreach (Type itype in ifaces)
8440 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8442 return ix;
8445 Type copy = lookup_type;
8446 while (copy != TypeManager.object_type && copy != null){
8447 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8448 copy = copy.BaseType;
8451 if (lookup_type.IsInterface) {
8452 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8453 if (ifaces != null) {
8454 foreach (Type itype in ifaces)
8455 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8459 return ix;
8464 // Points to our "data" repository
8466 MethodSpec get, set;
8467 bool is_base_indexer;
8468 bool prepared;
8469 LocalTemporary temp;
8470 LocalTemporary prepared_value;
8471 Expression set_expr;
8473 protected Type indexer_type;
8474 protected Type current_type;
8475 protected Expression instance_expr;
8476 protected Arguments arguments;
8478 public IndexerAccess (ElementAccess ea, Location loc)
8479 : this (ea.Expr, false, loc)
8481 this.arguments = ea.Arguments;
8484 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8485 Location loc)
8487 this.instance_expr = instance_expr;
8488 this.is_base_indexer = is_base_indexer;
8489 this.loc = loc;
8492 static string GetAccessorName (bool isSet)
8494 return isSet ? "set" : "get";
8497 public override Expression CreateExpressionTree (ResolveContext ec)
8499 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8500 instance_expr.CreateExpressionTree (ec),
8501 new TypeOfMethod (get, loc));
8503 return CreateExpressionFactoryCall (ec, "Call", args);
8506 protected virtual void CommonResolve (ResolveContext ec)
8508 indexer_type = instance_expr.Type;
8509 current_type = ec.CurrentType;
8512 protected override Expression DoResolve (ResolveContext ec)
8514 return ResolveAccessor (ec, null);
8517 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8519 if (right_side == EmptyExpression.OutAccess.Instance) {
8520 right_side.DoResolveLValue (ec, this);
8521 return null;
8524 // if the indexer returns a value type, and we try to set a field in it
8525 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8526 Error_CannotModifyIntermediateExpressionValue (ec);
8529 return ResolveAccessor (ec, right_side);
8532 Expression ResolveAccessor (ResolveContext ec, Expression right_side)
8534 CommonResolve (ec);
8536 MethodGroupExpr mg;
8537 Indexers ilist;
8538 bool dynamic;
8540 arguments.Resolve (ec, out dynamic);
8542 if (TypeManager.IsDynamicType (indexer_type)) {
8543 dynamic = true;
8544 mg = null;
8545 ilist = null;
8546 } else {
8547 ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8548 if (ilist.Methods == null) {
8549 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8550 TypeManager.CSharpName (indexer_type));
8551 return null;
8554 mg = new IndexerMethodGroupExpr (ilist, loc);
8555 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8556 if (mg == null)
8557 return null;
8560 if (dynamic) {
8561 Arguments args = new Arguments (arguments.Count + 1);
8562 if (is_base_indexer) {
8563 ec.Report.Error (1972, loc, "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8564 } else {
8565 args.Add (new Argument (instance_expr));
8567 args.AddRange (arguments);
8569 var expr = new DynamicIndexBinder (args, loc);
8570 if (right_side != null)
8571 return expr.ResolveLValue (ec, right_side);
8573 return expr.Resolve (ec);
8576 var mi = (MethodSpec) mg;
8577 PropertyInfo pi = null;
8578 for (int i = 0; i < ilist.Methods.Count; ++i) {
8579 if (ilist.Methods [i].MetaInfo == mi.MetaInfo) {
8580 pi = (PropertyInfo) ilist.Properties [i];
8581 break;
8585 type = TypeManager.TypeToCoreType (pi.PropertyType);
8586 if (type.IsPointer && !ec.IsUnsafe)
8587 UnsafeError (ec, loc);
8589 MethodSpec accessor = null;
8590 if (right_side == null) {
8591 var m = pi.GetGetMethod (true);
8592 if (m != null)
8593 accessor = get = Import.CreateMethod (m);
8594 } else {
8595 var m = pi.GetSetMethod (true);
8596 if (m != null)
8597 accessor = set = Import.CreateMethod (m);
8598 if (accessor == null && pi.GetGetMethod (true) != null) {
8599 ec.Report.SymbolRelatedToPreviousError (pi);
8600 ec.Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8601 TypeManager.GetFullNameSignature (pi));
8602 return null;
8605 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8608 if (accessor == null) {
8609 ec.Report.SymbolRelatedToPreviousError (pi);
8610 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8611 TypeManager.GetFullNameSignature (pi), GetAccessorName (right_side != null));
8612 return null;
8616 // Only base will allow this invocation to happen.
8618 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8619 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (pi));
8622 bool must_do_cs1540_check;
8623 if (!IsAccessorAccessible (ec.CurrentType, accessor, out must_do_cs1540_check)) {
8624 if (set == null) {
8625 var m = pi.GetSetMethod (true);
8626 if (m != null)
8627 set = Import.CreateMethod (m);
8628 } else {
8629 var m = pi.GetGetMethod (true);
8630 if (m != null)
8631 get = Import.CreateMethod (m);
8634 if (set != null && get != null &&
8635 (set.MetaInfo.Attributes & MethodAttributes.MemberAccessMask) != (get.MetaInfo.Attributes & MethodAttributes.MemberAccessMask)) {
8636 ec.Report.SymbolRelatedToPreviousError (accessor.MetaInfo);
8637 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8638 TypeManager.GetFullNameSignature (pi), GetAccessorName (right_side != null));
8639 } else {
8640 ec.Report.SymbolRelatedToPreviousError (pi);
8641 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi), ec.Report);
8645 instance_expr.CheckMarshalByRefAccess (ec);
8646 eclass = ExprClass.IndexerAccess;
8647 return this;
8650 public override void Emit (EmitContext ec)
8652 Emit (ec, false);
8655 public void Emit (EmitContext ec, bool leave_copy)
8657 if (prepared) {
8658 prepared_value.Emit (ec);
8659 } else {
8660 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8661 arguments, loc, false, false);
8664 if (leave_copy) {
8665 ec.ig.Emit (OpCodes.Dup);
8666 temp = new LocalTemporary (Type);
8667 temp.Store (ec);
8672 // source is ignored, because we already have a copy of it from the
8673 // LValue resolution and we have already constructed a pre-cached
8674 // version of the arguments (ea.set_arguments);
8676 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8678 prepared = prepare_for_load;
8679 Expression value = set_expr;
8681 if (prepared) {
8682 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8683 arguments, loc, true, false);
8685 prepared_value = new LocalTemporary (type);
8686 prepared_value.Store (ec);
8687 source.Emit (ec);
8688 prepared_value.Release (ec);
8690 if (leave_copy) {
8691 ec.ig.Emit (OpCodes.Dup);
8692 temp = new LocalTemporary (Type);
8693 temp.Store (ec);
8695 } else if (leave_copy) {
8696 temp = new LocalTemporary (Type);
8697 source.Emit (ec);
8698 temp.Store (ec);
8699 value = temp;
8702 if (!prepared)
8703 arguments.Add (new Argument (value));
8705 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8707 if (temp != null) {
8708 temp.Emit (ec);
8709 temp.Release (ec);
8713 public override string GetSignatureForError ()
8715 return TypeManager.CSharpSignature (get != null ? get.MetaInfo : set.MetaInfo, false);
8718 #if NET_4_0
8719 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
8721 var value = new[] { set_expr.MakeExpression (ctx) };
8722 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
8724 return SLE.Expression.Block (
8725 SLE.Expression.Call (instance_expr.MakeExpression (ctx), (MethodInfo) set.MetaInfo, args),
8726 value [0]);
8728 #endif
8730 public override SLE.Expression MakeExpression (BuilderContext ctx)
8732 var args = Arguments.MakeExpression (arguments, ctx);
8733 return SLE.Expression.Call (instance_expr.MakeExpression (ctx), (MethodInfo) get.MetaInfo, args);
8736 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8738 if (get != null)
8739 storey.MutateGenericMethod (get);
8740 if (set != null)
8741 storey.MutateGenericMethod (set);
8743 instance_expr.MutateHoistedGenericType (storey);
8744 if (arguments != null)
8745 arguments.MutateHoistedGenericType (storey);
8747 type = storey.MutateType (type);
8750 protected override void CloneTo (CloneContext clonectx, Expression t)
8752 IndexerAccess target = (IndexerAccess) t;
8754 if (arguments != null)
8755 target.arguments = arguments.Clone (clonectx);
8757 if (instance_expr != null)
8758 target.instance_expr = instance_expr.Clone (clonectx);
8762 /// <summary>
8763 /// The base operator for method names
8764 /// </summary>
8765 public class BaseAccess : Expression {
8766 public readonly string Identifier;
8767 TypeArguments args;
8769 public BaseAccess (string member, Location l)
8771 this.Identifier = member;
8772 loc = l;
8775 public BaseAccess (string member, TypeArguments args, Location l)
8776 : this (member, l)
8778 this.args = args;
8781 public override Expression CreateExpressionTree (ResolveContext ec)
8783 throw new NotSupportedException ("ET");
8786 protected override Expression DoResolve (ResolveContext ec)
8788 Expression c = CommonResolve (ec);
8790 if (c == null)
8791 return null;
8794 // MethodGroups use this opportunity to flag an error on lacking ()
8796 if (!(c is MethodGroupExpr))
8797 return c.Resolve (ec);
8798 return c;
8801 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8803 Expression c = CommonResolve (ec);
8805 if (c == null)
8806 return null;
8809 // MethodGroups use this opportunity to flag an error on lacking ()
8811 if (! (c is MethodGroupExpr))
8812 return c.DoResolveLValue (ec, right_side);
8814 return c;
8817 Expression CommonResolve (ResolveContext ec)
8819 Expression member_lookup;
8820 Type current_type = ec.CurrentType;
8821 Type base_type = current_type.BaseType;
8823 if (!This.IsThisAvailable (ec)) {
8824 if (ec.IsStatic) {
8825 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
8826 } else {
8827 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
8829 return null;
8832 member_lookup = MemberLookup (ec.Compiler, ec.CurrentType, null, base_type, Identifier,
8833 AllMemberTypes, AllBindingFlags, loc);
8834 if (member_lookup == null) {
8835 Error_MemberLookupFailed (ec, ec.CurrentType, base_type, base_type, Identifier,
8836 null, AllMemberTypes, AllBindingFlags);
8837 return null;
8840 Expression left;
8842 if (ec.IsStatic)
8843 left = new TypeExpression (base_type, loc);
8844 else
8845 left = ec.GetThis (loc);
8847 MemberExpr me = member_lookup as MemberExpr;
8848 if (me == null){
8849 if (member_lookup is TypeExpression){
8850 ec.Report.Error (582, loc, "{0}: Can not reference a type through an expression, try `{1}' instead",
8851 Identifier, member_lookup.GetSignatureForError ());
8852 } else {
8853 ec.Report.Error (582, loc, "{0}: Can not reference a {1} through an expression",
8854 Identifier, member_lookup.ExprClassName);
8857 return null;
8860 me = me.ResolveMemberAccess (ec, left, loc, null);
8861 if (me == null)
8862 return null;
8864 me.IsBase = true;
8865 if (args != null) {
8866 args.Resolve (ec);
8867 me.SetTypeArguments (ec, args);
8870 return me;
8873 public override void Emit (EmitContext ec)
8875 throw new Exception ("Should never be called");
8878 protected override void CloneTo (CloneContext clonectx, Expression t)
8880 BaseAccess target = (BaseAccess) t;
8882 if (args != null)
8883 target.args = args.Clone ();
8887 /// <summary>
8888 /// The base indexer operator
8889 /// </summary>
8890 public class BaseIndexerAccess : IndexerAccess {
8891 public BaseIndexerAccess (Arguments args, Location loc)
8892 : base (null, true, loc)
8894 this.arguments = args;
8897 protected override void CommonResolve (ResolveContext ec)
8899 instance_expr = ec.GetThis (loc);
8901 current_type = ec.CurrentType.BaseType;
8902 indexer_type = current_type;
8905 public override Expression CreateExpressionTree (ResolveContext ec)
8907 MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
8908 return base.CreateExpressionTree (ec);
8912 /// <summary>
8913 /// This class exists solely to pass the Type around and to be a dummy
8914 /// that can be passed to the conversion functions (this is used by
8915 /// foreach implementation to typecast the object return value from
8916 /// get_Current into the proper type. All code has been generated and
8917 /// we only care about the side effect conversions to be performed
8919 /// This is also now used as a placeholder where a no-action expression
8920 /// is needed (the `New' class).
8921 /// </summary>
8922 public class EmptyExpression : Expression {
8923 public static readonly Expression Null = new EmptyExpression ();
8925 public class OutAccess : EmptyExpression
8927 public static readonly OutAccess Instance = new OutAccess ();
8929 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8931 rc.Report.Error (206, right_side.Location,
8932 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
8934 return null;
8938 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8939 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8940 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8942 static EmptyExpression temp = new EmptyExpression ();
8943 public static EmptyExpression Grab ()
8945 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8946 temp = null;
8947 return retval;
8950 public static void Release (EmptyExpression e)
8952 temp = e;
8955 EmptyExpression ()
8957 // FIXME: Don't set to object
8958 type = TypeManager.object_type;
8959 eclass = ExprClass.Value;
8960 loc = Location.Null;
8963 public EmptyExpression (Type t)
8965 type = t;
8966 eclass = ExprClass.Value;
8967 loc = Location.Null;
8970 public override Expression CreateExpressionTree (ResolveContext ec)
8972 throw new NotSupportedException ("ET");
8975 protected override Expression DoResolve (ResolveContext ec)
8977 return this;
8980 public override void Emit (EmitContext ec)
8982 // nothing, as we only exist to not do anything.
8985 public override void EmitSideEffect (EmitContext ec)
8990 // This is just because we might want to reuse this bad boy
8991 // instead of creating gazillions of EmptyExpressions.
8992 // (CanImplicitConversion uses it)
8994 public void SetType (Type t)
8996 type = t;
9001 // Empty statement expression
9003 public sealed class EmptyExpressionStatement : ExpressionStatement
9005 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
9007 private EmptyExpressionStatement ()
9009 loc = Location.Null;
9012 public override Expression CreateExpressionTree (ResolveContext ec)
9014 return null;
9017 public override void EmitStatement (EmitContext ec)
9019 // Do nothing
9022 protected override Expression DoResolve (ResolveContext ec)
9024 eclass = ExprClass.Value;
9025 type = TypeManager.object_type;
9026 return this;
9029 public override void Emit (EmitContext ec)
9031 // Do nothing
9035 public class UserCast : Expression {
9036 MethodSpec method;
9037 Expression source;
9039 public UserCast (MethodSpec method, Expression source, Location l)
9041 this.method = method;
9042 this.source = source;
9043 type = TypeManager.TypeToCoreType (method.ReturnType);
9044 loc = l;
9047 public Expression Source {
9048 get {
9049 return source;
9053 public override Expression CreateExpressionTree (ResolveContext ec)
9055 Arguments args = new Arguments (3);
9056 args.Add (new Argument (source.CreateExpressionTree (ec)));
9057 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9058 args.Add (new Argument (new TypeOfMethod (method, loc)));
9059 return CreateExpressionFactoryCall (ec, "Convert", args);
9062 protected override Expression DoResolve (ResolveContext ec)
9064 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method.MetaInfo);
9065 if (oa != null)
9066 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
9068 eclass = ExprClass.Value;
9069 return this;
9072 public override void Emit (EmitContext ec)
9074 source.Emit (ec);
9075 ec.ig.Emit (OpCodes.Call, (MethodInfo) method.MetaInfo);
9078 public override string GetSignatureForError ()
9080 return TypeManager.CSharpSignature (method.MetaInfo);
9083 public override SLE.Expression MakeExpression (BuilderContext ctx)
9085 return SLE.Expression.Convert (source.MakeExpression (ctx), type, (MethodInfo) method.MetaInfo);
9088 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9090 source.MutateHoistedGenericType (storey);
9091 storey.MutateGenericMethod (method);
9095 // <summary>
9096 // This class is used to "construct" the type during a typecast
9097 // operation. Since the Type.GetType class in .NET can parse
9098 // the type specification, we just use this to construct the type
9099 // one bit at a time.
9100 // </summary>
9101 public class ComposedCast : TypeExpr {
9102 FullNamedExpression left;
9103 string dim;
9105 public ComposedCast (FullNamedExpression left, string dim)
9106 : this (left, dim, left.Location)
9110 public ComposedCast (FullNamedExpression left, string dim, Location l)
9112 this.left = left;
9113 this.dim = dim;
9114 loc = l;
9117 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
9119 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
9120 if (lexpr == null)
9121 return null;
9123 Type ltype = lexpr.Type;
9124 if ((dim.Length > 0) && (dim [0] == '?')) {
9125 TypeExpr nullable = new Nullable.NullableType (lexpr, loc);
9126 if (dim.Length > 1)
9127 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
9128 return nullable.ResolveAsTypeTerminal (ec, false);
9131 if (dim == "*" && !TypeManager.VerifyUnmanaged (ec.Compiler, ltype, loc))
9132 return null;
9134 if (dim.Length != 0 && dim [0] == '[') {
9135 if (TypeManager.IsSpecialType (ltype)) {
9136 ec.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
9137 return null;
9140 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
9141 ec.Compiler.Report.SymbolRelatedToPreviousError (ltype);
9142 ec.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9143 TypeManager.CSharpName (ltype));
9147 if (dim != "")
9148 type = TypeManager.GetConstructedType (ltype, dim);
9149 else
9150 type = ltype;
9152 if (type == null)
9153 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
9155 if (type.IsPointer && !ec.IsUnsafe){
9156 UnsafeError (ec.Compiler.Report, loc);
9159 eclass = ExprClass.Type;
9160 return this;
9163 public override string GetSignatureForError ()
9165 return left.GetSignatureForError () + dim;
9168 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
9170 return ResolveAsBaseTerminal (ec, silent);
9174 public class FixedBufferPtr : Expression {
9175 Expression array;
9177 public FixedBufferPtr (Expression array, Type array_type, Location l)
9179 this.array = array;
9180 this.loc = l;
9182 type = TypeManager.GetPointerType (array_type);
9183 eclass = ExprClass.Value;
9186 public override Expression CreateExpressionTree (ResolveContext ec)
9188 Error_PointerInsideExpressionTree (ec);
9189 return null;
9192 public override void Emit(EmitContext ec)
9194 array.Emit (ec);
9197 protected override Expression DoResolve (ResolveContext ec)
9200 // We are born fully resolved
9202 return this;
9208 // This class is used to represent the address of an array, used
9209 // only by the Fixed statement, this generates "&a [0]" construct
9210 // for fixed (char *pa = a)
9212 public class ArrayPtr : FixedBufferPtr {
9213 Type array_type;
9215 public ArrayPtr (Expression array, Type array_type, Location l):
9216 base (array, array_type, l)
9218 this.array_type = array_type;
9221 public override void Emit (EmitContext ec)
9223 base.Emit (ec);
9225 ILGenerator ig = ec.ig;
9226 IntLiteral.EmitInt (ig, 0);
9227 ig.Emit (OpCodes.Ldelema, array_type);
9232 // Encapsulates a conversion rules required for array indexes
9234 public class ArrayIndexCast : TypeCast
9236 public ArrayIndexCast (Expression expr)
9237 : base (expr, TypeManager.int32_type)
9239 if (expr.Type == TypeManager.int32_type)
9240 throw new ArgumentException ("unnecessary array index conversion");
9243 public override Expression CreateExpressionTree (ResolveContext ec)
9245 using (ec.Set (ResolveContext.Options.CheckedScope)) {
9246 return base.CreateExpressionTree (ec);
9250 public override void Emit (EmitContext ec)
9252 child.Emit (ec);
9254 var expr_type = child.Type;
9256 if (expr_type == TypeManager.uint32_type)
9257 ec.ig.Emit (OpCodes.Conv_U);
9258 else if (expr_type == TypeManager.int64_type)
9259 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9260 else if (expr_type == TypeManager.uint64_type)
9261 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9262 else
9263 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9266 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
9268 return child.GetAttributableValue (ec, value_type, out value);
9273 // Implements the `stackalloc' keyword
9275 public class StackAlloc : Expression {
9276 Type otype;
9277 Expression t;
9278 Expression count;
9280 public StackAlloc (Expression type, Expression count, Location l)
9282 t = type;
9283 this.count = count;
9284 loc = l;
9287 public override Expression CreateExpressionTree (ResolveContext ec)
9289 throw new NotSupportedException ("ET");
9292 protected override Expression DoResolve (ResolveContext ec)
9294 count = count.Resolve (ec);
9295 if (count == null)
9296 return null;
9298 if (count.Type != TypeManager.uint32_type){
9299 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9300 if (count == null)
9301 return null;
9304 Constant c = count as Constant;
9305 if (c != null && c.IsNegative) {
9306 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9309 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9310 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9313 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9314 if (texpr == null)
9315 return null;
9317 otype = texpr.Type;
9319 if (!TypeManager.VerifyUnmanaged (ec.Compiler, otype, loc))
9320 return null;
9322 type = TypeManager.GetPointerType (otype);
9323 eclass = ExprClass.Value;
9325 return this;
9328 public override void Emit (EmitContext ec)
9330 int size = GetTypeSize (otype);
9331 ILGenerator ig = ec.ig;
9333 count.Emit (ec);
9335 if (size == 0)
9336 ig.Emit (OpCodes.Sizeof, otype);
9337 else
9338 IntConstant.EmitInt (ig, size);
9340 ig.Emit (OpCodes.Mul_Ovf_Un);
9341 ig.Emit (OpCodes.Localloc);
9344 protected override void CloneTo (CloneContext clonectx, Expression t)
9346 StackAlloc target = (StackAlloc) t;
9347 target.count = count.Clone (clonectx);
9348 target.t = t.Clone (clonectx);
9353 // An object initializer expression
9355 public class ElementInitializer : Assign
9357 public readonly string Name;
9359 public ElementInitializer (string name, Expression initializer, Location loc)
9360 : base (null, initializer, loc)
9362 this.Name = name;
9365 protected override void CloneTo (CloneContext clonectx, Expression t)
9367 ElementInitializer target = (ElementInitializer) t;
9368 target.source = source.Clone (clonectx);
9371 public override Expression CreateExpressionTree (ResolveContext ec)
9373 Arguments args = new Arguments (2);
9374 FieldExpr fe = target as FieldExpr;
9375 if (fe != null)
9376 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9377 else
9378 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9380 args.Add (new Argument (source.CreateExpressionTree (ec)));
9381 return CreateExpressionFactoryCall (ec,
9382 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9383 args);
9386 protected override Expression DoResolve (ResolveContext ec)
9388 if (source == null)
9389 return EmptyExpressionStatement.Instance;
9391 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9392 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9394 if (me == null)
9395 return null;
9397 target = me;
9398 me.InstanceExpression = ec.CurrentInitializerVariable;
9400 if (source is CollectionOrObjectInitializers) {
9401 Expression previous = ec.CurrentInitializerVariable;
9402 ec.CurrentInitializerVariable = target;
9403 source = source.Resolve (ec);
9404 ec.CurrentInitializerVariable = previous;
9405 if (source == null)
9406 return null;
9408 eclass = source.eclass;
9409 type = source.Type;
9410 return this;
9413 Expression expr = base.DoResolve (ec);
9414 if (expr == null)
9415 return null;
9418 // Ignore field initializers with default value
9420 Constant c = source as Constant;
9421 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9422 return EmptyExpressionStatement.Instance.Resolve (ec);
9424 return expr;
9427 protected override Expression Error_MemberLookupFailed (ResolveContext ec, Type type, MemberInfo[] members)
9429 MemberInfo member = members [0];
9430 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9431 ec.Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9432 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9433 else
9434 ec.Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9435 TypeManager.GetFullNameSignature (member));
9437 return null;
9440 public override void EmitStatement (EmitContext ec)
9442 if (source is CollectionOrObjectInitializers)
9443 source.Emit (ec);
9444 else
9445 base.EmitStatement (ec);
9450 // A collection initializer expression
9452 class CollectionElementInitializer : Invocation
9454 public class ElementInitializerArgument : Argument
9456 public ElementInitializerArgument (Expression e)
9457 : base (e)
9462 sealed class AddMemberAccess : MemberAccess
9464 public AddMemberAccess (Expression expr, Location loc)
9465 : base (expr, "Add", loc)
9469 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
9471 if (TypeManager.HasElementType (type))
9472 return;
9474 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9478 public CollectionElementInitializer (Expression argument)
9479 : base (null, new Arguments (1))
9481 base.arguments.Add (new ElementInitializerArgument (argument));
9482 this.loc = argument.Location;
9485 public CollectionElementInitializer (List<Expression> arguments, Location loc)
9486 : base (null, new Arguments (arguments.Count))
9488 foreach (Expression e in arguments)
9489 base.arguments.Add (new ElementInitializerArgument (e));
9491 this.loc = loc;
9494 public override Expression CreateExpressionTree (ResolveContext ec)
9496 Arguments args = new Arguments (2);
9497 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9499 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
9500 foreach (Argument a in arguments)
9501 expr_initializers.Add (a.CreateExpressionTree (ec));
9503 args.Add (new Argument (new ArrayCreation (
9504 CreateExpressionTypeExpression (ec, loc), "[]", expr_initializers, loc)));
9505 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9508 protected override void CloneTo (CloneContext clonectx, Expression t)
9510 CollectionElementInitializer target = (CollectionElementInitializer) t;
9511 if (arguments != null)
9512 target.arguments = arguments.Clone (clonectx);
9515 protected override Expression DoResolve (ResolveContext ec)
9517 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9519 return base.DoResolve (ec);
9524 // A block of object or collection initializers
9526 public class CollectionOrObjectInitializers : ExpressionStatement
9528 IList<Expression> initializers;
9529 bool is_collection_initialization;
9531 public static readonly CollectionOrObjectInitializers Empty =
9532 new CollectionOrObjectInitializers (Array.AsReadOnly (new Expression [0]), Location.Null);
9534 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
9536 this.initializers = initializers;
9537 this.loc = loc;
9540 public bool IsEmpty {
9541 get {
9542 return initializers.Count == 0;
9546 public bool IsCollectionInitializer {
9547 get {
9548 return is_collection_initialization;
9552 protected override void CloneTo (CloneContext clonectx, Expression target)
9554 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9556 t.initializers = new List<Expression> (initializers.Count);
9557 foreach (var e in initializers)
9558 t.initializers.Add (e.Clone (clonectx));
9561 public override Expression CreateExpressionTree (ResolveContext ec)
9563 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
9564 foreach (Expression e in initializers) {
9565 Expression expr = e.CreateExpressionTree (ec);
9566 if (expr != null)
9567 expr_initializers.Add (expr);
9570 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9573 protected override Expression DoResolve (ResolveContext ec)
9575 List<string> element_names = null;
9576 for (int i = 0; i < initializers.Count; ++i) {
9577 Expression initializer = (Expression) initializers [i];
9578 ElementInitializer element_initializer = initializer as ElementInitializer;
9580 if (i == 0) {
9581 if (element_initializer != null) {
9582 element_names = new List<string> (initializers.Count);
9583 element_names.Add (element_initializer.Name);
9584 } else if (initializer is CompletingExpression){
9585 initializer.Resolve (ec);
9586 throw new InternalErrorException ("This line should never be reached");
9587 } else {
9588 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type, TypeManager.ienumerable_type)) {
9589 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9590 "object initializer because type `{1}' does not implement `{2}' interface",
9591 ec.CurrentInitializerVariable.GetSignatureForError (),
9592 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9593 TypeManager.CSharpName (TypeManager.ienumerable_type));
9594 return null;
9596 is_collection_initialization = true;
9598 } else {
9599 if (is_collection_initialization != (element_initializer == null)) {
9600 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9601 is_collection_initialization ? "collection initializer" : "object initializer");
9602 continue;
9605 if (!is_collection_initialization) {
9606 if (element_names.Contains (element_initializer.Name)) {
9607 ec.Report.Error (1912, element_initializer.Location,
9608 "An object initializer includes more than one member `{0}' initialization",
9609 element_initializer.Name);
9610 } else {
9611 element_names.Add (element_initializer.Name);
9616 Expression e = initializer.Resolve (ec);
9617 if (e == EmptyExpressionStatement.Instance)
9618 initializers.RemoveAt (i--);
9619 else
9620 initializers [i] = e;
9623 type = ec.CurrentInitializerVariable.Type;
9624 if (is_collection_initialization) {
9625 if (TypeManager.HasElementType (type)) {
9626 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9627 TypeManager.CSharpName (type));
9631 eclass = ExprClass.Variable;
9632 return this;
9635 public override void Emit (EmitContext ec)
9637 EmitStatement (ec);
9640 public override void EmitStatement (EmitContext ec)
9642 foreach (ExpressionStatement e in initializers)
9643 e.EmitStatement (ec);
9646 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9648 foreach (Expression e in initializers)
9649 e.MutateHoistedGenericType (storey);
9654 // New expression with element/object initializers
9656 public class NewInitialize : New
9659 // This class serves as a proxy for variable initializer target instances.
9660 // A real variable is assigned later when we resolve left side of an
9661 // assignment
9663 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9665 NewInitialize new_instance;
9667 public InitializerTargetExpression (NewInitialize newInstance)
9669 this.type = newInstance.type;
9670 this.loc = newInstance.loc;
9671 this.eclass = newInstance.eclass;
9672 this.new_instance = newInstance;
9675 public override Expression CreateExpressionTree (ResolveContext ec)
9677 // Should not be reached
9678 throw new NotSupportedException ("ET");
9681 protected override Expression DoResolve (ResolveContext ec)
9683 return this;
9686 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9688 return this;
9691 public override void Emit (EmitContext ec)
9693 Expression e = (Expression) new_instance.instance;
9694 e.Emit (ec);
9697 #region IMemoryLocation Members
9699 public void AddressOf (EmitContext ec, AddressOp mode)
9701 new_instance.instance.AddressOf (ec, mode);
9704 #endregion
9707 CollectionOrObjectInitializers initializers;
9708 IMemoryLocation instance;
9710 public NewInitialize (Expression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9711 : base (requested_type, arguments, l)
9713 this.initializers = initializers;
9716 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9718 instance = base.EmitAddressOf (ec, Mode);
9720 if (!initializers.IsEmpty)
9721 initializers.Emit (ec);
9723 return instance;
9726 protected override void CloneTo (CloneContext clonectx, Expression t)
9728 base.CloneTo (clonectx, t);
9730 NewInitialize target = (NewInitialize) t;
9731 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9734 public override Expression CreateExpressionTree (ResolveContext ec)
9736 Arguments args = new Arguments (2);
9737 args.Add (new Argument (base.CreateExpressionTree (ec)));
9738 if (!initializers.IsEmpty)
9739 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9741 return CreateExpressionFactoryCall (ec,
9742 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9743 args);
9746 protected override Expression DoResolve (ResolveContext ec)
9748 Expression e = base.DoResolve (ec);
9749 if (type == null)
9750 return null;
9752 Expression previous = ec.CurrentInitializerVariable;
9753 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9754 initializers.Resolve (ec);
9755 ec.CurrentInitializerVariable = previous;
9756 return e;
9759 public override bool Emit (EmitContext ec, IMemoryLocation target)
9761 bool left_on_stack = base.Emit (ec, target);
9763 if (initializers.IsEmpty)
9764 return left_on_stack;
9766 LocalTemporary temp = target as LocalTemporary;
9767 if (temp == null) {
9768 if (!left_on_stack) {
9769 VariableReference vr = target as VariableReference;
9771 // FIXME: This still does not work correctly for pre-set variables
9772 if (vr != null && vr.IsRef)
9773 target.AddressOf (ec, AddressOp.Load);
9775 ((Expression) target).Emit (ec);
9776 left_on_stack = true;
9779 temp = new LocalTemporary (type);
9782 instance = temp;
9783 if (left_on_stack)
9784 temp.Store (ec);
9786 initializers.Emit (ec);
9788 if (left_on_stack) {
9789 temp.Emit (ec);
9790 temp.Release (ec);
9793 return left_on_stack;
9796 public override bool HasInitializer {
9797 get {
9798 return !initializers.IsEmpty;
9802 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9804 base.MutateHoistedGenericType (storey);
9805 initializers.MutateHoistedGenericType (storey);
9809 public class NewAnonymousType : New
9811 static readonly IList<AnonymousTypeParameter> EmptyParameters = Array.AsReadOnly (new AnonymousTypeParameter[0]);
9813 List<AnonymousTypeParameter> parameters;
9814 readonly TypeContainer parent;
9815 AnonymousTypeClass anonymous_type;
9817 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
9818 : base (null, null, loc)
9820 this.parameters = parameters;
9821 this.parent = parent;
9824 protected override void CloneTo (CloneContext clonectx, Expression target)
9826 if (parameters == null)
9827 return;
9829 NewAnonymousType t = (NewAnonymousType) target;
9830 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
9831 foreach (AnonymousTypeParameter atp in parameters)
9832 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
9835 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
9837 AnonymousTypeClass type = parent.Module.Compiled.GetAnonymousType (parameters);
9838 if (type != null)
9839 return type;
9841 type = AnonymousTypeClass.Create (ec.Compiler, parent, parameters, loc);
9842 if (type == null)
9843 return null;
9845 type.DefineType ();
9846 type.Define ();
9847 type.EmitType ();
9848 if (ec.Report.Errors == 0)
9849 type.CloseType ();
9851 parent.Module.Compiled.AddAnonymousType (type);
9852 return type;
9855 public override Expression CreateExpressionTree (ResolveContext ec)
9857 if (parameters == null)
9858 return base.CreateExpressionTree (ec);
9860 var init = new ArrayInitializer (parameters.Count, loc);
9861 foreach (Property p in anonymous_type.Properties)
9862 init.Add (new TypeOfMethod (Import.CreateMethod (TypeBuilder.GetMethod (type, p.GetBuilder)), loc));
9864 var ctor_args = new ArrayInitializer (Arguments.Count, loc);
9865 foreach (Argument a in Arguments)
9866 ctor_args.Add (a.CreateExpressionTree (ec));
9868 Arguments args = new Arguments (3);
9869 args.Add (new Argument (method.CreateExpressionTree (ec)));
9870 args.Add (new Argument (new ArrayCreation (TypeManager.expression_type_expr, "[]", ctor_args, loc)));
9871 args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", init, loc)));
9873 return CreateExpressionFactoryCall (ec, "New", args);
9876 protected override Expression DoResolve (ResolveContext ec)
9878 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
9879 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9880 return null;
9883 if (parameters == null) {
9884 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
9885 RequestedType = new TypeExpression (anonymous_type.TypeBuilder, loc);
9886 return base.DoResolve (ec);
9889 bool error = false;
9890 Arguments = new Arguments (parameters.Count);
9891 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9892 for (int i = 0; i < parameters.Count; ++i) {
9893 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9894 if (e == null) {
9895 error = true;
9896 continue;
9899 Arguments.Add (new Argument (e));
9900 t_args [i] = new TypeExpression (e.Type, e.Location);
9903 if (error)
9904 return null;
9906 anonymous_type = CreateAnonymousType (ec, parameters);
9907 if (anonymous_type == null)
9908 return null;
9910 RequestedType = new GenericTypeExpr (anonymous_type.TypeBuilder, new TypeArguments (t_args), loc);
9911 return base.DoResolve (ec);
9915 public class AnonymousTypeParameter : ShimExpression
9917 public readonly string Name;
9919 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9920 : base (initializer)
9922 this.Name = name;
9923 this.loc = loc;
9926 public AnonymousTypeParameter (Parameter parameter)
9927 : base (new SimpleName (parameter.Name, parameter.Location))
9929 this.Name = parameter.Name;
9930 this.loc = parameter.Location;
9933 public override bool Equals (object o)
9935 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9936 return other != null && Name == other.Name;
9939 public override int GetHashCode ()
9941 return Name.GetHashCode ();
9944 protected override Expression DoResolve (ResolveContext ec)
9946 Expression e = expr.Resolve (ec);
9947 if (e == null)
9948 return null;
9950 if (e.eclass == ExprClass.MethodGroup) {
9951 Error_InvalidInitializer (ec, e.ExprClassName);
9952 return null;
9955 type = e.Type;
9956 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9957 type == InternalType.AnonymousMethod || type.IsPointer) {
9958 Error_InvalidInitializer (ec, e.GetSignatureForError ());
9959 return null;
9962 return e;
9965 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
9967 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9968 Name, initializer);