revert 144379
[mcs.git] / mcs / expression.cs
blobb56e171327f217cdba01c5e88b55c279dcda542b
1 //
2 // expression.cs: Expression representation for the IL tree.
3 //
4 // Author:
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
7 //
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
11 #define USE_OLD
13 namespace Mono.CSharp {
14 using System;
15 using System.Collections;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Text;
20 #if NET_4_0
21 using System.Linq;
22 using SLE = System.Linq.Expressions;
23 #endif
26 // This is an user operator expression, automatically created during
27 // resolve phase
29 public class UserOperatorCall : Expression {
30 public delegate Expression ExpressionTreeExpression (ResolveContext ec, MethodGroupExpr mg);
32 protected readonly Arguments arguments;
33 protected readonly MethodGroupExpr mg;
34 readonly ExpressionTreeExpression expr_tree;
36 public UserOperatorCall (MethodGroupExpr mg, Arguments args, ExpressionTreeExpression expr_tree, Location loc)
38 this.mg = mg;
39 this.arguments = args;
40 this.expr_tree = expr_tree;
42 type = TypeManager.TypeToCoreType (((MethodInfo) mg).ReturnType);
43 eclass = ExprClass.Value;
44 this.loc = loc;
47 public override Expression CreateExpressionTree (ResolveContext ec)
49 if (expr_tree != null)
50 return expr_tree (ec, mg);
52 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
53 new NullLiteral (loc),
54 mg.CreateExpressionTree (ec));
56 return CreateExpressionFactoryCall (ec, "Call", args);
59 protected override void CloneTo (CloneContext context, Expression target)
61 // Nothing to clone
64 public override Expression DoResolve (ResolveContext ec)
67 // We are born fully resolved
69 return this;
72 public override void Emit (EmitContext ec)
74 mg.EmitCall (ec, arguments);
77 #if NET_4_0
78 public override SLE.Expression MakeExpression (BuilderContext ctx)
80 return SLE.Expression.Call ((MethodInfo) mg, Arguments.MakeExpression (arguments, ctx));
82 #endif
84 public MethodGroupExpr Method {
85 get { return mg; }
88 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
90 arguments.MutateHoistedGenericType (storey);
91 mg.MutateHoistedGenericType (storey);
95 public class ParenthesizedExpression : ShimExpression
97 public ParenthesizedExpression (Expression expr)
98 : base (expr)
100 loc = expr.Location;
103 public override Expression DoResolve (ResolveContext ec)
105 return expr.Resolve (ec);
108 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
110 return expr.DoResolveLValue (ec, right_side);
115 // Unary implements unary expressions.
117 public class Unary : Expression
119 public enum Operator : byte {
120 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
121 AddressOf, TOP
124 static Type [] [] predefined_operators;
126 public readonly Operator Oper;
127 public Expression Expr;
128 Expression enum_conversion;
130 public Unary (Operator op, Expression expr)
132 Oper = op;
133 Expr = expr;
134 loc = expr.Location;
137 // <summary>
138 // This routine will attempt to simplify the unary expression when the
139 // argument is a constant.
140 // </summary>
141 Constant TryReduceConstant (ResolveContext ec, Constant e)
143 if (e is EmptyConstantCast)
144 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
146 if (e is SideEffectConstant) {
147 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
148 return r == null ? null : new SideEffectConstant (r, e, r.Location);
151 Type expr_type = e.Type;
153 switch (Oper){
154 case Operator.UnaryPlus:
155 // Unary numeric promotions
156 if (expr_type == TypeManager.byte_type)
157 return new IntConstant (((ByteConstant)e).Value, e.Location);
158 if (expr_type == TypeManager.sbyte_type)
159 return new IntConstant (((SByteConstant)e).Value, e.Location);
160 if (expr_type == TypeManager.short_type)
161 return new IntConstant (((ShortConstant)e).Value, e.Location);
162 if (expr_type == TypeManager.ushort_type)
163 return new IntConstant (((UShortConstant)e).Value, e.Location);
164 if (expr_type == TypeManager.char_type)
165 return new IntConstant (((CharConstant)e).Value, e.Location);
167 // Predefined operators
168 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
169 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
170 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
171 expr_type == TypeManager.decimal_type) {
172 return e;
175 return null;
177 case Operator.UnaryNegation:
178 // Unary numeric promotions
179 if (expr_type == TypeManager.byte_type)
180 return new IntConstant (-((ByteConstant)e).Value, e.Location);
181 if (expr_type == TypeManager.sbyte_type)
182 return new IntConstant (-((SByteConstant)e).Value, e.Location);
183 if (expr_type == TypeManager.short_type)
184 return new IntConstant (-((ShortConstant)e).Value, e.Location);
185 if (expr_type == TypeManager.ushort_type)
186 return new IntConstant (-((UShortConstant)e).Value, e.Location);
187 if (expr_type == TypeManager.char_type)
188 return new IntConstant (-((CharConstant)e).Value, e.Location);
190 // Predefined operators
191 if (expr_type == TypeManager.int32_type) {
192 int value = ((IntConstant)e).Value;
193 if (value == int.MinValue) {
194 if (ec.ConstantCheckState) {
195 ConstantFold.Error_CompileTimeOverflow (ec, loc);
196 return null;
198 return e;
200 return new IntConstant (-value, e.Location);
202 if (expr_type == TypeManager.int64_type) {
203 long value = ((LongConstant)e).Value;
204 if (value == long.MinValue) {
205 if (ec.ConstantCheckState) {
206 ConstantFold.Error_CompileTimeOverflow (ec, loc);
207 return null;
209 return e;
211 return new LongConstant (-value, e.Location);
214 if (expr_type == TypeManager.uint32_type) {
215 UIntLiteral uil = e as UIntLiteral;
216 if (uil != null) {
217 if (uil.Value == 2147483648)
218 return new IntLiteral (int.MinValue, e.Location);
219 return new LongLiteral (-uil.Value, e.Location);
221 return new LongConstant (-((UIntConstant)e).Value, e.Location);
224 if (expr_type == TypeManager.uint64_type) {
225 ULongLiteral ull = e as ULongLiteral;
226 if (ull != null && ull.Value == 9223372036854775808)
227 return new LongLiteral (long.MinValue, e.Location);
228 return null;
231 if (expr_type == TypeManager.float_type) {
232 FloatLiteral fl = e as FloatLiteral;
233 // For better error reporting
234 if (fl != null)
235 return new FloatLiteral (-fl.Value, e.Location);
237 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
239 if (expr_type == TypeManager.double_type) {
240 DoubleLiteral dl = e as DoubleLiteral;
241 // For better error reporting
242 if (dl != null)
243 return new DoubleLiteral (-dl.Value, e.Location);
245 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
247 if (expr_type == TypeManager.decimal_type)
248 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
250 return null;
252 case Operator.LogicalNot:
253 if (expr_type != TypeManager.bool_type)
254 return null;
256 bool b = (bool)e.GetValue ();
257 return new BoolConstant (!b, e.Location);
259 case Operator.OnesComplement:
260 // Unary numeric promotions
261 if (expr_type == TypeManager.byte_type)
262 return new IntConstant (~((ByteConstant)e).Value, e.Location);
263 if (expr_type == TypeManager.sbyte_type)
264 return new IntConstant (~((SByteConstant)e).Value, e.Location);
265 if (expr_type == TypeManager.short_type)
266 return new IntConstant (~((ShortConstant)e).Value, e.Location);
267 if (expr_type == TypeManager.ushort_type)
268 return new IntConstant (~((UShortConstant)e).Value, e.Location);
269 if (expr_type == TypeManager.char_type)
270 return new IntConstant (~((CharConstant)e).Value, e.Location);
272 // Predefined operators
273 if (expr_type == TypeManager.int32_type)
274 return new IntConstant (~((IntConstant)e).Value, e.Location);
275 if (expr_type == TypeManager.uint32_type)
276 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
277 if (expr_type == TypeManager.int64_type)
278 return new LongConstant (~((LongConstant)e).Value, e.Location);
279 if (expr_type == TypeManager.uint64_type){
280 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
282 if (e is EnumConstant) {
283 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
284 if (e != null)
285 e = new EnumConstant (e, expr_type);
286 return e;
288 return null;
290 throw new Exception ("Can not constant fold: " + Oper.ToString());
293 protected Expression ResolveOperator (ResolveContext ec, Expression expr)
295 eclass = ExprClass.Value;
297 if (predefined_operators == null)
298 CreatePredefinedOperatorsTable ();
300 Type expr_type = expr.Type;
301 Expression best_expr;
304 // Primitive types first
306 if (TypeManager.IsPrimitiveType (expr_type)) {
307 best_expr = ResolvePrimitivePredefinedType (expr);
308 if (best_expr == null)
309 return null;
311 type = best_expr.Type;
312 Expr = best_expr;
313 return this;
317 // E operator ~(E x);
319 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
320 return ResolveEnumOperator (ec, expr);
322 return ResolveUserType (ec, expr);
325 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr)
327 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
328 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
329 if (best_expr == null)
330 return null;
332 Expr = best_expr;
333 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
334 type = expr.Type;
335 return EmptyCast.Create (this, type);
338 public override Expression CreateExpressionTree (ResolveContext ec)
340 return CreateExpressionTree (ec, null);
343 Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr user_op)
345 string method_name;
346 switch (Oper) {
347 case Operator.AddressOf:
348 Error_PointerInsideExpressionTree (ec);
349 return null;
350 case Operator.UnaryNegation:
351 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
352 method_name = "NegateChecked";
353 else
354 method_name = "Negate";
355 break;
356 case Operator.OnesComplement:
357 case Operator.LogicalNot:
358 method_name = "Not";
359 break;
360 case Operator.UnaryPlus:
361 method_name = "UnaryPlus";
362 break;
363 default:
364 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
367 Arguments args = new Arguments (2);
368 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
369 if (user_op != null)
370 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
371 return CreateExpressionFactoryCall (ec, method_name, args);
374 static void CreatePredefinedOperatorsTable ()
376 predefined_operators = new Type [(int) Operator.TOP] [];
379 // 7.6.1 Unary plus operator
381 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
382 TypeManager.int32_type, TypeManager.uint32_type,
383 TypeManager.int64_type, TypeManager.uint64_type,
384 TypeManager.float_type, TypeManager.double_type,
385 TypeManager.decimal_type
389 // 7.6.2 Unary minus operator
391 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
392 TypeManager.int32_type,
393 TypeManager.int64_type,
394 TypeManager.float_type, TypeManager.double_type,
395 TypeManager.decimal_type
399 // 7.6.3 Logical negation operator
401 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
402 TypeManager.bool_type
406 // 7.6.4 Bitwise complement operator
408 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
409 TypeManager.int32_type, TypeManager.uint32_type,
410 TypeManager.int64_type, TypeManager.uint64_type
415 // Unary numeric promotions
417 static Expression DoNumericPromotion (Operator op, Expression expr)
419 Type expr_type = expr.Type;
420 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
421 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
422 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
423 expr_type == TypeManager.char_type)
424 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
426 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
427 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
429 return expr;
432 public override Expression DoResolve (ResolveContext ec)
434 if (Oper == Operator.AddressOf) {
435 return ResolveAddressOf (ec);
438 Expr = Expr.Resolve (ec);
439 if (Expr == null)
440 return null;
442 if (TypeManager.IsDynamicType (Expr.Type)) {
443 Arguments args = new Arguments (1);
444 args.Add (new Argument (Expr));
445 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
448 if (TypeManager.IsNullableType (Expr.Type))
449 return new Nullable.LiftedUnaryOperator (Oper, Expr).Resolve (ec);
452 // Attempt to use a constant folding operation.
454 Constant cexpr = Expr as Constant;
455 if (cexpr != null) {
456 cexpr = TryReduceConstant (ec, cexpr);
457 if (cexpr != null)
458 return cexpr;
461 Expression expr = ResolveOperator (ec, Expr);
462 if (expr == null)
463 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
466 // Reduce unary operator on predefined types
468 if (expr == this && Oper == Operator.UnaryPlus)
469 return Expr;
471 return expr;
474 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
476 return null;
479 public override void Emit (EmitContext ec)
481 EmitOperator (ec, type);
484 protected void EmitOperator (EmitContext ec, Type type)
486 ILGenerator ig = ec.ig;
488 switch (Oper) {
489 case Operator.UnaryPlus:
490 Expr.Emit (ec);
491 break;
493 case Operator.UnaryNegation:
494 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
495 ig.Emit (OpCodes.Ldc_I4_0);
496 if (type == TypeManager.int64_type)
497 ig.Emit (OpCodes.Conv_U8);
498 Expr.Emit (ec);
499 ig.Emit (OpCodes.Sub_Ovf);
500 } else {
501 Expr.Emit (ec);
502 ig.Emit (OpCodes.Neg);
505 break;
507 case Operator.LogicalNot:
508 Expr.Emit (ec);
509 ig.Emit (OpCodes.Ldc_I4_0);
510 ig.Emit (OpCodes.Ceq);
511 break;
513 case Operator.OnesComplement:
514 Expr.Emit (ec);
515 ig.Emit (OpCodes.Not);
516 break;
518 case Operator.AddressOf:
519 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
520 break;
522 default:
523 throw new Exception ("This should not happen: Operator = "
524 + Oper.ToString ());
528 // Same trick as in Binary expression
530 if (enum_conversion != null)
531 enum_conversion.Emit (ec);
534 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
536 if (Oper == Operator.LogicalNot)
537 Expr.EmitBranchable (ec, target, !on_true);
538 else
539 base.EmitBranchable (ec, target, on_true);
542 public override void EmitSideEffect (EmitContext ec)
544 Expr.EmitSideEffect (ec);
547 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Location loc, string oper, Type t)
549 ec.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
550 oper, TypeManager.CSharpName (t));
554 // Converts operator to System.Linq.Expressions.ExpressionType enum name
556 string GetOperatorExpressionTypeName ()
558 switch (Oper) {
559 case Operator.OnesComplement:
560 return "OnesComplement";
561 case Operator.LogicalNot:
562 return "Not";
563 case Operator.UnaryNegation:
564 return "Negate";
565 case Operator.UnaryPlus:
566 return "UnaryPlus";
567 default:
568 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
572 static bool IsFloat (Type t)
574 return t == TypeManager.float_type || t == TypeManager.double_type;
578 // Returns a stringified representation of the Operator
580 public static string OperName (Operator oper)
582 switch (oper) {
583 case Operator.UnaryPlus:
584 return "+";
585 case Operator.UnaryNegation:
586 return "-";
587 case Operator.LogicalNot:
588 return "!";
589 case Operator.OnesComplement:
590 return "~";
591 case Operator.AddressOf:
592 return "&";
595 throw new NotImplementedException (oper.ToString ());
598 #if NET_4_0
599 public override SLE.Expression MakeExpression (BuilderContext ctx)
601 var expr = Expr.MakeExpression (ctx);
602 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
604 switch (Oper) {
605 case Operator.UnaryNegation:
606 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
607 case Operator.LogicalNot:
608 return SLE.Expression.Not (expr);
609 case Operator.OnesComplement:
610 return SLE.Expression.OnesComplement (expr);
611 default:
612 throw new NotImplementedException (Oper.ToString ());
615 #endif
617 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
619 type = storey.MutateType (type);
620 Expr.MutateHoistedGenericType (storey);
623 Expression ResolveAddressOf (ResolveContext ec)
625 if (!ec.IsUnsafe)
626 UnsafeError (ec, loc);
628 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
629 if (Expr == null || Expr.eclass != ExprClass.Variable) {
630 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
631 return null;
634 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
635 return null;
638 IVariableReference vr = Expr as IVariableReference;
639 bool is_fixed;
640 if (vr != null) {
641 VariableInfo vi = vr.VariableInfo;
642 if (vi != null) {
643 if (vi.LocalInfo != null)
644 vi.LocalInfo.Used = true;
647 // A variable is considered definitely assigned if you take its address.
649 vi.SetAssigned (ec);
652 is_fixed = vr.IsFixed;
653 vr.SetHasAddressTaken ();
655 if (vr.IsHoisted) {
656 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
658 } else {
659 IFixedExpression fe = Expr as IFixedExpression;
660 is_fixed = fe != null && fe.IsFixed;
663 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
664 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
667 type = TypeManager.GetPointerType (Expr.Type);
668 eclass = ExprClass.Value;
669 return this;
672 Expression ResolvePrimitivePredefinedType (Expression expr)
674 expr = DoNumericPromotion (Oper, expr);
675 Type expr_type = expr.Type;
676 Type[] predefined = predefined_operators [(int) Oper];
677 foreach (Type t in predefined) {
678 if (t == expr_type)
679 return expr;
681 return null;
685 // Perform user-operator overload resolution
687 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
689 CSharp.Operator.OpType op_type;
690 switch (Oper) {
691 case Operator.LogicalNot:
692 op_type = CSharp.Operator.OpType.LogicalNot; break;
693 case Operator.OnesComplement:
694 op_type = CSharp.Operator.OpType.OnesComplement; break;
695 case Operator.UnaryNegation:
696 op_type = CSharp.Operator.OpType.UnaryNegation; break;
697 case Operator.UnaryPlus:
698 op_type = CSharp.Operator.OpType.UnaryPlus; break;
699 default:
700 throw new InternalErrorException (Oper.ToString ());
703 string op_name = CSharp.Operator.GetMetadataName (op_type);
704 MethodGroupExpr user_op = MemberLookup (ec.Compiler, ec.CurrentType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
705 if (user_op == null)
706 return null;
708 Arguments args = new Arguments (1);
709 args.Add (new Argument (expr));
710 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
712 if (user_op == null)
713 return null;
715 Expr = args [0].Expr;
716 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
720 // Unary user type overload resolution
722 Expression ResolveUserType (ResolveContext ec, Expression expr)
724 Expression best_expr = ResolveUserOperator (ec, expr);
725 if (best_expr != null)
726 return best_expr;
728 Type[] predefined = predefined_operators [(int) Oper];
729 foreach (Type t in predefined) {
730 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false, false);
731 if (oper_expr == null)
732 continue;
735 // decimal type is predefined but has user-operators
737 if (oper_expr.Type == TypeManager.decimal_type)
738 oper_expr = ResolveUserType (ec, oper_expr);
739 else
740 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
742 if (oper_expr == null)
743 continue;
745 if (best_expr == null) {
746 best_expr = oper_expr;
747 continue;
750 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
751 if (result == 0) {
752 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
753 OperName (Oper), TypeManager.CSharpName (expr.Type));
754 break;
757 if (result == 2)
758 best_expr = oper_expr;
761 if (best_expr == null)
762 return null;
765 // HACK: Decimal user-operator is included in standard operators
767 if (best_expr.Type == TypeManager.decimal_type)
768 return best_expr;
770 Expr = best_expr;
771 type = best_expr.Type;
772 return this;
775 protected override void CloneTo (CloneContext clonectx, Expression t)
777 Unary target = (Unary) t;
779 target.Expr = Expr.Clone (clonectx);
784 // Unary operators are turned into Indirection expressions
785 // after semantic analysis (this is so we can take the address
786 // of an indirection).
788 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
789 Expression expr;
790 LocalTemporary temporary;
791 bool prepared;
793 public Indirection (Expression expr, Location l)
795 this.expr = expr;
796 loc = l;
799 public override Expression CreateExpressionTree (ResolveContext ec)
801 Error_PointerInsideExpressionTree (ec);
802 return null;
805 protected override void CloneTo (CloneContext clonectx, Expression t)
807 Indirection target = (Indirection) t;
808 target.expr = expr.Clone (clonectx);
811 public override void Emit (EmitContext ec)
813 if (!prepared)
814 expr.Emit (ec);
816 LoadFromPtr (ec.ig, Type);
819 public void Emit (EmitContext ec, bool leave_copy)
821 Emit (ec);
822 if (leave_copy) {
823 ec.ig.Emit (OpCodes.Dup);
824 temporary = new LocalTemporary (expr.Type);
825 temporary.Store (ec);
829 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
831 prepared = prepare_for_load;
833 expr.Emit (ec);
835 if (prepare_for_load)
836 ec.ig.Emit (OpCodes.Dup);
838 source.Emit (ec);
839 if (leave_copy) {
840 ec.ig.Emit (OpCodes.Dup);
841 temporary = new LocalTemporary (expr.Type);
842 temporary.Store (ec);
845 StoreFromPtr (ec.ig, type);
847 if (temporary != null) {
848 temporary.Emit (ec);
849 temporary.Release (ec);
853 public void AddressOf (EmitContext ec, AddressOp Mode)
855 expr.Emit (ec);
858 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
860 return DoResolve (ec);
863 public override Expression DoResolve (ResolveContext ec)
865 expr = expr.Resolve (ec);
866 if (expr == null)
867 return null;
869 if (!ec.IsUnsafe)
870 UnsafeError (ec, loc);
872 if (!expr.Type.IsPointer) {
873 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
874 return null;
877 if (expr.Type == TypeManager.void_ptr_type) {
878 ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
879 return null;
882 type = TypeManager.GetElementType (expr.Type);
883 eclass = ExprClass.Variable;
884 return this;
887 public bool IsFixed {
888 get { return true; }
891 public override string ToString ()
893 return "*(" + expr + ")";
897 /// <summary>
898 /// Unary Mutator expressions (pre and post ++ and --)
899 /// </summary>
901 /// <remarks>
902 /// UnaryMutator implements ++ and -- expressions. It derives from
903 /// ExpressionStatement becuase the pre/post increment/decrement
904 /// operators can be used in a statement context.
906 /// FIXME: Idea, we could split this up in two classes, one simpler
907 /// for the common case, and one with the extra fields for more complex
908 /// classes (indexers require temporary access; overloaded require method)
910 /// </remarks>
911 public class UnaryMutator : ExpressionStatement {
912 [Flags]
913 public enum Mode : byte {
914 IsIncrement = 0,
915 IsDecrement = 1,
916 IsPre = 0,
917 IsPost = 2,
919 PreIncrement = 0,
920 PreDecrement = IsDecrement,
921 PostIncrement = IsPost,
922 PostDecrement = IsPost | IsDecrement
925 Mode mode;
926 bool is_expr, recurse;
928 Expression expr;
930 // Holds the real operation
931 Expression operation;
933 public UnaryMutator (Mode m, Expression e)
935 mode = m;
936 loc = e.Location;
937 expr = e;
940 public override Expression CreateExpressionTree (ResolveContext ec)
942 return new SimpleAssign (this, this).CreateExpressionTree (ec);
945 public override Expression DoResolve (ResolveContext ec)
947 expr = expr.Resolve (ec);
949 if (expr == null)
950 return null;
952 if (TypeManager.IsDynamicType (expr.Type)) {
953 Arguments args = new Arguments (1);
954 args.Add (new Argument (expr));
955 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
958 eclass = ExprClass.Value;
960 if (TypeManager.IsNullableType (expr.Type))
961 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
963 return ResolveOperator (ec);
966 void EmitCode (EmitContext ec, bool is_expr)
968 recurse = true;
969 this.is_expr = is_expr;
970 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
973 public override void Emit (EmitContext ec)
976 // We use recurse to allow ourselfs to be the source
977 // of an assignment. This little hack prevents us from
978 // having to allocate another expression
980 if (recurse) {
981 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
983 operation.Emit (ec);
985 recurse = false;
986 return;
989 EmitCode (ec, true);
992 public override void EmitStatement (EmitContext ec)
994 EmitCode (ec, false);
998 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1000 string GetOperatorExpressionTypeName ()
1002 return IsDecrement ? "Decrement" : "Increment";
1005 bool IsDecrement {
1006 get { return (mode & Mode.IsDecrement) != 0; }
1010 // Returns whether an object of type `t' can be incremented
1011 // or decremented with add/sub (ie, basically whether we can
1012 // use pre-post incr-decr operations on it, but it is not a
1013 // System.Decimal, which we require operator overloading to catch)
1015 static bool IsPredefinedOperator (Type t)
1017 return (TypeManager.IsPrimitiveType (t) && t != TypeManager.bool_type) ||
1018 TypeManager.IsEnumType (t) ||
1019 t.IsPointer && t != TypeManager.void_ptr_type;
1022 #if NET_4_0
1023 public override SLE.Expression MakeExpression (BuilderContext ctx)
1025 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1026 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1027 return SLE.Expression.Assign (target, source);
1029 #endif
1031 protected override void CloneTo (CloneContext clonectx, Expression t)
1033 UnaryMutator target = (UnaryMutator) t;
1035 target.expr = expr.Clone (clonectx);
1038 Expression ResolveOperator (ResolveContext ec)
1040 type = expr.Type;
1042 if (expr is RuntimeValueExpression) {
1043 operation = expr;
1044 } else {
1045 // Use itself at the top of the stack
1046 operation = new EmptyExpression (type);
1050 // The operand of the prefix/postfix increment decrement operators
1051 // should be an expression that is classified as a variable,
1052 // a property access or an indexer access
1054 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1055 expr = expr.ResolveLValue (ec, expr);
1056 } else {
1057 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1061 // 1. Check predefined types
1063 if (IsPredefinedOperator (type)) {
1064 // TODO: Move to IntConstant once I get rid of int32_type
1065 var one = new IntConstant (1, loc);
1067 // TODO: Cache this based on type when using EmptyExpression in
1068 // context cache
1069 Binary.Operator op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1070 operation = new Binary (op, operation, one);
1071 operation = operation.Resolve (ec);
1072 if (operation.Type != type)
1073 operation = Convert.ExplicitNumericConversion (operation, type);
1075 return this;
1079 // Step 2: Perform Operator Overload location
1081 MethodGroupExpr mg;
1082 string op_name;
1084 if (IsDecrement)
1085 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
1086 else
1087 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
1089 mg = MemberLookup (ec.Compiler, ec.CurrentType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1091 if (mg != null) {
1092 Arguments args = new Arguments (1);
1093 args.Add (new Argument (expr));
1094 mg = mg.OverloadResolve (ec, ref args, false, loc);
1095 if (mg == null)
1096 return null;
1098 args[0].Expr = operation;
1099 operation = new UserOperatorCall (mg, args, null, loc);
1100 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1101 return this;
1104 string name = IsDecrement ?
1105 Operator.GetName (Operator.OpType.Decrement) :
1106 Operator.GetName (Operator.OpType.Increment);
1108 Unary.Error_OperatorCannotBeApplied (ec, loc, name, type);
1109 return null;
1113 /// <summary>
1114 /// Base class for the `Is' and `As' classes.
1115 /// </summary>
1117 /// <remarks>
1118 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1119 /// size.
1120 /// </remarks>
1121 public abstract class Probe : Expression {
1122 public Expression ProbeType;
1123 protected Expression expr;
1124 protected TypeExpr probe_type_expr;
1126 public Probe (Expression expr, Expression probe_type, Location l)
1128 ProbeType = probe_type;
1129 loc = l;
1130 this.expr = expr;
1133 public Expression Expr {
1134 get {
1135 return expr;
1139 public override Expression DoResolve (ResolveContext ec)
1141 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1142 if (probe_type_expr == null)
1143 return null;
1145 expr = expr.Resolve (ec);
1146 if (expr == null)
1147 return null;
1149 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1150 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1151 OperatorName);
1154 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1155 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1156 OperatorName);
1157 return null;
1160 if (expr.Type == InternalType.AnonymousMethod) {
1161 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1162 OperatorName);
1163 return null;
1166 return this;
1169 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1171 expr.MutateHoistedGenericType (storey);
1172 probe_type_expr.MutateHoistedGenericType (storey);
1175 protected abstract string OperatorName { get; }
1177 protected override void CloneTo (CloneContext clonectx, Expression t)
1179 Probe target = (Probe) t;
1181 target.expr = expr.Clone (clonectx);
1182 target.ProbeType = ProbeType.Clone (clonectx);
1187 /// <summary>
1188 /// Implementation of the `is' operator.
1189 /// </summary>
1190 public class Is : Probe {
1191 Nullable.Unwrap expr_unwrap;
1193 public Is (Expression expr, Expression probe_type, Location l)
1194 : base (expr, probe_type, l)
1198 public override Expression CreateExpressionTree (ResolveContext ec)
1200 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1201 expr.CreateExpressionTree (ec),
1202 new TypeOf (probe_type_expr, loc));
1204 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1207 public override void Emit (EmitContext ec)
1209 ILGenerator ig = ec.ig;
1210 if (expr_unwrap != null) {
1211 expr_unwrap.EmitCheck (ec);
1212 return;
1215 expr.Emit (ec);
1216 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1217 ig.Emit (OpCodes.Ldnull);
1218 ig.Emit (OpCodes.Cgt_Un);
1221 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1223 ILGenerator ig = ec.ig;
1224 if (expr_unwrap != null) {
1225 expr_unwrap.EmitCheck (ec);
1226 } else {
1227 expr.Emit (ec);
1228 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1230 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1233 Expression CreateConstantResult (ResolveContext ec, bool result)
1235 if (result)
1236 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1237 TypeManager.CSharpName (probe_type_expr.Type));
1238 else
1239 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1240 TypeManager.CSharpName (probe_type_expr.Type));
1242 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1245 public override Expression DoResolve (ResolveContext ec)
1247 if (base.DoResolve (ec) == null)
1248 return null;
1250 Type d = expr.Type;
1251 bool d_is_nullable = false;
1254 // If E is a method group or the null literal, or if the type of E is a reference
1255 // type or a nullable type and the value of E is null, the result is false
1257 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1258 return CreateConstantResult (ec, false);
1260 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1261 d = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (d) [0]);
1262 d_is_nullable = true;
1265 type = TypeManager.bool_type;
1266 eclass = ExprClass.Value;
1267 Type t = probe_type_expr.Type;
1268 bool t_is_nullable = false;
1269 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1270 t = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (t) [0]);
1271 t_is_nullable = true;
1274 if (TypeManager.IsStruct (t)) {
1275 if (d == t) {
1277 // D and T are the same value types but D can be null
1279 if (d_is_nullable && !t_is_nullable) {
1280 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1281 return this;
1285 // The result is true if D and T are the same value types
1287 return CreateConstantResult (ec, true);
1290 if (TypeManager.IsGenericParameter (d))
1291 return ResolveGenericParameter (ec, t, d);
1294 // An unboxing conversion exists
1296 if (Convert.ExplicitReferenceConversionExists (d, t))
1297 return this;
1298 } else {
1299 if (TypeManager.IsGenericParameter (t))
1300 return ResolveGenericParameter (ec, d, t);
1302 if (TypeManager.IsStruct (d)) {
1303 bool temp;
1304 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1305 return CreateConstantResult (ec, true);
1306 } else {
1307 if (TypeManager.IsGenericParameter (d))
1308 return ResolveGenericParameter (ec, t, d);
1310 if (TypeManager.ContainsGenericParameters (d))
1311 return this;
1313 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1314 Convert.ExplicitReferenceConversionExists (d, t)) {
1315 return this;
1320 return CreateConstantResult (ec, false);
1323 Expression ResolveGenericParameter (ResolveContext ec, Type d, Type t)
1325 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1326 if (constraints != null) {
1327 if (constraints.IsReferenceType && TypeManager.IsStruct (d))
1328 return CreateConstantResult (ec, false);
1331 if (TypeManager.IsGenericParameter (expr.Type)) {
1332 if (constraints != null && constraints.IsValueType && expr.Type == t)
1333 return CreateConstantResult (ec, true);
1335 expr = new BoxedCast (expr, d);
1338 return this;
1341 protected override string OperatorName {
1342 get { return "is"; }
1346 /// <summary>
1347 /// Implementation of the `as' operator.
1348 /// </summary>
1349 public class As : Probe {
1350 bool do_isinst;
1351 Expression resolved_type;
1353 public As (Expression expr, Expression probe_type, Location l)
1354 : base (expr, probe_type, l)
1358 public override Expression CreateExpressionTree (ResolveContext ec)
1360 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1361 expr.CreateExpressionTree (ec),
1362 new TypeOf (probe_type_expr, loc));
1364 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1367 public override void Emit (EmitContext ec)
1369 ILGenerator ig = ec.ig;
1371 expr.Emit (ec);
1373 if (do_isinst)
1374 ig.Emit (OpCodes.Isinst, type);
1376 if (TypeManager.IsGenericParameter (type) || TypeManager.IsNullableType (type))
1377 ig.Emit (OpCodes.Unbox_Any, type);
1380 public override Expression DoResolve (ResolveContext ec)
1382 // Because expr is modified
1383 if (eclass != ExprClass.Invalid)
1384 return this;
1386 if (resolved_type == null) {
1387 resolved_type = base.DoResolve (ec);
1389 if (resolved_type == null)
1390 return null;
1393 type = probe_type_expr.Type;
1394 eclass = ExprClass.Value;
1395 Type etype = expr.Type;
1397 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1398 if (TypeManager.IsGenericParameter (type)) {
1399 ec.Report.Error (413, loc,
1400 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1401 probe_type_expr.GetSignatureForError ());
1402 } else {
1403 ec.Report.Error (77, loc,
1404 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1405 TypeManager.CSharpName (type));
1407 return null;
1410 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1411 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1414 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1415 if (e != null){
1416 expr = e;
1417 do_isinst = false;
1418 return this;
1421 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1422 if (TypeManager.IsGenericParameter (etype))
1423 expr = new BoxedCast (expr, etype);
1425 do_isinst = true;
1426 return this;
1429 if (TypeManager.ContainsGenericParameters (etype) ||
1430 TypeManager.ContainsGenericParameters (type)) {
1431 expr = new BoxedCast (expr, etype);
1432 do_isinst = true;
1433 return this;
1436 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1437 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1439 return null;
1442 protected override string OperatorName {
1443 get { return "as"; }
1446 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1448 type = storey.MutateType (type);
1449 base.MutateHoistedGenericType (storey);
1452 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1454 return expr.GetAttributableValue (ec, value_type, out value);
1458 /// <summary>
1459 /// This represents a typecast in the source language.
1461 /// FIXME: Cast expressions have an unusual set of parsing
1462 /// rules, we need to figure those out.
1463 /// </summary>
1464 public class Cast : ShimExpression {
1465 Expression target_type;
1467 public Cast (Expression cast_type, Expression expr)
1468 : this (cast_type, expr, cast_type.Location)
1472 public Cast (Expression cast_type, Expression expr, Location loc)
1473 : base (expr)
1475 this.target_type = cast_type;
1476 this.loc = loc;
1479 public Expression TargetType {
1480 get { return target_type; }
1483 public override Expression DoResolve (ResolveContext ec)
1485 expr = expr.Resolve (ec);
1486 if (expr == null)
1487 return null;
1489 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1490 if (target == null)
1491 return null;
1493 type = target.Type;
1495 if (type.IsAbstract && type.IsSealed) {
1496 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1497 return null;
1500 eclass = ExprClass.Value;
1502 Constant c = expr as Constant;
1503 if (c != null) {
1504 c = c.TryReduce (ec, type, loc);
1505 if (c != null)
1506 return c;
1509 if (type.IsPointer && !ec.IsUnsafe) {
1510 UnsafeError (ec, loc);
1511 } else if (TypeManager.IsDynamicType (expr.Type)) {
1512 Arguments arg = new Arguments (1);
1513 arg.Add (new Argument (expr));
1514 return new DynamicConversion (type, true, arg, loc).Resolve (ec);
1517 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1518 return expr;
1521 protected override void CloneTo (CloneContext clonectx, Expression t)
1523 Cast target = (Cast) t;
1525 target.target_type = target_type.Clone (clonectx);
1526 target.expr = expr.Clone (clonectx);
1530 public class ImplicitCast : ShimExpression
1532 public ImplicitCast (Expression expr, Type target)
1533 : base (expr)
1535 this.loc = expr.Location;
1536 this.type = target;
1539 public override Expression DoResolve (ResolveContext ec)
1541 expr = expr.Resolve (ec);
1542 if (expr != null)
1543 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1545 return expr;
1550 // C# 2.0 Default value expression
1552 public class DefaultValueExpression : Expression
1554 sealed class DefaultValueNullLiteral : NullLiteral
1556 public DefaultValueNullLiteral (DefaultValueExpression expr)
1557 : base (expr.type, expr.loc)
1561 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type t, bool expl)
1563 Error_ValueCannotBeConvertedCore (ec, loc, t, expl);
1568 Expression expr;
1570 public DefaultValueExpression (Expression expr, Location loc)
1572 this.expr = expr;
1573 this.loc = loc;
1576 public override Expression CreateExpressionTree (ResolveContext ec)
1578 Arguments args = new Arguments (2);
1579 args.Add (new Argument (this));
1580 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1581 return CreateExpressionFactoryCall (ec, "Constant", args);
1584 public override Expression DoResolve (ResolveContext ec)
1586 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1587 if (texpr == null)
1588 return null;
1590 type = texpr.Type;
1592 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1593 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1596 if (type.IsPointer)
1597 return new NullLiteral (Location).ConvertImplicitly (type);
1599 if (TypeManager.IsReferenceType (type))
1600 return new DefaultValueNullLiteral (this);
1602 Constant c = New.Constantify (type);
1603 if (c != null)
1604 return c;
1606 eclass = ExprClass.Variable;
1607 return this;
1610 public override void Emit (EmitContext ec)
1612 LocalTemporary temp_storage = new LocalTemporary(type);
1614 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1615 ec.ig.Emit(OpCodes.Initobj, type);
1616 temp_storage.Emit(ec);
1619 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1621 type = storey.MutateType (type);
1624 protected override void CloneTo (CloneContext clonectx, Expression t)
1626 DefaultValueExpression target = (DefaultValueExpression) t;
1628 target.expr = expr.Clone (clonectx);
1632 /// <summary>
1633 /// Binary operators
1634 /// </summary>
1635 public class Binary : Expression, IDynamicBinder
1638 protected class PredefinedOperator {
1639 protected readonly Type left;
1640 protected readonly Type right;
1641 public readonly Operator OperatorsMask;
1642 public Type ReturnType;
1644 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1645 : this (ltype, rtype, op_mask, ltype)
1649 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1650 : this (type, type, op_mask, return_type)
1654 public PredefinedOperator (Type type, Operator op_mask)
1655 : this (type, type, op_mask, type)
1659 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1661 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1662 throw new InternalErrorException ("Only masked values can be used");
1664 this.left = ltype;
1665 this.right = rtype;
1666 this.OperatorsMask = op_mask;
1667 this.ReturnType = return_type;
1670 public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1672 b.type = ReturnType;
1674 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1675 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1678 // A user operators does not support multiple user conversions, but decimal type
1679 // is considered to be predefined type therefore we apply predefined operators rules
1680 // and then look for decimal user-operator implementation
1682 if (left == TypeManager.decimal_type)
1683 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1685 return b;
1688 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1691 // We are dealing with primitive types only
1693 return left == ltype && ltype == rtype;
1696 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1698 if (TypeManager.IsEqual (left, lexpr.Type) &&
1699 TypeManager.IsEqual (right, rexpr.Type))
1700 return true;
1702 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1703 Convert.ImplicitConversionExists (ec, rexpr, right);
1706 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1708 int result = 0;
1709 if (left != null && best_operator.left != null) {
1710 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1714 // When second arguments are same as the first one, the result is same
1716 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1717 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1720 if (result == 0 || result > 2)
1721 return null;
1723 return result == 1 ? best_operator : this;
1727 class PredefinedStringOperator : PredefinedOperator {
1728 public PredefinedStringOperator (Type type, Operator op_mask)
1729 : base (type, op_mask, type)
1731 ReturnType = TypeManager.string_type;
1734 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1735 : base (ltype, rtype, op_mask)
1737 ReturnType = TypeManager.string_type;
1740 public override Expression ConvertResult (ResolveContext ec, Binary b)
1743 // Use original expression for nullable arguments
1745 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1746 if (unwrap != null)
1747 b.left = unwrap.Original;
1749 unwrap = b.right as Nullable.Unwrap;
1750 if (unwrap != null)
1751 b.right = unwrap.Original;
1753 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1754 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1757 // Start a new concat expression using converted expression
1759 return new StringConcat (b.loc, b.left, b.right).Resolve (ec);
1763 class PredefinedShiftOperator : PredefinedOperator {
1764 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1765 base (ltype, TypeManager.int32_type, op_mask)
1769 public override Expression ConvertResult (ResolveContext ec, Binary b)
1771 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1773 Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, TypeManager.int32_type, b.right.Location);
1775 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1778 // b = b.left >> b.right & (0x1f|0x3f)
1780 b.right = new Binary (Operator.BitwiseAnd,
1781 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1784 // Expression tree representation does not use & mask
1786 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1787 b.type = ReturnType;
1788 return b;
1792 class PredefinedPointerOperator : PredefinedOperator {
1793 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1794 : base (ltype, rtype, op_mask)
1798 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1799 : base (ltype, rtype, op_mask, retType)
1803 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1804 : base (type, op_mask, return_type)
1808 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1810 if (left == null) {
1811 if (!lexpr.Type.IsPointer)
1812 return false;
1813 } else {
1814 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1815 return false;
1818 if (right == null) {
1819 if (!rexpr.Type.IsPointer)
1820 return false;
1821 } else {
1822 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1823 return false;
1826 return true;
1829 public override Expression ConvertResult (ResolveContext ec, Binary b)
1831 if (left != null) {
1832 b.left = EmptyCast.Create (b.left, left);
1833 } else if (right != null) {
1834 b.right = EmptyCast.Create (b.right, right);
1837 Type r_type = ReturnType;
1838 Expression left_arg, right_arg;
1839 if (r_type == null) {
1840 if (left == null) {
1841 left_arg = b.left;
1842 right_arg = b.right;
1843 r_type = b.left.Type;
1844 } else {
1845 left_arg = b.right;
1846 right_arg = b.left;
1847 r_type = b.right.Type;
1849 } else {
1850 left_arg = b.left;
1851 right_arg = b.right;
1854 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1858 [Flags]
1859 public enum Operator {
1860 Multiply = 0 | ArithmeticMask,
1861 Division = 1 | ArithmeticMask,
1862 Modulus = 2 | ArithmeticMask,
1863 Addition = 3 | ArithmeticMask | AdditionMask,
1864 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1866 LeftShift = 5 | ShiftMask,
1867 RightShift = 6 | ShiftMask,
1869 LessThan = 7 | ComparisonMask | RelationalMask,
1870 GreaterThan = 8 | ComparisonMask | RelationalMask,
1871 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1872 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1873 Equality = 11 | ComparisonMask | EqualityMask,
1874 Inequality = 12 | ComparisonMask | EqualityMask,
1876 BitwiseAnd = 13 | BitwiseMask,
1877 ExclusiveOr = 14 | BitwiseMask,
1878 BitwiseOr = 15 | BitwiseMask,
1880 LogicalAnd = 16 | LogicalMask,
1881 LogicalOr = 17 | LogicalMask,
1884 // Operator masks
1886 ValuesOnlyMask = ArithmeticMask - 1,
1887 ArithmeticMask = 1 << 5,
1888 ShiftMask = 1 << 6,
1889 ComparisonMask = 1 << 7,
1890 EqualityMask = 1 << 8,
1891 BitwiseMask = 1 << 9,
1892 LogicalMask = 1 << 10,
1893 AdditionMask = 1 << 11,
1894 SubtractionMask = 1 << 12,
1895 RelationalMask = 1 << 13
1898 readonly Operator oper;
1899 protected Expression left, right;
1900 readonly bool is_compound;
1901 Expression enum_conversion;
1903 static PredefinedOperator [] standard_operators;
1904 static PredefinedOperator [] pointer_operators;
1906 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1907 : this (oper, left, right)
1909 this.is_compound = isCompound;
1912 public Binary (Operator oper, Expression left, Expression right)
1914 this.oper = oper;
1915 this.left = left;
1916 this.right = right;
1917 this.loc = left.Location;
1920 public Operator Oper {
1921 get {
1922 return oper;
1926 /// <summary>
1927 /// Returns a stringified representation of the Operator
1928 /// </summary>
1929 string OperName (Operator oper)
1931 string s;
1932 switch (oper){
1933 case Operator.Multiply:
1934 s = "*";
1935 break;
1936 case Operator.Division:
1937 s = "/";
1938 break;
1939 case Operator.Modulus:
1940 s = "%";
1941 break;
1942 case Operator.Addition:
1943 s = "+";
1944 break;
1945 case Operator.Subtraction:
1946 s = "-";
1947 break;
1948 case Operator.LeftShift:
1949 s = "<<";
1950 break;
1951 case Operator.RightShift:
1952 s = ">>";
1953 break;
1954 case Operator.LessThan:
1955 s = "<";
1956 break;
1957 case Operator.GreaterThan:
1958 s = ">";
1959 break;
1960 case Operator.LessThanOrEqual:
1961 s = "<=";
1962 break;
1963 case Operator.GreaterThanOrEqual:
1964 s = ">=";
1965 break;
1966 case Operator.Equality:
1967 s = "==";
1968 break;
1969 case Operator.Inequality:
1970 s = "!=";
1971 break;
1972 case Operator.BitwiseAnd:
1973 s = "&";
1974 break;
1975 case Operator.BitwiseOr:
1976 s = "|";
1977 break;
1978 case Operator.ExclusiveOr:
1979 s = "^";
1980 break;
1981 case Operator.LogicalOr:
1982 s = "||";
1983 break;
1984 case Operator.LogicalAnd:
1985 s = "&&";
1986 break;
1987 default:
1988 s = oper.ToString ();
1989 break;
1992 if (is_compound)
1993 return s + "=";
1995 return s;
1998 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2000 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2003 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2005 string l, r;
2006 l = TypeManager.CSharpName (left.Type);
2007 r = TypeManager.CSharpName (right.Type);
2009 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2010 oper, l, r);
2013 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2015 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2019 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2021 string GetOperatorExpressionTypeName ()
2023 switch (oper) {
2024 case Operator.Addition:
2025 return is_compound ? "AddAssign" : "Add";
2026 case Operator.BitwiseAnd:
2027 return is_compound ? "AndAssign" : "And";
2028 case Operator.BitwiseOr:
2029 return is_compound ? "OrAssign" : "Or";
2030 case Operator.Division:
2031 return is_compound ? "DivideAssign" : "Divide";
2032 case Operator.ExclusiveOr:
2033 return is_compound ? "ExclusiveOrAssign" : "ExclusiveOr";
2034 case Operator.Equality:
2035 return "Equal";
2036 case Operator.GreaterThan:
2037 return "GreaterThan";
2038 case Operator.GreaterThanOrEqual:
2039 return "GreaterThanOrEqual";
2040 case Operator.Inequality:
2041 return "NotEqual";
2042 case Operator.LeftShift:
2043 return is_compound ? "LeftShiftAssign" : "LeftShift";
2044 case Operator.LessThan:
2045 return "LessThan";
2046 case Operator.LessThanOrEqual:
2047 return "LessThanOrEqual";
2048 case Operator.LogicalAnd:
2049 return "And";
2050 case Operator.LogicalOr:
2051 return "Or";
2052 case Operator.Modulus:
2053 return is_compound ? "ModuloAssign" : "Modulo";
2054 case Operator.Multiply:
2055 return is_compound ? "MultiplyAssign" : "Multiply";
2056 case Operator.RightShift:
2057 return is_compound ? "RightShiftAssign" : "RightShift";
2058 case Operator.Subtraction:
2059 return is_compound ? "SubtractAssign" : "Subtract";
2060 default:
2061 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2065 static string GetOperatorMetadataName (Operator op)
2067 CSharp.Operator.OpType op_type;
2068 switch (op) {
2069 case Operator.Addition:
2070 op_type = CSharp.Operator.OpType.Addition; break;
2071 case Operator.BitwiseAnd:
2072 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2073 case Operator.BitwiseOr:
2074 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2075 case Operator.Division:
2076 op_type = CSharp.Operator.OpType.Division; break;
2077 case Operator.Equality:
2078 op_type = CSharp.Operator.OpType.Equality; break;
2079 case Operator.ExclusiveOr:
2080 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2081 case Operator.GreaterThan:
2082 op_type = CSharp.Operator.OpType.GreaterThan; break;
2083 case Operator.GreaterThanOrEqual:
2084 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2085 case Operator.Inequality:
2086 op_type = CSharp.Operator.OpType.Inequality; break;
2087 case Operator.LeftShift:
2088 op_type = CSharp.Operator.OpType.LeftShift; break;
2089 case Operator.LessThan:
2090 op_type = CSharp.Operator.OpType.LessThan; break;
2091 case Operator.LessThanOrEqual:
2092 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2093 case Operator.Modulus:
2094 op_type = CSharp.Operator.OpType.Modulus; break;
2095 case Operator.Multiply:
2096 op_type = CSharp.Operator.OpType.Multiply; break;
2097 case Operator.RightShift:
2098 op_type = CSharp.Operator.OpType.RightShift; break;
2099 case Operator.Subtraction:
2100 op_type = CSharp.Operator.OpType.Subtraction; break;
2101 default:
2102 throw new InternalErrorException (op.ToString ());
2105 return CSharp.Operator.GetMetadataName (op_type);
2108 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2110 OpCode opcode;
2111 ILGenerator ig = ec.ig;
2113 switch (oper){
2114 case Operator.Multiply:
2115 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2116 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2117 opcode = OpCodes.Mul_Ovf;
2118 else if (!IsFloat (l))
2119 opcode = OpCodes.Mul_Ovf_Un;
2120 else
2121 opcode = OpCodes.Mul;
2122 } else
2123 opcode = OpCodes.Mul;
2125 break;
2127 case Operator.Division:
2128 if (IsUnsigned (l))
2129 opcode = OpCodes.Div_Un;
2130 else
2131 opcode = OpCodes.Div;
2132 break;
2134 case Operator.Modulus:
2135 if (IsUnsigned (l))
2136 opcode = OpCodes.Rem_Un;
2137 else
2138 opcode = OpCodes.Rem;
2139 break;
2141 case Operator.Addition:
2142 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2143 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2144 opcode = OpCodes.Add_Ovf;
2145 else if (!IsFloat (l))
2146 opcode = OpCodes.Add_Ovf_Un;
2147 else
2148 opcode = OpCodes.Add;
2149 } else
2150 opcode = OpCodes.Add;
2151 break;
2153 case Operator.Subtraction:
2154 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2155 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2156 opcode = OpCodes.Sub_Ovf;
2157 else if (!IsFloat (l))
2158 opcode = OpCodes.Sub_Ovf_Un;
2159 else
2160 opcode = OpCodes.Sub;
2161 } else
2162 opcode = OpCodes.Sub;
2163 break;
2165 case Operator.RightShift:
2166 if (IsUnsigned (l))
2167 opcode = OpCodes.Shr_Un;
2168 else
2169 opcode = OpCodes.Shr;
2170 break;
2172 case Operator.LeftShift:
2173 opcode = OpCodes.Shl;
2174 break;
2176 case Operator.Equality:
2177 opcode = OpCodes.Ceq;
2178 break;
2180 case Operator.Inequality:
2181 ig.Emit (OpCodes.Ceq);
2182 ig.Emit (OpCodes.Ldc_I4_0);
2184 opcode = OpCodes.Ceq;
2185 break;
2187 case Operator.LessThan:
2188 if (IsUnsigned (l))
2189 opcode = OpCodes.Clt_Un;
2190 else
2191 opcode = OpCodes.Clt;
2192 break;
2194 case Operator.GreaterThan:
2195 if (IsUnsigned (l))
2196 opcode = OpCodes.Cgt_Un;
2197 else
2198 opcode = OpCodes.Cgt;
2199 break;
2201 case Operator.LessThanOrEqual:
2202 if (IsUnsigned (l) || IsFloat (l))
2203 ig.Emit (OpCodes.Cgt_Un);
2204 else
2205 ig.Emit (OpCodes.Cgt);
2206 ig.Emit (OpCodes.Ldc_I4_0);
2208 opcode = OpCodes.Ceq;
2209 break;
2211 case Operator.GreaterThanOrEqual:
2212 if (IsUnsigned (l) || IsFloat (l))
2213 ig.Emit (OpCodes.Clt_Un);
2214 else
2215 ig.Emit (OpCodes.Clt);
2217 ig.Emit (OpCodes.Ldc_I4_0);
2219 opcode = OpCodes.Ceq;
2220 break;
2222 case Operator.BitwiseOr:
2223 opcode = OpCodes.Or;
2224 break;
2226 case Operator.BitwiseAnd:
2227 opcode = OpCodes.And;
2228 break;
2230 case Operator.ExclusiveOr:
2231 opcode = OpCodes.Xor;
2232 break;
2234 default:
2235 throw new InternalErrorException (oper.ToString ());
2238 ig.Emit (opcode);
2241 static bool IsUnsigned (Type t)
2243 if (t.IsPointer)
2244 return true;
2246 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2247 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2250 static bool IsFloat (Type t)
2252 return t == TypeManager.float_type || t == TypeManager.double_type;
2255 Expression ResolveOperator (ResolveContext ec)
2257 Type l = left.Type;
2258 Type r = right.Type;
2259 Expression expr;
2260 bool primitives_only = false;
2262 if (standard_operators == null)
2263 CreateStandardOperatorsTable ();
2266 // Handles predefined primitive types
2268 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2269 if ((oper & Operator.ShiftMask) == 0) {
2270 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2271 return null;
2273 primitives_only = true;
2275 } else {
2276 // Pointers
2277 if (l.IsPointer || r.IsPointer)
2278 return ResolveOperatorPointer (ec, l, r);
2280 // Enums
2281 bool lenum = TypeManager.IsEnumType (l);
2282 bool renum = TypeManager.IsEnumType (r);
2283 if (lenum || renum) {
2284 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2286 // TODO: Can this be ambiguous
2287 if (expr != null)
2288 return expr;
2291 // Delegates
2292 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2293 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2295 expr = ResolveOperatorDelegate (ec, l, r);
2297 // TODO: Can this be ambiguous
2298 if (expr != null)
2299 return expr;
2302 // User operators
2303 expr = ResolveUserOperator (ec, l, r);
2304 if (expr != null)
2305 return expr;
2307 // Predefined reference types equality
2308 if ((oper & Operator.EqualityMask) != 0) {
2309 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2310 if (expr != null)
2311 return expr;
2315 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2318 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2319 // if 'left' is not an enumeration constant, create one from the type of 'right'
2320 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2322 switch (oper) {
2323 case Operator.BitwiseOr:
2324 case Operator.BitwiseAnd:
2325 case Operator.ExclusiveOr:
2326 case Operator.Equality:
2327 case Operator.Inequality:
2328 case Operator.LessThan:
2329 case Operator.LessThanOrEqual:
2330 case Operator.GreaterThan:
2331 case Operator.GreaterThanOrEqual:
2332 if (TypeManager.IsEnumType (left.Type))
2333 return left;
2335 if (left.IsZeroInteger)
2336 return left.TryReduce (ec, right.Type, loc);
2338 break;
2340 case Operator.Addition:
2341 case Operator.Subtraction:
2342 return left;
2344 case Operator.Multiply:
2345 case Operator.Division:
2346 case Operator.Modulus:
2347 case Operator.LeftShift:
2348 case Operator.RightShift:
2349 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2350 break;
2351 return left;
2353 Error_OperatorCannotBeApplied (ec, this.left, this.right);
2354 return null;
2358 // The `|' operator used on types which were extended is dangerous
2360 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2362 OpcodeCast lcast = left as OpcodeCast;
2363 if (lcast != null) {
2364 if (IsUnsigned (lcast.UnderlyingType))
2365 lcast = null;
2368 OpcodeCast rcast = right as OpcodeCast;
2369 if (rcast != null) {
2370 if (IsUnsigned (rcast.UnderlyingType))
2371 rcast = null;
2374 if (lcast == null && rcast == null)
2375 return;
2377 // FIXME: consider constants
2379 ec.Report.Warning (675, 3, loc,
2380 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2381 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2384 static void CreatePointerOperatorsTable ()
2386 ArrayList temp = new ArrayList ();
2389 // Pointer arithmetic:
2391 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2392 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2393 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2394 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2396 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2397 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2398 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2399 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2402 // T* operator + (int y, T* x);
2403 // T* operator + (uint y, T *x);
2404 // T* operator + (long y, T *x);
2405 // T* operator + (ulong y, T *x);
2407 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2408 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2409 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2410 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2413 // long operator - (T* x, T *y)
2415 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2417 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2420 static void CreateStandardOperatorsTable ()
2422 ArrayList temp = new ArrayList ();
2423 Type bool_type = TypeManager.bool_type;
2425 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2426 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2427 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2428 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2429 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2430 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2431 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2433 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2434 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2435 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2436 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2437 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2438 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2439 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2441 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2443 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2444 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2445 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2447 temp.Add (new PredefinedOperator (bool_type,
2448 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2450 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2451 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2452 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2453 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2455 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2459 // Rules used during binary numeric promotion
2461 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2463 Expression temp;
2464 Type etype;
2466 Constant c = prim_expr as Constant;
2467 if (c != null) {
2468 temp = c.ConvertImplicitly (type);
2469 if (temp != null) {
2470 prim_expr = temp;
2471 return true;
2475 if (type == TypeManager.uint32_type) {
2476 etype = prim_expr.Type;
2477 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2478 type = TypeManager.int64_type;
2480 if (type != second_expr.Type) {
2481 c = second_expr as Constant;
2482 if (c != null)
2483 temp = c.ConvertImplicitly (type);
2484 else
2485 temp = Convert.ImplicitNumericConversion (second_expr, type);
2486 if (temp == null)
2487 return false;
2488 second_expr = temp;
2491 } else if (type == TypeManager.uint64_type) {
2493 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2495 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2496 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2497 return false;
2500 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2501 if (temp == null)
2502 return false;
2504 prim_expr = temp;
2505 return true;
2509 // 7.2.6.2 Binary numeric promotions
2511 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2513 Type ltype = left.Type;
2514 Type rtype = right.Type;
2515 Expression temp;
2517 foreach (Type t in ConstantFold.binary_promotions) {
2518 if (t == ltype)
2519 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2521 if (t == rtype)
2522 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2525 Type int32 = TypeManager.int32_type;
2526 if (ltype != int32) {
2527 Constant c = left as Constant;
2528 if (c != null)
2529 temp = c.ConvertImplicitly (int32);
2530 else
2531 temp = Convert.ImplicitNumericConversion (left, int32);
2533 if (temp == null)
2534 return false;
2535 left = temp;
2538 if (rtype != int32) {
2539 Constant c = right as Constant;
2540 if (c != null)
2541 temp = c.ConvertImplicitly (int32);
2542 else
2543 temp = Convert.ImplicitNumericConversion (right, int32);
2545 if (temp == null)
2546 return false;
2547 right = temp;
2550 return true;
2553 public override Expression DoResolve (ResolveContext ec)
2555 if (left == null)
2556 return null;
2558 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2559 left = ((ParenthesizedExpression) left).Expr;
2560 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2561 if (left == null)
2562 return null;
2564 if (left.eclass == ExprClass.Type) {
2565 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2566 return null;
2568 } else
2569 left = left.Resolve (ec);
2571 if (left == null)
2572 return null;
2574 Constant lc = left as Constant;
2576 if (lc != null && lc.Type == TypeManager.bool_type &&
2577 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2578 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2580 // FIXME: resolve right expression as unreachable
2581 // right.Resolve (ec);
2583 ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2584 return left;
2587 right = right.Resolve (ec);
2588 if (right == null)
2589 return null;
2591 eclass = ExprClass.Value;
2592 Constant rc = right as Constant;
2594 // The conversion rules are ignored in enum context but why
2595 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2596 lc = EnumLiftUp (ec, lc, rc, loc);
2597 if (lc != null)
2598 rc = EnumLiftUp (ec, rc, lc, loc);
2601 if (rc != null && lc != null) {
2602 int prev_e = ec.Report.Errors;
2603 Expression e = ConstantFold.BinaryFold (
2604 ec, oper, lc, rc, loc);
2605 if (e != null || ec.Report.Errors != prev_e)
2606 return e;
2607 } else if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) && !TypeManager.IsDynamicType (left.Type) &&
2608 ((lc != null && lc.IsDefaultValue && !(lc is NullLiteral)) || (rc != null && rc.IsDefaultValue && !(rc is NullLiteral)))) {
2610 if ((ResolveOperator (ec)) == null) {
2611 Error_OperatorCannotBeApplied (ec, left, right);
2612 return null;
2616 // The result is a constant with side-effect
2618 Constant side_effect = rc == null ?
2619 new SideEffectConstant (lc, right, loc) :
2620 new SideEffectConstant (rc, left, loc);
2622 return ReducedExpression.Create (side_effect, this);
2625 // Comparison warnings
2626 if ((oper & Operator.ComparisonMask) != 0) {
2627 if (left.Equals (right)) {
2628 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2630 CheckUselessComparison (ec, lc, right.Type);
2631 CheckUselessComparison (ec, rc, left.Type);
2634 if (TypeManager.IsDynamicType (left.Type) || TypeManager.IsDynamicType (right.Type)) {
2635 Arguments args = new Arguments (2);
2636 args.Add (new Argument (left));
2637 args.Add (new Argument (right));
2638 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
2641 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2642 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2643 (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
2644 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2645 (TypeManager.IsValueType (right.Type) && left is NullLiteral)))
2646 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2648 return DoResolveCore (ec, left, right);
2651 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
2653 Expression expr = ResolveOperator (ec);
2654 if (expr == null)
2655 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
2657 if (left == null || right == null)
2658 throw new InternalErrorException ("Invalid conversion");
2660 if (oper == Operator.BitwiseOr)
2661 CheckBitwiseOrOnSignExtended (ec);
2663 return expr;
2666 #if NET_4_0
2667 public override SLE.Expression MakeExpression (BuilderContext ctx)
2669 var le = left.MakeExpression (ctx);
2670 var re = right.MakeExpression (ctx);
2671 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
2673 switch (oper) {
2674 case Operator.Addition:
2675 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
2676 case Operator.BitwiseAnd:
2677 return SLE.Expression.And (le, re);
2678 case Operator.BitwiseOr:
2679 return SLE.Expression.Or (le, re);
2680 case Operator.Division:
2681 return SLE.Expression.Divide (le, re);
2682 case Operator.Equality:
2683 return SLE.Expression.Equal (le, re);
2684 case Operator.ExclusiveOr:
2685 return SLE.Expression.ExclusiveOr (le, re);
2686 case Operator.GreaterThan:
2687 return SLE.Expression.GreaterThan (le, re);
2688 case Operator.GreaterThanOrEqual:
2689 return SLE.Expression.GreaterThanOrEqual (le, re);
2690 case Operator.Inequality:
2691 return SLE.Expression.NotEqual (le, re);
2692 case Operator.LeftShift:
2693 return SLE.Expression.LeftShift (le, re);
2694 case Operator.LessThan:
2695 return SLE.Expression.LessThan (le, re);
2696 case Operator.LessThanOrEqual:
2697 return SLE.Expression.LessThanOrEqual (le, re);
2698 case Operator.LogicalAnd:
2699 return SLE.Expression.AndAlso (le, re);
2700 case Operator.LogicalOr:
2701 return SLE.Expression.OrElse (le, re);
2702 case Operator.Modulus:
2703 return SLE.Expression.Modulo (le, re);
2704 case Operator.Multiply:
2705 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
2706 case Operator.RightShift:
2707 return SLE.Expression.RightShift (le, re);
2708 case Operator.Subtraction:
2709 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
2710 default:
2711 throw new NotImplementedException (oper.ToString ());
2714 #endif
2716 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2718 left.MutateHoistedGenericType (storey);
2719 right.MutateHoistedGenericType (storey);
2723 // D operator + (D x, D y)
2724 // D operator - (D x, D y)
2725 // bool operator == (D x, D y)
2726 // bool operator != (D x, D y)
2728 Expression ResolveOperatorDelegate (ResolveContext ec, Type l, Type r)
2730 bool is_equality = (oper & Operator.EqualityMask) != 0;
2731 if (!TypeManager.IsEqual (l, r) && !TypeManager.IsVariantOf (r, l)) {
2732 Expression tmp;
2733 if (right.eclass == ExprClass.MethodGroup || (r == InternalType.AnonymousMethod && !is_equality)) {
2734 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2735 if (tmp == null)
2736 return null;
2737 right = tmp;
2738 r = right.Type;
2739 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod && !is_equality)) {
2740 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2741 if (tmp == null)
2742 return null;
2743 left = tmp;
2744 l = left.Type;
2745 } else {
2746 return null;
2751 // Resolve delegate equality as a user operator
2753 if (is_equality)
2754 return ResolveUserOperator (ec, l, r);
2756 MethodInfo method;
2757 Arguments args = new Arguments (2);
2758 args.Add (new Argument (left));
2759 args.Add (new Argument (right));
2761 if (oper == Operator.Addition) {
2762 if (TypeManager.delegate_combine_delegate_delegate == null) {
2763 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2764 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2767 method = TypeManager.delegate_combine_delegate_delegate;
2768 } else {
2769 if (TypeManager.delegate_remove_delegate_delegate == null) {
2770 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2771 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2774 method = TypeManager.delegate_remove_delegate_delegate;
2777 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2778 mg = mg.OverloadResolve (ec, ref args, false, loc);
2780 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2784 // Enumeration operators
2786 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2789 // bool operator == (E x, E y);
2790 // bool operator != (E x, E y);
2791 // bool operator < (E x, E y);
2792 // bool operator > (E x, E y);
2793 // bool operator <= (E x, E y);
2794 // bool operator >= (E x, E y);
2796 // E operator & (E x, E y);
2797 // E operator | (E x, E y);
2798 // E operator ^ (E x, E y);
2800 // U operator - (E e, E f)
2801 // E operator - (E e, U x)
2803 // E operator + (U x, E e)
2804 // E operator + (E e, U x)
2806 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2807 (oper == Operator.Subtraction && lenum) ||
2808 (oper == Operator.Addition && (lenum != renum || type != null)))) // type != null for lifted null
2809 return null;
2811 Expression ltemp = left;
2812 Expression rtemp = right;
2813 Type underlying_type;
2814 Expression expr;
2816 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2817 if (renum) {
2818 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2819 if (expr != null) {
2820 left = expr;
2821 ltype = expr.Type;
2823 } else if (lenum) {
2824 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2825 if (expr != null) {
2826 right = expr;
2827 rtype = expr.Type;
2832 if (TypeManager.IsEqual (ltype, rtype)) {
2833 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2835 if (left is Constant)
2836 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2837 else
2838 left = EmptyCast.Create (left, underlying_type);
2840 if (right is Constant)
2841 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2842 else
2843 right = EmptyCast.Create (right, underlying_type);
2844 } else if (lenum) {
2845 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2847 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2848 Constant c = right as Constant;
2849 if (c == null || !c.IsDefaultValue)
2850 return null;
2851 } else {
2852 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2853 return null;
2855 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2858 if (left is Constant)
2859 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2860 else
2861 left = EmptyCast.Create (left, underlying_type);
2863 } else if (renum) {
2864 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2866 if (oper != Operator.Addition) {
2867 Constant c = left as Constant;
2868 if (c == null || !c.IsDefaultValue)
2869 return null;
2870 } else {
2871 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2872 return null;
2874 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2877 if (right is Constant)
2878 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2879 else
2880 right = EmptyCast.Create (right, underlying_type);
2882 } else {
2883 return null;
2887 // C# specification uses explicit cast syntax which means binary promotion
2888 // should happen, however it seems that csc does not do that
2890 if (!DoBinaryOperatorPromotion (ec)) {
2891 left = ltemp;
2892 right = rtemp;
2893 return null;
2896 Type res_type = null;
2897 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2898 Type promoted_type = lenum ? left.Type : right.Type;
2899 enum_conversion = Convert.ExplicitNumericConversion (
2900 new EmptyExpression (promoted_type), underlying_type);
2902 if (oper == Operator.Subtraction && renum && lenum)
2903 res_type = underlying_type;
2904 else if (oper == Operator.Addition && renum)
2905 res_type = rtype;
2906 else
2907 res_type = ltype;
2910 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2911 if (!is_compound || expr == null)
2912 return expr;
2915 // Section: 7.16.2
2919 // If the return type of the selected operator is implicitly convertible to the type of x
2921 if (Convert.ImplicitConversionExists (ec, expr, ltype))
2922 return expr;
2925 // Otherwise, if the selected operator is a predefined operator, if the return type of the
2926 // selected operator is explicitly convertible to the type of x, and if y is implicitly
2927 // convertible to the type of x or the operator is a shift operator, then the operation
2928 // is evaluated as x = (T)(x op y), where T is the type of x
2930 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
2931 if (expr == null)
2932 return null;
2934 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
2935 return expr;
2937 return null;
2941 // 7.9.6 Reference type equality operators
2943 Binary ResolveOperatorEqualityRerefence (ResolveContext ec, Type l, Type r)
2946 // operator != (object a, object b)
2947 // operator == (object a, object b)
2950 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2952 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2953 return null;
2955 type = TypeManager.bool_type;
2956 GenericConstraints constraints;
2958 bool lgen = TypeManager.IsGenericParameter (l);
2960 if (TypeManager.IsEqual (l, r)) {
2961 if (lgen) {
2963 // Only allow to compare same reference type parameter
2965 if (TypeManager.IsReferenceType (l)) {
2966 left = new BoxedCast (left, TypeManager.object_type);
2967 right = new BoxedCast (right, TypeManager.object_type);
2968 return this;
2971 return null;
2974 if (l == InternalType.AnonymousMethod)
2975 return null;
2977 if (TypeManager.IsValueType (l))
2978 return null;
2980 return this;
2983 bool rgen = TypeManager.IsGenericParameter (r);
2986 // a, Both operands are reference-type values or the value null
2987 // b, One operand is a value of type T where T is a type-parameter and
2988 // the other operand is the value null. Furthermore T does not have the
2989 // value type constrain
2991 if (left is NullLiteral || right is NullLiteral) {
2992 if (lgen) {
2993 constraints = TypeManager.GetTypeParameterConstraints (l);
2994 if (constraints != null && constraints.HasValueTypeConstraint)
2995 return null;
2997 left = new BoxedCast (left, TypeManager.object_type);
2998 return this;
3001 if (rgen) {
3002 constraints = TypeManager.GetTypeParameterConstraints (r);
3003 if (constraints != null && constraints.HasValueTypeConstraint)
3004 return null;
3006 right = new BoxedCast (right, TypeManager.object_type);
3007 return this;
3012 // An interface is converted to the object before the
3013 // standard conversion is applied. It's not clear from the
3014 // standard but it looks like it works like that.
3016 if (lgen) {
3017 if (!TypeManager.IsReferenceType (l))
3018 return null;
3020 l = TypeManager.object_type;
3021 left = new BoxedCast (left, l);
3022 } else if (l.IsInterface) {
3023 l = TypeManager.object_type;
3024 } else if (TypeManager.IsStruct (l)) {
3025 return null;
3028 if (rgen) {
3029 if (!TypeManager.IsReferenceType (r))
3030 return null;
3032 r = TypeManager.object_type;
3033 right = new BoxedCast (right, r);
3034 } else if (r.IsInterface) {
3035 r = TypeManager.object_type;
3036 } else if (TypeManager.IsStruct (r)) {
3037 return null;
3041 const string ref_comparison = "Possible unintended reference comparison. " +
3042 "Consider casting the {0} side of the expression to `string' to compare the values";
3045 // A standard implicit conversion exists from the type of either
3046 // operand to the type of the other operand
3048 if (Convert.ImplicitReferenceConversionExists (left, r)) {
3049 if (l == TypeManager.string_type)
3050 ec.Report.Warning (253, 2, loc, ref_comparison, "right");
3052 return this;
3055 if (Convert.ImplicitReferenceConversionExists (right, l)) {
3056 if (r == TypeManager.string_type)
3057 ec.Report.Warning (252, 2, loc, ref_comparison, "left");
3059 return this;
3062 return null;
3066 Expression ResolveOperatorPointer (ResolveContext ec, Type l, Type r)
3069 // bool operator == (void* x, void* y);
3070 // bool operator != (void* x, void* y);
3071 // bool operator < (void* x, void* y);
3072 // bool operator > (void* x, void* y);
3073 // bool operator <= (void* x, void* y);
3074 // bool operator >= (void* x, void* y);
3076 if ((oper & Operator.ComparisonMask) != 0) {
3077 Expression temp;
3078 if (!l.IsPointer) {
3079 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3080 if (temp == null)
3081 return null;
3082 left = temp;
3085 if (!r.IsPointer) {
3086 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3087 if (temp == null)
3088 return null;
3089 right = temp;
3092 type = TypeManager.bool_type;
3093 return this;
3096 if (pointer_operators == null)
3097 CreatePointerOperatorsTable ();
3099 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
3103 // Build-in operators method overloading
3105 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
3107 PredefinedOperator best_operator = null;
3108 Type l = left.Type;
3109 Type r = right.Type;
3110 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3112 foreach (PredefinedOperator po in operators) {
3113 if ((po.OperatorsMask & oper_mask) == 0)
3114 continue;
3116 if (primitives_only) {
3117 if (!po.IsPrimitiveApplicable (l, r))
3118 continue;
3119 } else {
3120 if (!po.IsApplicable (ec, left, right))
3121 continue;
3124 if (best_operator == null) {
3125 best_operator = po;
3126 if (primitives_only)
3127 break;
3129 continue;
3132 best_operator = po.ResolveBetterOperator (ec, best_operator);
3134 if (best_operator == null) {
3135 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3136 OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
3138 best_operator = po;
3139 break;
3143 if (best_operator == null)
3144 return null;
3146 Expression expr = best_operator.ConvertResult (ec, this);
3147 if (enum_type == null)
3148 return expr;
3151 // HACK: required by enum_conversion
3153 expr.Type = enum_type;
3154 return EmptyCast.Create (expr, enum_type);
3158 // Performs user-operator overloading
3160 protected virtual Expression ResolveUserOperator (ResolveContext ec, Type l, Type r)
3162 Operator user_oper;
3163 if (oper == Operator.LogicalAnd)
3164 user_oper = Operator.BitwiseAnd;
3165 else if (oper == Operator.LogicalOr)
3166 user_oper = Operator.BitwiseOr;
3167 else
3168 user_oper = oper;
3170 string op = GetOperatorMetadataName (user_oper);
3172 MethodGroupExpr left_operators = MemberLookup (ec.Compiler, ec.CurrentType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3173 MethodGroupExpr right_operators = null;
3175 if (!TypeManager.IsEqual (r, l)) {
3176 right_operators = MemberLookup (ec.Compiler, ec.CurrentType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3177 if (right_operators == null && left_operators == null)
3178 return null;
3179 } else if (left_operators == null) {
3180 return null;
3183 Arguments args = new Arguments (2);
3184 Argument larg = new Argument (left);
3185 args.Add (larg);
3186 Argument rarg = new Argument (right);
3187 args.Add (rarg);
3189 MethodGroupExpr union;
3192 // User-defined operator implementations always take precedence
3193 // over predefined operator implementations
3195 if (left_operators != null && right_operators != null) {
3196 if (IsPredefinedUserOperator (l, user_oper)) {
3197 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3198 if (union == null)
3199 union = left_operators;
3200 } else if (IsPredefinedUserOperator (r, user_oper)) {
3201 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3202 if (union == null)
3203 union = right_operators;
3204 } else {
3205 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3207 } else if (left_operators != null) {
3208 union = left_operators;
3209 } else {
3210 union = right_operators;
3213 union = union.OverloadResolve (ec, ref args, true, loc);
3214 if (union == null)
3215 return null;
3217 Expression oper_expr;
3219 // TODO: CreateExpressionTree is allocated every time
3220 if (user_oper != oper) {
3221 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3222 oper == Operator.LogicalAnd, loc).Resolve (ec);
3223 } else {
3224 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3227 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3228 // and not invoke user operator
3230 if ((oper & Operator.EqualityMask) != 0) {
3231 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3232 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3233 type = TypeManager.bool_type;
3234 if (left is NullLiteral || right is NullLiteral)
3235 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3236 } else if (l != r) {
3237 MethodInfo mi = (MethodInfo) union;
3240 // Two System.Delegate(s) are never equal
3242 if (mi.DeclaringType == TypeManager.multicast_delegate_type)
3243 return null;
3248 left = larg.Expr;
3249 right = rarg.Expr;
3250 return oper_expr;
3253 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3255 return null;
3258 private void CheckUselessComparison (ResolveContext ec, Constant c, Type type)
3260 if (c == null || !IsTypeIntegral (type)
3261 || c is StringConstant
3262 || c is BoolConstant
3263 || c is FloatConstant
3264 || c is DoubleConstant
3265 || c is DecimalConstant
3267 return;
3269 long value = 0;
3271 if (c is ULongConstant) {
3272 ulong uvalue = ((ULongConstant) c).Value;
3273 if (uvalue > long.MaxValue) {
3274 if (type == TypeManager.byte_type ||
3275 type == TypeManager.sbyte_type ||
3276 type == TypeManager.short_type ||
3277 type == TypeManager.ushort_type ||
3278 type == TypeManager.int32_type ||
3279 type == TypeManager.uint32_type ||
3280 type == TypeManager.int64_type ||
3281 type == TypeManager.char_type)
3282 WarnUselessComparison (ec, type);
3283 return;
3285 value = (long) uvalue;
3287 else if (c is ByteConstant)
3288 value = ((ByteConstant) c).Value;
3289 else if (c is SByteConstant)
3290 value = ((SByteConstant) c).Value;
3291 else if (c is ShortConstant)
3292 value = ((ShortConstant) c).Value;
3293 else if (c is UShortConstant)
3294 value = ((UShortConstant) c).Value;
3295 else if (c is IntConstant)
3296 value = ((IntConstant) c).Value;
3297 else if (c is UIntConstant)
3298 value = ((UIntConstant) c).Value;
3299 else if (c is LongConstant)
3300 value = ((LongConstant) c).Value;
3301 else if (c is CharConstant)
3302 value = ((CharConstant)c).Value;
3304 if (value == 0)
3305 return;
3307 if (IsValueOutOfRange (value, type))
3308 WarnUselessComparison (ec, type);
3311 static bool IsValueOutOfRange (long value, Type type)
3313 if (IsTypeUnsigned (type) && value < 0)
3314 return true;
3315 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3316 type == TypeManager.byte_type && value >= 0x100 ||
3317 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3318 type == TypeManager.ushort_type && value >= 0x10000 ||
3319 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3320 type == TypeManager.uint32_type && value >= 0x100000000;
3323 static bool IsBuildInEqualityOperator (Type t)
3325 return t == TypeManager.object_type || t == TypeManager.string_type ||
3326 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3329 static bool IsPredefinedUserOperator (Type t, Operator op)
3332 // Some predefined types have user operators
3334 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3337 private static bool IsTypeIntegral (Type type)
3339 return type == TypeManager.uint64_type ||
3340 type == TypeManager.int64_type ||
3341 type == TypeManager.uint32_type ||
3342 type == TypeManager.int32_type ||
3343 type == TypeManager.ushort_type ||
3344 type == TypeManager.short_type ||
3345 type == TypeManager.sbyte_type ||
3346 type == TypeManager.byte_type ||
3347 type == TypeManager.char_type;
3350 private static bool IsTypeUnsigned (Type type)
3352 return type == TypeManager.uint64_type ||
3353 type == TypeManager.uint32_type ||
3354 type == TypeManager.ushort_type ||
3355 type == TypeManager.byte_type ||
3356 type == TypeManager.char_type;
3359 private void WarnUselessComparison (ResolveContext ec, Type type)
3361 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}'",
3362 TypeManager.CSharpName (type));
3365 /// <remarks>
3366 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3367 /// context of a conditional bool expression. This function will return
3368 /// false if it is was possible to use EmitBranchable, or true if it was.
3370 /// The expression's code is generated, and we will generate a branch to `target'
3371 /// if the resulting expression value is equal to isTrue
3372 /// </remarks>
3373 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3375 ILGenerator ig = ec.ig;
3378 // This is more complicated than it looks, but its just to avoid
3379 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3380 // but on top of that we want for == and != to use a special path
3381 // if we are comparing against null
3383 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3384 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3387 // put the constant on the rhs, for simplicity
3389 if (left is Constant) {
3390 Expression swap = right;
3391 right = left;
3392 left = swap;
3395 if (((Constant) right).IsZeroInteger) {
3396 left.EmitBranchable (ec, target, my_on_true);
3397 return;
3399 if (right.Type == TypeManager.bool_type) {
3400 // right is a boolean, and it's not 'false' => it is 'true'
3401 left.EmitBranchable (ec, target, !my_on_true);
3402 return;
3405 } else if (oper == Operator.LogicalAnd) {
3407 if (on_true) {
3408 Label tests_end = ig.DefineLabel ();
3410 left.EmitBranchable (ec, tests_end, false);
3411 right.EmitBranchable (ec, target, true);
3412 ig.MarkLabel (tests_end);
3413 } else {
3415 // This optimizes code like this
3416 // if (true && i > 4)
3418 if (!(left is Constant))
3419 left.EmitBranchable (ec, target, false);
3421 if (!(right is Constant))
3422 right.EmitBranchable (ec, target, false);
3425 return;
3427 } else if (oper == Operator.LogicalOr){
3428 if (on_true) {
3429 left.EmitBranchable (ec, target, true);
3430 right.EmitBranchable (ec, target, true);
3432 } else {
3433 Label tests_end = ig.DefineLabel ();
3434 left.EmitBranchable (ec, tests_end, true);
3435 right.EmitBranchable (ec, target, false);
3436 ig.MarkLabel (tests_end);
3439 return;
3441 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3442 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3443 oper == Operator.Equality || oper == Operator.Inequality)) {
3444 base.EmitBranchable (ec, target, on_true);
3445 return;
3448 left.Emit (ec);
3449 right.Emit (ec);
3451 Type t = left.Type;
3452 bool is_float = IsFloat (t);
3453 bool is_unsigned = is_float || IsUnsigned (t);
3455 switch (oper){
3456 case Operator.Equality:
3457 if (on_true)
3458 ig.Emit (OpCodes.Beq, target);
3459 else
3460 ig.Emit (OpCodes.Bne_Un, target);
3461 break;
3463 case Operator.Inequality:
3464 if (on_true)
3465 ig.Emit (OpCodes.Bne_Un, target);
3466 else
3467 ig.Emit (OpCodes.Beq, target);
3468 break;
3470 case Operator.LessThan:
3471 if (on_true)
3472 if (is_unsigned && !is_float)
3473 ig.Emit (OpCodes.Blt_Un, target);
3474 else
3475 ig.Emit (OpCodes.Blt, target);
3476 else
3477 if (is_unsigned)
3478 ig.Emit (OpCodes.Bge_Un, target);
3479 else
3480 ig.Emit (OpCodes.Bge, target);
3481 break;
3483 case Operator.GreaterThan:
3484 if (on_true)
3485 if (is_unsigned && !is_float)
3486 ig.Emit (OpCodes.Bgt_Un, target);
3487 else
3488 ig.Emit (OpCodes.Bgt, target);
3489 else
3490 if (is_unsigned)
3491 ig.Emit (OpCodes.Ble_Un, target);
3492 else
3493 ig.Emit (OpCodes.Ble, target);
3494 break;
3496 case Operator.LessThanOrEqual:
3497 if (on_true)
3498 if (is_unsigned && !is_float)
3499 ig.Emit (OpCodes.Ble_Un, target);
3500 else
3501 ig.Emit (OpCodes.Ble, target);
3502 else
3503 if (is_unsigned)
3504 ig.Emit (OpCodes.Bgt_Un, target);
3505 else
3506 ig.Emit (OpCodes.Bgt, target);
3507 break;
3510 case Operator.GreaterThanOrEqual:
3511 if (on_true)
3512 if (is_unsigned && !is_float)
3513 ig.Emit (OpCodes.Bge_Un, target);
3514 else
3515 ig.Emit (OpCodes.Bge, target);
3516 else
3517 if (is_unsigned)
3518 ig.Emit (OpCodes.Blt_Un, target);
3519 else
3520 ig.Emit (OpCodes.Blt, target);
3521 break;
3522 default:
3523 throw new InternalErrorException (oper.ToString ());
3527 public override void Emit (EmitContext ec)
3529 EmitOperator (ec, left.Type);
3532 protected virtual void EmitOperator (EmitContext ec, Type l)
3534 ILGenerator ig = ec.ig;
3537 // Handle short-circuit operators differently
3538 // than the rest
3540 if ((oper & Operator.LogicalMask) != 0) {
3541 Label load_result = ig.DefineLabel ();
3542 Label end = ig.DefineLabel ();
3544 bool is_or = oper == Operator.LogicalOr;
3545 left.EmitBranchable (ec, load_result, is_or);
3546 right.Emit (ec);
3547 ig.Emit (OpCodes.Br_S, end);
3549 ig.MarkLabel (load_result);
3550 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3551 ig.MarkLabel (end);
3552 return;
3555 left.Emit (ec);
3558 // Optimize zero-based operations
3560 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3562 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3563 Constant rc = right as Constant;
3564 if (rc != null && rc.IsDefaultValue) {
3565 return;
3569 right.Emit (ec);
3570 EmitOperatorOpcode (ec, oper, l);
3573 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3574 // expression because that would wrap lifted binary operation
3576 if (enum_conversion != null)
3577 enum_conversion.Emit (ec);
3580 public override void EmitSideEffect (EmitContext ec)
3582 if ((oper & Operator.LogicalMask) != 0 ||
3583 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3584 base.EmitSideEffect (ec);
3585 } else {
3586 left.EmitSideEffect (ec);
3587 right.EmitSideEffect (ec);
3591 protected override void CloneTo (CloneContext clonectx, Expression t)
3593 Binary target = (Binary) t;
3595 target.left = left.Clone (clonectx);
3596 target.right = right.Clone (clonectx);
3599 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3601 Arguments binder_args = new Arguments (4);
3603 MemberAccess sle = new MemberAccess (new MemberAccess (
3604 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3606 MemberAccess binder = DynamicExpressionStatement.GetBinderNamespace (loc);
3608 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3609 binder_args.Add (new Argument (new BoolLiteral (ec.HasSet (ResolveContext.Options.CheckedScope), loc)));
3611 bool member_access = left is DynamicMemberBinder || right is DynamicMemberBinder;
3612 binder_args.Add (new Argument (new BoolLiteral (member_access, loc)));
3613 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (), loc)));
3615 return new New (new MemberAccess (binder, "CSharpBinaryOperationBinder", loc), binder_args, loc);
3618 public override Expression CreateExpressionTree (ResolveContext ec)
3620 return CreateExpressionTree (ec, null);
3623 Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr method)
3625 string method_name;
3626 bool lift_arg = false;
3628 switch (oper) {
3629 case Operator.Addition:
3630 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3631 method_name = "AddChecked";
3632 else
3633 method_name = "Add";
3634 break;
3635 case Operator.BitwiseAnd:
3636 method_name = "And";
3637 break;
3638 case Operator.BitwiseOr:
3639 method_name = "Or";
3640 break;
3641 case Operator.Division:
3642 method_name = "Divide";
3643 break;
3644 case Operator.Equality:
3645 method_name = "Equal";
3646 lift_arg = true;
3647 break;
3648 case Operator.ExclusiveOr:
3649 method_name = "ExclusiveOr";
3650 break;
3651 case Operator.GreaterThan:
3652 method_name = "GreaterThan";
3653 lift_arg = true;
3654 break;
3655 case Operator.GreaterThanOrEqual:
3656 method_name = "GreaterThanOrEqual";
3657 lift_arg = true;
3658 break;
3659 case Operator.Inequality:
3660 method_name = "NotEqual";
3661 lift_arg = true;
3662 break;
3663 case Operator.LeftShift:
3664 method_name = "LeftShift";
3665 break;
3666 case Operator.LessThan:
3667 method_name = "LessThan";
3668 lift_arg = true;
3669 break;
3670 case Operator.LessThanOrEqual:
3671 method_name = "LessThanOrEqual";
3672 lift_arg = true;
3673 break;
3674 case Operator.LogicalAnd:
3675 method_name = "AndAlso";
3676 break;
3677 case Operator.LogicalOr:
3678 method_name = "OrElse";
3679 break;
3680 case Operator.Modulus:
3681 method_name = "Modulo";
3682 break;
3683 case Operator.Multiply:
3684 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3685 method_name = "MultiplyChecked";
3686 else
3687 method_name = "Multiply";
3688 break;
3689 case Operator.RightShift:
3690 method_name = "RightShift";
3691 break;
3692 case Operator.Subtraction:
3693 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3694 method_name = "SubtractChecked";
3695 else
3696 method_name = "Subtract";
3697 break;
3699 default:
3700 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3703 Arguments args = new Arguments (2);
3704 args.Add (new Argument (left.CreateExpressionTree (ec)));
3705 args.Add (new Argument (right.CreateExpressionTree (ec)));
3706 if (method != null) {
3707 if (lift_arg)
3708 args.Add (new Argument (new BoolConstant (false, loc)));
3710 args.Add (new Argument (method.CreateExpressionTree (ec)));
3713 return CreateExpressionFactoryCall (ec, method_name, args);
3718 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3719 // b, c, d... may be strings or objects.
3721 public class StringConcat : Expression {
3722 Arguments arguments;
3724 public StringConcat (Location loc, Expression left, Expression right)
3726 this.loc = loc;
3727 type = TypeManager.string_type;
3728 eclass = ExprClass.Value;
3730 arguments = new Arguments (2);
3731 Append (left);
3732 Append (right);
3735 public override Expression CreateExpressionTree (ResolveContext ec)
3737 Argument arg = arguments [0];
3738 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
3742 // Creates nested calls tree from an array of arguments used for IL emit
3744 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
3746 Arguments concat_args = new Arguments (2);
3747 Arguments add_args = new Arguments (3);
3749 concat_args.Add (left);
3750 add_args.Add (new Argument (left_etree));
3752 concat_args.Add (arguments [pos]);
3753 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
3755 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3756 if (method == null)
3757 return null;
3759 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3760 if (method == null)
3761 return null;
3763 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3765 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
3766 if (++pos == arguments.Count)
3767 return expr;
3769 left = new Argument (new EmptyExpression (((MethodInfo)method).ReturnType));
3770 return CreateExpressionAddCall (ec, left, expr, pos);
3773 public override Expression DoResolve (ResolveContext ec)
3775 return this;
3778 public void Append (Expression operand)
3781 // Constant folding
3783 StringConstant sc = operand as StringConstant;
3784 if (sc != null) {
3785 if (arguments.Count != 0) {
3786 Argument last_argument = arguments [arguments.Count - 1];
3787 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3788 if (last_expr_constant != null) {
3789 last_argument.Expr = new StringConstant (
3790 last_expr_constant.Value + sc.Value, sc.Location);
3791 return;
3794 } else {
3796 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3798 StringConcat concat_oper = operand as StringConcat;
3799 if (concat_oper != null) {
3800 arguments.AddRange (concat_oper.arguments);
3801 return;
3805 arguments.Add (new Argument (operand));
3808 Expression CreateConcatMemberExpression ()
3810 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3813 public override void Emit (EmitContext ec)
3815 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3816 concat = concat.Resolve (new ResolveContext (ec.MemberContext));
3817 if (concat != null)
3818 concat.Emit (ec);
3821 #if NET_4_0
3822 public override SLE.Expression MakeExpression (BuilderContext ctx)
3824 if (arguments.Count != 2)
3825 throw new NotImplementedException ("arguments.Count != 2");
3827 var concat = TypeManager.string_type.GetMethod ("Concat", new[] { typeof (object), typeof (object) });
3828 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
3830 #endif
3832 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3834 arguments.MutateHoistedGenericType (storey);
3839 // User-defined conditional logical operator
3841 public class ConditionalLogicalOperator : UserOperatorCall {
3842 readonly bool is_and;
3843 Expression oper;
3845 public ConditionalLogicalOperator (MethodGroupExpr oper_method, Arguments arguments,
3846 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3847 : base (oper_method, arguments, expr_tree, loc)
3849 this.is_and = is_and;
3852 public override Expression DoResolve (ResolveContext ec)
3854 MethodInfo method = (MethodInfo)mg;
3855 type = TypeManager.TypeToCoreType (method.ReturnType);
3856 AParametersCollection pd = TypeManager.GetParameterData (method);
3857 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3858 ec.Report.Error (217, loc,
3859 "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",
3860 TypeManager.CSharpSignature (method));
3861 return null;
3864 Expression left_dup = new EmptyExpression (type);
3865 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3866 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3867 if (op_true == null || op_false == null) {
3868 ec.Report.Error (218, loc,
3869 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3870 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3871 return null;
3874 oper = is_and ? op_false : op_true;
3875 eclass = ExprClass.Value;
3876 return this;
3879 public override void Emit (EmitContext ec)
3881 ILGenerator ig = ec.ig;
3882 Label end_target = ig.DefineLabel ();
3885 // Emit and duplicate left argument
3887 arguments [0].Expr.Emit (ec);
3888 ig.Emit (OpCodes.Dup);
3889 arguments.RemoveAt (0);
3891 oper.EmitBranchable (ec, end_target, true);
3892 base.Emit (ec);
3893 ig.MarkLabel (end_target);
3897 public class PointerArithmetic : Expression {
3898 Expression left, right;
3899 Binary.Operator op;
3902 // We assume that `l' is always a pointer
3904 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3906 type = t;
3907 this.loc = loc;
3908 left = l;
3909 right = r;
3910 this.op = op;
3913 public override Expression CreateExpressionTree (ResolveContext ec)
3915 Error_PointerInsideExpressionTree (ec);
3916 return null;
3919 public override Expression DoResolve (ResolveContext ec)
3921 eclass = ExprClass.Variable;
3923 if (left.Type == TypeManager.void_ptr_type) {
3924 ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
3925 return null;
3928 return this;
3931 public override void Emit (EmitContext ec)
3933 Type op_type = left.Type;
3934 ILGenerator ig = ec.ig;
3936 // It must be either array or fixed buffer
3937 Type element;
3938 if (TypeManager.HasElementType (op_type)) {
3939 element = TypeManager.GetElementType (op_type);
3940 } else {
3941 FieldExpr fe = left as FieldExpr;
3942 if (fe != null)
3943 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3944 else
3945 element = op_type;
3948 int size = GetTypeSize (element);
3949 Type rtype = right.Type;
3951 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3953 // handle (pointer - pointer)
3955 left.Emit (ec);
3956 right.Emit (ec);
3957 ig.Emit (OpCodes.Sub);
3959 if (size != 1){
3960 if (size == 0)
3961 ig.Emit (OpCodes.Sizeof, element);
3962 else
3963 IntLiteral.EmitInt (ig, size);
3964 ig.Emit (OpCodes.Div);
3966 ig.Emit (OpCodes.Conv_I8);
3967 } else {
3969 // handle + and - on (pointer op int)
3971 Constant left_const = left as Constant;
3972 if (left_const != null) {
3974 // Optimize ((T*)null) pointer operations
3976 if (left_const.IsDefaultValue) {
3977 left = EmptyExpression.Null;
3978 } else {
3979 left_const = null;
3983 left.Emit (ec);
3985 Constant right_const = right as Constant;
3986 if (right_const != null) {
3988 // Optimize 0-based arithmetic
3990 if (right_const.IsDefaultValue)
3991 return;
3993 if (size != 0) {
3994 // TODO: Should be the checks resolve context sensitive?
3995 ResolveContext rc = new ResolveContext (ec.MemberContext);
3996 right = ConstantFold.BinaryFold (rc, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3997 if (right == null)
3998 return;
3999 } else {
4000 ig.Emit (OpCodes.Sizeof, element);
4001 right = EmptyExpression.Null;
4005 right.Emit (ec);
4006 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
4007 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
4008 ig.Emit (OpCodes.Conv_I);
4009 } else if (rtype == TypeManager.uint32_type) {
4010 ig.Emit (OpCodes.Conv_U);
4013 if (right_const == null && size != 1){
4014 if (size == 0)
4015 ig.Emit (OpCodes.Sizeof, element);
4016 else
4017 IntLiteral.EmitInt (ig, size);
4018 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
4019 ig.Emit (OpCodes.Conv_I8);
4021 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4024 if (left_const == null) {
4025 if (rtype == TypeManager.int64_type)
4026 ig.Emit (OpCodes.Conv_I);
4027 else if (rtype == TypeManager.uint64_type)
4028 ig.Emit (OpCodes.Conv_U);
4030 Binary.EmitOperatorOpcode (ec, op, op_type);
4037 // A boolean-expression is an expression that yields a result
4038 // of type bool
4040 public class BooleanExpression : Expression
4042 Expression expr;
4044 public BooleanExpression (Expression expr)
4046 this.expr = expr;
4047 this.loc = expr.Location;
4050 protected override void CloneTo (CloneContext clonectx, Expression t)
4052 BooleanExpression target = (BooleanExpression) t;
4053 target.expr = expr.Clone (clonectx);
4056 public override Expression CreateExpressionTree (ResolveContext ec)
4058 // TODO: We should emit IsTrue (v4) instead of direct user operator
4059 // call but that would break csc compatibility
4060 throw new NotSupportedException ();
4063 public override Expression DoResolve (ResolveContext ec)
4065 // A boolean-expression is required to be of a type
4066 // that can be implicitly converted to bool or of
4067 // a type that implements operator true
4069 expr = expr.Resolve (ec);
4070 if (expr == null)
4071 return null;
4073 Assign ass = expr as Assign;
4074 if (ass != null && ass.Source is Constant) {
4075 ec.Report.Warning (665, 3, expr.Location,
4076 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4079 if (expr.Type == TypeManager.bool_type)
4080 return expr;
4082 if (TypeManager.IsDynamicType (expr.Type)) {
4083 Arguments args = new Arguments (1);
4084 args.Add (new Argument (expr));
4085 return new DynamicUnaryConversion ("IsTrue", args, loc).Resolve (ec);
4088 type = TypeManager.bool_type;
4089 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4090 if (converted != null)
4091 return converted;
4094 // If no implicit conversion to bool exists, try using `operator true'
4096 converted = GetOperatorTrue (ec, expr, loc);
4097 if (converted == null) {
4098 expr.Error_ValueCannotBeConverted (ec, loc, type, false);
4099 return null;
4102 return converted;
4105 public override void Emit (EmitContext ec)
4107 throw new InternalErrorException ("Should not be reached");
4111 /// <summary>
4112 /// Implements the ternary conditional operator (?:)
4113 /// </summary>
4114 public class Conditional : Expression {
4115 Expression expr, true_expr, false_expr;
4117 public Conditional (BooleanExpression expr, Expression true_expr, Expression false_expr)
4119 this.expr = expr;
4120 this.true_expr = true_expr;
4121 this.false_expr = false_expr;
4122 this.loc = expr.Location;
4125 public Expression Expr {
4126 get {
4127 return expr;
4131 public Expression TrueExpr {
4132 get {
4133 return true_expr;
4137 public Expression FalseExpr {
4138 get {
4139 return false_expr;
4143 public override Expression CreateExpressionTree (ResolveContext ec)
4145 Arguments args = new Arguments (3);
4146 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4147 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4148 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4149 return CreateExpressionFactoryCall (ec, "Condition", args);
4152 public override Expression DoResolve (ResolveContext ec)
4154 expr = expr.Resolve (ec);
4155 true_expr = true_expr.Resolve (ec);
4156 false_expr = false_expr.Resolve (ec);
4158 if (true_expr == null || false_expr == null || expr == null)
4159 return null;
4161 eclass = ExprClass.Value;
4162 Type true_type = true_expr.Type;
4163 Type false_type = false_expr.Type;
4164 type = true_type;
4167 // First, if an implicit conversion exists from true_expr
4168 // to false_expr, then the result type is of type false_expr.Type
4170 if (!TypeManager.IsEqual (true_type, false_type)) {
4171 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4172 if (conv != null) {
4174 // Check if both can convert implicitl to each other's type
4176 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
4177 ec.Report.Error (172, loc,
4178 "Can not compute type of conditional expression " +
4179 "as `" + TypeManager.CSharpName (true_expr.Type) +
4180 "' and `" + TypeManager.CSharpName (false_expr.Type) +
4181 "' convert implicitly to each other");
4182 return null;
4184 type = false_type;
4185 true_expr = conv;
4186 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4187 false_expr = conv;
4188 } else {
4189 ec.Report.Error (173, loc,
4190 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4191 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4192 return null;
4196 // Dead code optimalization
4197 Constant c = expr as Constant;
4198 if (c != null){
4199 bool is_false = c.IsDefaultValue;
4200 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
4201 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
4204 return this;
4207 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4209 expr.MutateHoistedGenericType (storey);
4210 true_expr.MutateHoistedGenericType (storey);
4211 false_expr.MutateHoistedGenericType (storey);
4212 type = storey.MutateType (type);
4215 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
4217 return null;
4220 public override void Emit (EmitContext ec)
4222 ILGenerator ig = ec.ig;
4223 Label false_target = ig.DefineLabel ();
4224 Label end_target = ig.DefineLabel ();
4226 expr.EmitBranchable (ec, false_target, false);
4227 true_expr.Emit (ec);
4229 if (type.IsInterface) {
4230 LocalBuilder temp = ec.GetTemporaryLocal (type);
4231 ig.Emit (OpCodes.Stloc, temp);
4232 ig.Emit (OpCodes.Ldloc, temp);
4233 ec.FreeTemporaryLocal (temp, type);
4236 ig.Emit (OpCodes.Br, end_target);
4237 ig.MarkLabel (false_target);
4238 false_expr.Emit (ec);
4239 ig.MarkLabel (end_target);
4242 protected override void CloneTo (CloneContext clonectx, Expression t)
4244 Conditional target = (Conditional) t;
4246 target.expr = expr.Clone (clonectx);
4247 target.true_expr = true_expr.Clone (clonectx);
4248 target.false_expr = false_expr.Clone (clonectx);
4252 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4253 LocalTemporary temp;
4255 #region Abstract
4256 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4257 public abstract bool IsFixed { get; }
4258 public abstract bool IsRef { get; }
4259 public abstract string Name { get; }
4260 public abstract void SetHasAddressTaken ();
4263 // Variable IL data, it has to be protected to encapsulate hoisted variables
4265 protected abstract ILocalVariable Variable { get; }
4268 // Variable flow-analysis data
4270 public abstract VariableInfo VariableInfo { get; }
4271 #endregion
4273 public void AddressOf (EmitContext ec, AddressOp mode)
4275 HoistedVariable hv = GetHoistedVariable (ec);
4276 if (hv != null) {
4277 hv.AddressOf (ec, mode);
4278 return;
4281 Variable.EmitAddressOf (ec);
4284 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4286 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4289 public HoistedVariable GetHoistedVariable (EmitContext ec)
4291 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4294 public override string GetSignatureForError ()
4296 return Name;
4299 public override void Emit (EmitContext ec)
4301 Emit (ec, false);
4304 public override void EmitSideEffect (EmitContext ec)
4306 // do nothing
4310 // This method is used by parameters that are references, that are
4311 // being passed as references: we only want to pass the pointer (that
4312 // is already stored in the parameter, not the address of the pointer,
4313 // and not the value of the variable).
4315 public void EmitLoad (EmitContext ec)
4317 Variable.Emit (ec);
4320 public void Emit (EmitContext ec, bool leave_copy)
4322 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4324 HoistedVariable hv = GetHoistedVariable (ec);
4325 if (hv != null) {
4326 hv.Emit (ec, leave_copy);
4327 return;
4330 EmitLoad (ec);
4332 if (IsRef) {
4334 // If we are a reference, we loaded on the stack a pointer
4335 // Now lets load the real value
4337 LoadFromPtr (ec.ig, type);
4340 if (leave_copy) {
4341 ec.ig.Emit (OpCodes.Dup);
4343 if (IsRef) {
4344 temp = new LocalTemporary (Type);
4345 temp.Store (ec);
4350 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4351 bool prepare_for_load)
4353 HoistedVariable hv = GetHoistedVariable (ec);
4354 if (hv != null) {
4355 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4356 return;
4359 New n_source = source as New;
4360 if (n_source != null) {
4361 if (!n_source.Emit (ec, this)) {
4362 if (leave_copy)
4363 EmitLoad (ec);
4364 return;
4366 } else {
4367 if (IsRef)
4368 EmitLoad (ec);
4370 source.Emit (ec);
4373 if (leave_copy) {
4374 ec.ig.Emit (OpCodes.Dup);
4375 if (IsRef) {
4376 temp = new LocalTemporary (Type);
4377 temp.Store (ec);
4381 if (IsRef)
4382 StoreFromPtr (ec.ig, type);
4383 else
4384 Variable.EmitAssign (ec);
4386 if (temp != null) {
4387 temp.Emit (ec);
4388 temp.Release (ec);
4392 public bool IsHoisted {
4393 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4396 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4398 type = storey.MutateType (type);
4402 /// <summary>
4403 /// Local variables
4404 /// </summary>
4405 public class LocalVariableReference : VariableReference {
4406 readonly string name;
4407 public Block Block;
4408 public LocalInfo local_info;
4409 bool is_readonly;
4410 bool resolved; // TODO: merge with eclass
4412 public LocalVariableReference (Block block, string name, Location l)
4414 Block = block;
4415 this.name = name;
4416 loc = l;
4420 // Setting `is_readonly' to false will allow you to create a writable
4421 // reference to a read-only variable. This is used by foreach and using.
4423 public LocalVariableReference (Block block, string name, Location l,
4424 LocalInfo local_info, bool is_readonly)
4425 : this (block, name, l)
4427 this.local_info = local_info;
4428 this.is_readonly = is_readonly;
4431 public override VariableInfo VariableInfo {
4432 get { return local_info.VariableInfo; }
4435 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4437 return local_info.HoistedVariableReference;
4441 // A local variable is always fixed
4443 public override bool IsFixed {
4444 get { return true; }
4447 public override bool IsRef {
4448 get { return false; }
4451 public bool IsReadOnly {
4452 get { return is_readonly; }
4455 public override string Name {
4456 get { return name; }
4459 public bool VerifyAssigned (ResolveContext ec)
4461 VariableInfo variable_info = local_info.VariableInfo;
4462 return variable_info == null || variable_info.IsAssigned (ec, loc);
4465 void ResolveLocalInfo ()
4467 if (local_info == null) {
4468 local_info = Block.GetLocalInfo (Name);
4469 type = local_info.VariableType;
4470 is_readonly = local_info.ReadOnly;
4474 public override void SetHasAddressTaken ()
4476 local_info.AddressTaken = true;
4479 public override Expression CreateExpressionTree (ResolveContext ec)
4481 HoistedVariable hv = GetHoistedVariable (ec);
4482 if (hv != null)
4483 return hv.CreateExpressionTree (ec);
4485 Arguments arg = new Arguments (1);
4486 arg.Add (new Argument (this));
4487 return CreateExpressionFactoryCall (ec, "Constant", arg);
4490 Expression DoResolveBase (ResolveContext ec)
4492 type = local_info.VariableType;
4494 Expression e = Block.GetConstantExpression (Name);
4495 if (e != null)
4496 return e.Resolve (ec);
4498 VerifyAssigned (ec);
4501 // If we are referencing a variable from the external block
4502 // flag it for capturing
4504 if (ec.MustCaptureVariable (local_info)) {
4505 if (local_info.AddressTaken)
4506 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4508 if (ec.IsVariableCapturingRequired) {
4509 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4510 storey.CaptureLocalVariable (ec, local_info);
4514 resolved |= ec.DoFlowAnalysis;
4515 eclass = ExprClass.Variable;
4516 return this;
4519 public override Expression DoResolve (ResolveContext ec)
4521 if (resolved)
4522 return this;
4524 ResolveLocalInfo ();
4525 local_info.Used = true;
4527 if (type == null && local_info.Type is VarExpr) {
4528 local_info.VariableType = TypeManager.object_type;
4529 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
4530 return null;
4533 return DoResolveBase (ec);
4536 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4538 ResolveLocalInfo ();
4540 // is out param
4541 if (right_side == EmptyExpression.OutAccess)
4542 local_info.Used = true;
4544 // Infer implicitly typed local variable
4545 if (type == null) {
4546 VarExpr ve = local_info.Type as VarExpr;
4547 if (ve != null) {
4548 if (!ve.InferType (ec, right_side))
4549 return null;
4550 type = local_info.VariableType = ve.Type;
4554 if (is_readonly) {
4555 int code;
4556 string msg;
4557 if (right_side == EmptyExpression.OutAccess) {
4558 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4559 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4560 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4561 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4562 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4563 } else if (right_side == EmptyExpression.UnaryAddress) {
4564 code = 459; msg = "Cannot take the address of {1} `{0}'";
4565 } else {
4566 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4568 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4569 } else if (VariableInfo != null) {
4570 VariableInfo.SetAssigned (ec);
4573 return DoResolveBase (ec);
4576 public override int GetHashCode ()
4578 return Name.GetHashCode ();
4581 public override bool Equals (object obj)
4583 LocalVariableReference lvr = obj as LocalVariableReference;
4584 if (lvr == null)
4585 return false;
4587 return Name == lvr.Name && Block == lvr.Block;
4590 protected override ILocalVariable Variable {
4591 get { return local_info; }
4594 public override string ToString ()
4596 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4599 protected override void CloneTo (CloneContext clonectx, Expression t)
4601 LocalVariableReference target = (LocalVariableReference) t;
4603 target.Block = clonectx.LookupBlock (Block);
4604 if (local_info != null)
4605 target.local_info = clonectx.LookupVariable (local_info);
4609 /// <summary>
4610 /// This represents a reference to a parameter in the intermediate
4611 /// representation.
4612 /// </summary>
4613 public class ParameterReference : VariableReference {
4614 readonly ToplevelParameterInfo pi;
4616 public ParameterReference (ToplevelParameterInfo pi, Location loc)
4618 this.pi = pi;
4619 this.loc = loc;
4622 public override bool IsRef {
4623 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4626 bool HasOutModifier {
4627 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4630 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4632 return pi.Parameter.HoistedVariableReference;
4636 // A ref or out parameter is classified as a moveable variable, even
4637 // if the argument given for the parameter is a fixed variable
4639 public override bool IsFixed {
4640 get { return !IsRef; }
4643 public override string Name {
4644 get { return Parameter.Name; }
4647 public Parameter Parameter {
4648 get { return pi.Parameter; }
4651 public override VariableInfo VariableInfo {
4652 get { return pi.VariableInfo; }
4655 protected override ILocalVariable Variable {
4656 get { return Parameter; }
4659 public bool IsAssigned (ResolveContext ec, Location loc)
4661 // HACK: Variables are not captured in probing mode
4662 if (ec.IsInProbingMode)
4663 return true;
4665 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4666 return true;
4668 ec.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4669 return false;
4672 public override void SetHasAddressTaken ()
4674 Parameter.HasAddressTaken = true;
4677 void SetAssigned (ResolveContext ec)
4679 if (HasOutModifier && ec.DoFlowAnalysis)
4680 ec.CurrentBranching.SetAssigned (VariableInfo);
4683 bool DoResolveBase (ResolveContext ec)
4685 type = pi.ParameterType;
4686 eclass = ExprClass.Variable;
4688 AnonymousExpression am = ec.CurrentAnonymousMethod;
4689 if (am == null)
4690 return true;
4692 Block b = ec.CurrentBlock;
4693 while (b != null) {
4694 IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
4695 for (int i = 0; i < p.Length; ++i) {
4696 if (p [i] != Parameter)
4697 continue;
4700 // Skip closest anonymous method parameters
4702 if (b == ec.CurrentBlock && !am.IsIterator)
4703 return true;
4705 if (IsRef) {
4706 ec.Report.Error (1628, loc,
4707 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4708 Name, am.ContainerType);
4711 b = null;
4712 break;
4715 if (b != null)
4716 b = b.Toplevel.Parent;
4719 if (pi.Parameter.HasAddressTaken)
4720 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4722 if (ec.IsVariableCapturingRequired) {
4723 AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
4724 storey.CaptureParameter (ec, this);
4727 return true;
4730 public override int GetHashCode ()
4732 return Name.GetHashCode ();
4735 public override bool Equals (object obj)
4737 ParameterReference pr = obj as ParameterReference;
4738 if (pr == null)
4739 return false;
4741 return Name == pr.Name;
4744 protected override void CloneTo (CloneContext clonectx, Expression target)
4746 // Nothing to clone
4749 public override Expression CreateExpressionTree (ResolveContext ec)
4751 HoistedVariable hv = GetHoistedVariable (ec);
4752 if (hv != null)
4753 return hv.CreateExpressionTree (ec);
4755 return Parameter.ExpressionTreeVariableReference ();
4759 // Notice that for ref/out parameters, the type exposed is not the
4760 // same type exposed externally.
4762 // for "ref int a":
4763 // externally we expose "int&"
4764 // here we expose "int".
4766 // We record this in "is_ref". This means that the type system can treat
4767 // the type as it is expected, but when we generate the code, we generate
4768 // the alternate kind of code.
4770 public override Expression DoResolve (ResolveContext ec)
4772 if (!DoResolveBase (ec))
4773 return null;
4775 // HACK: Variables are not captured in probing mode
4776 if (ec.IsInProbingMode)
4777 return this;
4779 if (HasOutModifier && ec.DoFlowAnalysis &&
4780 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4781 return null;
4783 return this;
4786 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4788 if (!DoResolveBase (ec))
4789 return null;
4791 // HACK: parameters are not captured when probing is on
4792 if (!ec.IsInProbingMode)
4793 SetAssigned (ec);
4795 return this;
4798 static public void EmitLdArg (ILGenerator ig, int x)
4800 switch (x) {
4801 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4802 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4803 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4804 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4805 default:
4806 if (x > byte.MaxValue)
4807 ig.Emit (OpCodes.Ldarg, x);
4808 else
4809 ig.Emit (OpCodes.Ldarg_S, (byte) x);
4810 break;
4815 /// <summary>
4816 /// Invocation of methods or delegates.
4817 /// </summary>
4818 public class Invocation : ExpressionStatement
4820 protected Arguments arguments;
4821 protected Expression expr;
4822 protected MethodGroupExpr mg;
4823 bool arguments_resolved;
4826 // arguments is an ArrayList, but we do not want to typecast,
4827 // as it might be null.
4829 public Invocation (Expression expr, Arguments arguments)
4831 SimpleName sn = expr as SimpleName;
4832 if (sn != null)
4833 this.expr = sn.GetMethodGroup ();
4834 else
4835 this.expr = expr;
4837 this.arguments = arguments;
4838 if (expr != null)
4839 loc = expr.Location;
4842 public Invocation (Expression expr, Arguments arguments, bool arguments_resolved)
4843 : this (expr, arguments)
4845 this.arguments_resolved = arguments_resolved;
4848 public override Expression CreateExpressionTree (ResolveContext ec)
4850 Arguments args;
4853 // Special conversion for nested expression trees
4855 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4856 args = new Arguments (1);
4857 args.Add (new Argument (this));
4858 return CreateExpressionFactoryCall (ec, "Quote", args);
4861 Expression instance = mg.IsInstance ?
4862 mg.InstanceExpression.CreateExpressionTree (ec) :
4863 new NullLiteral (loc);
4865 args = Arguments.CreateForExpressionTree (ec, arguments,
4866 instance,
4867 mg.CreateExpressionTree (ec));
4869 if (mg.IsBase)
4870 MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
4872 return CreateExpressionFactoryCall (ec, "Call", args);
4875 public override Expression DoResolve (ResolveContext ec)
4877 // Don't resolve already resolved expression
4878 if (eclass != ExprClass.Invalid)
4879 return this;
4881 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4882 if (expr_resolved == null)
4883 return null;
4886 // Next, evaluate all the expressions in the argument list
4888 bool dynamic_arg = false;
4889 if (arguments != null && !arguments_resolved)
4890 arguments.Resolve (ec, out dynamic_arg);
4892 Type expr_type = expr_resolved.Type;
4893 mg = expr_resolved as MethodGroupExpr;
4895 if (dynamic_arg || TypeManager.IsDynamicType (expr_type)) {
4896 Arguments args;
4897 DynamicMemberBinder dmb = expr_resolved as DynamicMemberBinder;
4898 if (dmb != null) {
4899 args = dmb.Arguments;
4900 if (arguments != null)
4901 args.AddRange (arguments);
4902 } else if (mg == null) {
4903 if (arguments == null)
4904 args = new Arguments (1);
4905 else
4906 args = arguments;
4908 args.Insert (0, new Argument (expr_resolved));
4909 expr = null;
4910 } else {
4911 if (mg.IsBase) {
4912 ec.Report.Error (1971, loc,
4913 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
4914 mg.Name);
4915 return null;
4918 args = arguments;
4920 if (mg.IsStatic != mg.IsInstance) {
4921 if (args == null)
4922 args = new Arguments (1);
4924 if (mg.IsStatic) {
4925 args.Insert (0, new Argument (new TypeOf (new TypeExpression (mg.DeclaringType, loc), loc).Resolve (ec), Argument.AType.DynamicStatic));
4926 } else {
4927 MemberAccess ma = expr as MemberAccess;
4928 if (ma != null)
4929 args.Insert (0, new Argument (ma.Left.Resolve (ec)));
4930 else
4931 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
4936 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
4939 if (mg == null) {
4940 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4941 return (new DelegateInvocation (
4942 expr_resolved, arguments, loc)).Resolve (ec);
4945 MemberExpr me = expr_resolved as MemberExpr;
4946 if (me == null) {
4947 expr_resolved.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
4948 return null;
4951 mg = ec.LookupExtensionMethod (me.Type, me.Name, loc);
4952 if (mg == null) {
4953 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4954 expr_resolved.GetSignatureForError ());
4955 return null;
4958 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4961 mg = DoResolveOverload (ec);
4962 if (mg == null)
4963 return null;
4965 MethodInfo method = (MethodInfo)mg;
4966 if (method != null) {
4967 type = TypeManager.TypeToCoreType (method.ReturnType);
4969 // TODO: this is a copy of mg.ResolveMemberAccess method
4970 Expression iexpr = mg.InstanceExpression;
4971 if (method.IsStatic) {
4972 if (iexpr == null ||
4973 iexpr is This || iexpr is EmptyExpression ||
4974 mg.IdenticalTypeName) {
4975 mg.InstanceExpression = null;
4976 } else {
4977 MemberExpr.error176 (ec, loc, mg.GetSignatureForError ());
4978 return null;
4980 } else {
4981 if (iexpr == null || iexpr == EmptyExpression.Null) {
4982 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4988 // Only base will allow this invocation to happen.
4990 if (mg.IsBase && method.IsAbstract){
4991 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature (method));
4992 return null;
4995 if (arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
4996 if (mg.IsBase)
4997 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4998 else
4999 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5000 return null;
5003 IsSpecialMethodInvocation (ec, method, loc);
5005 if (mg.InstanceExpression != null)
5006 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
5008 eclass = ExprClass.Value;
5009 return this;
5012 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5014 return mg.OverloadResolve (ec, ref arguments, false, loc);
5017 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodBase method, Location loc)
5019 if (!TypeManager.IsSpecialMethod (method))
5020 return false;
5022 ec.Report.SymbolRelatedToPreviousError (method);
5023 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5024 TypeManager.CSharpSignature (method, true));
5026 return true;
5029 static Type[] GetVarargsTypes (MethodBase mb, Arguments arguments)
5031 AParametersCollection pd = TypeManager.GetParameterData (mb);
5033 Argument a = arguments [pd.Count - 1];
5034 Arglist list = (Arglist) a.Expr;
5036 return list.ArgumentTypes;
5039 /// <summary>
5040 /// This checks the ConditionalAttribute on the method
5041 /// </summary>
5042 public static bool IsMethodExcluded (MethodBase method, Location loc)
5044 if (method.IsConstructor)
5045 return false;
5047 method = TypeManager.DropGenericMethodArguments (method);
5048 if (method.DeclaringType.Module == RootContext.ToplevelTypes.Builder) {
5049 IMethodData md = TypeManager.GetMethod (method);
5050 if (md != null)
5051 return md.IsExcluded ();
5053 // For some methods (generated by delegate class) GetMethod returns null
5054 // because they are not included in builder_to_method table
5055 return false;
5058 return AttributeTester.IsConditionalMethodExcluded (method, loc);
5061 /// <remarks>
5062 /// is_base tells whether we want to force the use of the `call'
5063 /// opcode instead of using callvirt. Call is required to call
5064 /// a specific method, while callvirt will always use the most
5065 /// recent method in the vtable.
5067 /// is_static tells whether this is an invocation on a static method
5069 /// instance_expr is an expression that represents the instance
5070 /// it must be non-null if is_static is false.
5072 /// method is the method to invoke.
5074 /// Arguments is the list of arguments to pass to the method or constructor.
5075 /// </remarks>
5076 public static void EmitCall (EmitContext ec, bool is_base,
5077 Expression instance_expr,
5078 MethodBase method, Arguments Arguments, Location loc)
5080 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
5083 // `dup_args' leaves an extra copy of the arguments on the stack
5084 // `omit_args' does not leave any arguments at all.
5085 // So, basically, you could make one call with `dup_args' set to true,
5086 // and then another with `omit_args' set to true, and the two calls
5087 // would have the same set of arguments. However, each argument would
5088 // only have been evaluated once.
5089 public static void EmitCall (EmitContext ec, bool is_base,
5090 Expression instance_expr,
5091 MethodBase method, Arguments Arguments, Location loc,
5092 bool dup_args, bool omit_args)
5094 ILGenerator ig = ec.ig;
5095 bool struct_call = false;
5096 bool this_call = false;
5097 LocalTemporary this_arg = null;
5099 Type decl_type = method.DeclaringType;
5101 if (IsMethodExcluded (method, loc))
5102 return;
5104 bool is_static = method.IsStatic;
5105 if (!is_static){
5106 this_call = instance_expr is This;
5107 if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type))
5108 struct_call = true;
5111 // If this is ourselves, push "this"
5113 if (!omit_args) {
5114 Type t = null;
5115 Type iexpr_type = instance_expr.Type;
5118 // Push the instance expression
5120 if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
5122 // Special case: calls to a function declared in a
5123 // reference-type with a value-type argument need
5124 // to have their value boxed.
5125 if (TypeManager.IsStruct (decl_type) ||
5126 TypeManager.IsGenericParameter (iexpr_type)) {
5128 // If the expression implements IMemoryLocation, then
5129 // we can optimize and use AddressOf on the
5130 // return.
5132 // If not we have to use some temporary storage for
5133 // it.
5134 if (instance_expr is IMemoryLocation) {
5135 ((IMemoryLocation)instance_expr).
5136 AddressOf (ec, AddressOp.LoadStore);
5137 } else {
5138 LocalTemporary temp = new LocalTemporary (iexpr_type);
5139 instance_expr.Emit (ec);
5140 temp.Store (ec);
5141 temp.AddressOf (ec, AddressOp.Load);
5144 // avoid the overhead of doing this all the time.
5145 if (dup_args)
5146 t = TypeManager.GetReferenceType (iexpr_type);
5147 } else {
5148 instance_expr.Emit (ec);
5150 // FIXME: should use instance_expr is IMemoryLocation + constraint.
5151 // to help JIT to produce better code
5152 ig.Emit (OpCodes.Box, instance_expr.Type);
5153 t = TypeManager.object_type;
5155 } else {
5156 instance_expr.Emit (ec);
5157 t = instance_expr.Type;
5160 if (dup_args) {
5161 ig.Emit (OpCodes.Dup);
5162 if (Arguments != null && Arguments.Count != 0) {
5163 this_arg = new LocalTemporary (t);
5164 this_arg.Store (ec);
5170 if (!omit_args && Arguments != null)
5171 Arguments.Emit (ec, dup_args, this_arg);
5173 OpCode call_op;
5174 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
5175 call_op = OpCodes.Call;
5176 } else {
5177 call_op = OpCodes.Callvirt;
5179 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5180 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5183 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5184 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5185 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5186 return;
5190 // If you have:
5191 // this.DoFoo ();
5192 // and DoFoo is not virtual, you can omit the callvirt,
5193 // because you don't need the null checking behavior.
5195 if (method is MethodInfo)
5196 ig.Emit (call_op, (MethodInfo) method);
5197 else
5198 ig.Emit (call_op, (ConstructorInfo) method);
5201 public override void Emit (EmitContext ec)
5203 mg.EmitCall (ec, arguments);
5206 public override void EmitStatement (EmitContext ec)
5208 Emit (ec);
5211 // Pop the return value if there is one
5213 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5214 ec.ig.Emit (OpCodes.Pop);
5217 protected override void CloneTo (CloneContext clonectx, Expression t)
5219 Invocation target = (Invocation) t;
5221 if (arguments != null)
5222 target.arguments = arguments.Clone (clonectx);
5224 target.expr = expr.Clone (clonectx);
5227 #if NET_4_0
5228 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodInfo mi, Arguments args)
5230 SLE.Expression expr = SLE.Expression.Call (instance.MakeExpression (ctx), mi,
5231 Arguments.MakeExpression (args, ctx));
5233 if (mi.ReturnType == typeof (void)) {
5234 expr = SLE.Expression.Block (
5235 expr,
5236 SLE.Expression.Default (typeof (object)));
5239 return expr;
5241 #endif
5243 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5245 mg.MutateHoistedGenericType (storey);
5246 type = storey.MutateType (type);
5247 if (arguments != null) {
5248 arguments.MutateHoistedGenericType (storey);
5253 /// <summary>
5254 /// Implements the new expression
5255 /// </summary>
5256 public class New : ExpressionStatement, IMemoryLocation {
5257 Arguments Arguments;
5260 // During bootstrap, it contains the RequestedType,
5261 // but if `type' is not null, it *might* contain a NewDelegate
5262 // (because of field multi-initialization)
5264 Expression RequestedType;
5266 MethodGroupExpr method;
5268 bool is_type_parameter;
5270 public New (Expression requested_type, Arguments arguments, Location l)
5272 RequestedType = requested_type;
5273 Arguments = arguments;
5274 loc = l;
5277 /// <summary>
5278 /// Converts complex core type syntax like 'new int ()' to simple constant
5279 /// </summary>
5280 public static Constant Constantify (Type t)
5282 if (t == TypeManager.int32_type)
5283 return new IntConstant (0, Location.Null);
5284 if (t == TypeManager.uint32_type)
5285 return new UIntConstant (0, Location.Null);
5286 if (t == TypeManager.int64_type)
5287 return new LongConstant (0, Location.Null);
5288 if (t == TypeManager.uint64_type)
5289 return new ULongConstant (0, Location.Null);
5290 if (t == TypeManager.float_type)
5291 return new FloatConstant (0, Location.Null);
5292 if (t == TypeManager.double_type)
5293 return new DoubleConstant (0, Location.Null);
5294 if (t == TypeManager.short_type)
5295 return new ShortConstant (0, Location.Null);
5296 if (t == TypeManager.ushort_type)
5297 return new UShortConstant (0, Location.Null);
5298 if (t == TypeManager.sbyte_type)
5299 return new SByteConstant (0, Location.Null);
5300 if (t == TypeManager.byte_type)
5301 return new ByteConstant (0, Location.Null);
5302 if (t == TypeManager.char_type)
5303 return new CharConstant ('\0', Location.Null);
5304 if (t == TypeManager.bool_type)
5305 return new BoolConstant (false, Location.Null);
5306 if (t == TypeManager.decimal_type)
5307 return new DecimalConstant (0, Location.Null);
5308 if (TypeManager.IsEnumType (t))
5309 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5310 if (TypeManager.IsNullableType (t))
5311 return Nullable.LiftedNull.Create (t, Location.Null);
5313 return null;
5317 // Checks whether the type is an interface that has the
5318 // [ComImport, CoClass] attributes and must be treated
5319 // specially
5321 public Expression CheckComImport (ResolveContext ec)
5323 if (!type.IsInterface)
5324 return null;
5327 // Turn the call into:
5328 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5330 Type real_class = AttributeTester.GetCoClassAttribute (type);
5331 if (real_class == null)
5332 return null;
5334 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5335 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5336 return cast.Resolve (ec);
5339 public override Expression CreateExpressionTree (ResolveContext ec)
5341 Arguments args;
5342 if (method == null) {
5343 args = new Arguments (1);
5344 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5345 } else {
5346 args = Arguments.CreateForExpressionTree (ec, Arguments,
5347 method.CreateExpressionTree (ec));
5350 return CreateExpressionFactoryCall (ec, "New", args);
5353 public override Expression DoResolve (ResolveContext ec)
5356 // The New DoResolve might be called twice when initializing field
5357 // expressions (see EmitFieldInitializers, the call to
5358 // GetInitializerExpression will perform a resolve on the expression,
5359 // and later the assign will trigger another resolution
5361 // This leads to bugs (#37014)
5363 if (type != null){
5364 if (RequestedType is NewDelegate)
5365 return RequestedType;
5366 return this;
5369 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5370 if (texpr == null)
5371 return null;
5373 type = texpr.Type;
5375 if (type.IsPointer) {
5376 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5377 TypeManager.CSharpName (type));
5378 return null;
5381 if (Arguments == null) {
5382 Constant c = Constantify (type);
5383 if (c != null)
5384 return ReducedExpression.Create (c, this);
5387 if (TypeManager.IsDelegateType (type)) {
5388 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5391 if (TypeManager.IsGenericParameter (type)) {
5392 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5394 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5395 ec.Report.Error (304, loc,
5396 "Cannot create an instance of the variable type '{0}' because it doesn't have the new() constraint",
5397 TypeManager.CSharpName (type));
5398 return null;
5401 if ((Arguments != null) && (Arguments.Count != 0)) {
5402 ec.Report.Error (417, loc,
5403 "`{0}': cannot provide arguments when creating an instance of a variable type",
5404 TypeManager.CSharpName (type));
5405 return null;
5408 if (TypeManager.activator_create_instance == null) {
5409 Type activator_type = TypeManager.CoreLookupType (ec.Compiler, "System", "Activator", Kind.Class, true);
5410 if (activator_type != null) {
5411 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5412 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5416 is_type_parameter = true;
5417 eclass = ExprClass.Value;
5418 return this;
5421 if (type.IsAbstract && type.IsSealed) {
5422 ec.Report.SymbolRelatedToPreviousError (type);
5423 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5424 return null;
5427 if (type.IsInterface || type.IsAbstract){
5428 if (!TypeManager.IsGenericType (type)) {
5429 RequestedType = CheckComImport (ec);
5430 if (RequestedType != null)
5431 return RequestedType;
5434 ec.Report.SymbolRelatedToPreviousError (type);
5435 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5436 return null;
5439 bool is_struct = TypeManager.IsStruct (type);
5440 eclass = ExprClass.Value;
5443 // SRE returns a match for .ctor () on structs (the object constructor),
5444 // so we have to manually ignore it.
5446 if (is_struct && Arguments == null)
5447 return this;
5449 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5450 Expression ml = MemberLookupFinal (ec, type, type, ConstructorInfo.ConstructorName,
5451 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5453 if (Arguments != null) {
5454 bool dynamic;
5455 Arguments.Resolve (ec, out dynamic);
5457 if (dynamic) {
5458 Arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec)));
5459 return new DynamicInvocation (new SimpleName (ConstructorInfo.ConstructorName, loc), Arguments, type, loc).Resolve (ec);
5463 if (ml == null)
5464 return null;
5466 method = ml as MethodGroupExpr;
5467 if (method == null) {
5468 ml.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5469 return null;
5472 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5473 if (method == null)
5474 return null;
5476 return this;
5479 bool DoEmitTypeParameter (EmitContext ec)
5481 ILGenerator ig = ec.ig;
5483 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5484 new Type [] { type });
5486 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5487 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5488 ig.Emit (OpCodes.Call, ci);
5489 return true;
5492 // Allow DoEmit() to be called multiple times.
5493 // We need to create a new LocalTemporary each time since
5494 // you can't share LocalBuilders among ILGeneators.
5495 LocalTemporary temp = new LocalTemporary (type);
5497 Label label_activator = ig.DefineLabel ();
5498 Label label_end = ig.DefineLabel ();
5500 temp.AddressOf (ec, AddressOp.Store);
5501 ig.Emit (OpCodes.Initobj, type);
5503 temp.Emit (ec);
5504 ig.Emit (OpCodes.Box, type);
5505 ig.Emit (OpCodes.Brfalse, label_activator);
5507 temp.AddressOf (ec, AddressOp.Store);
5508 ig.Emit (OpCodes.Initobj, type);
5509 temp.Emit (ec);
5510 ig.Emit (OpCodes.Br_S, label_end);
5512 ig.MarkLabel (label_activator);
5514 ig.Emit (OpCodes.Call, ci);
5515 ig.MarkLabel (label_end);
5516 return true;
5520 // This Emit can be invoked in two contexts:
5521 // * As a mechanism that will leave a value on the stack (new object)
5522 // * As one that wont (init struct)
5524 // If we are dealing with a ValueType, we have a few
5525 // situations to deal with:
5527 // * The target is a ValueType, and we have been provided
5528 // the instance (this is easy, we are being assigned).
5530 // * The target of New is being passed as an argument,
5531 // to a boxing operation or a function that takes a
5532 // ValueType.
5534 // In this case, we need to create a temporary variable
5535 // that is the argument of New.
5537 // Returns whether a value is left on the stack
5539 // *** Implementation note ***
5541 // To benefit from this optimization, each assignable expression
5542 // has to manually cast to New and call this Emit.
5544 // TODO: It's worth to implement it for arrays and fields
5546 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5548 bool is_value_type = TypeManager.IsValueType (type);
5549 ILGenerator ig = ec.ig;
5550 VariableReference vr = target as VariableReference;
5552 if (target != null && is_value_type && (vr != null || method == null)) {
5553 target.AddressOf (ec, AddressOp.Store);
5554 } else if (vr != null && vr.IsRef) {
5555 vr.EmitLoad (ec);
5558 if (Arguments != null)
5559 Arguments.Emit (ec);
5561 if (is_value_type) {
5562 if (method == null) {
5563 ig.Emit (OpCodes.Initobj, type);
5564 return false;
5567 if (vr != null) {
5568 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5569 return false;
5573 if (is_type_parameter)
5574 return DoEmitTypeParameter (ec);
5576 ConstructorInfo ci = (ConstructorInfo) method;
5577 #if MS_COMPATIBLE
5578 if (TypeManager.IsGenericType (type) && type.IsGenericTypeDefinition)
5579 ci = TypeBuilder.GetConstructor (type, ci);
5580 #endif
5582 ig.Emit (OpCodes.Newobj, ci);
5583 return true;
5586 public override void Emit (EmitContext ec)
5588 LocalTemporary v = null;
5589 if (method == null && TypeManager.IsValueType (type)) {
5590 // TODO: Use temporary variable from pool
5591 v = new LocalTemporary (type);
5594 if (!Emit (ec, v))
5595 v.Emit (ec);
5598 public override void EmitStatement (EmitContext ec)
5600 LocalTemporary v = null;
5601 if (method == null && TypeManager.IsValueType (type)) {
5602 // TODO: Use temporary variable from pool
5603 v = new LocalTemporary (type);
5606 if (Emit (ec, v))
5607 ec.ig.Emit (OpCodes.Pop);
5610 public bool IsDefaultValueType {
5611 get {
5612 return TypeManager.IsValueType (type) && !HasInitializer && Arguments == null;
5616 public virtual bool HasInitializer {
5617 get {
5618 return false;
5622 public void AddressOf (EmitContext ec, AddressOp mode)
5624 EmitAddressOf (ec, mode);
5627 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5629 LocalTemporary value_target = new LocalTemporary (type);
5631 if (is_type_parameter) {
5632 DoEmitTypeParameter (ec);
5633 value_target.Store (ec);
5634 value_target.AddressOf (ec, mode);
5635 return value_target;
5638 if (!TypeManager.IsStruct (type)){
5640 // We throw an exception. So far, I believe we only need to support
5641 // value types:
5642 // foreach (int j in new StructType ())
5643 // see bug 42390
5645 throw new Exception ("AddressOf should not be used for classes");
5648 value_target.AddressOf (ec, AddressOp.Store);
5650 if (method == null) {
5651 ec.ig.Emit (OpCodes.Initobj, type);
5652 } else {
5653 if (Arguments != null)
5654 Arguments.Emit (ec);
5656 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5659 value_target.AddressOf (ec, mode);
5660 return value_target;
5663 protected override void CloneTo (CloneContext clonectx, Expression t)
5665 New target = (New) t;
5667 target.RequestedType = RequestedType.Clone (clonectx);
5668 if (Arguments != null){
5669 target.Arguments = Arguments.Clone (clonectx);
5673 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5675 if (method != null) {
5676 method.MutateHoistedGenericType (storey);
5677 if (Arguments != null) {
5678 Arguments.MutateHoistedGenericType (storey);
5682 type = storey.MutateType (type);
5686 /// <summary>
5687 /// 14.5.10.2: Represents an array creation expression.
5688 /// </summary>
5690 /// <remarks>
5691 /// There are two possible scenarios here: one is an array creation
5692 /// expression that specifies the dimensions and optionally the
5693 /// initialization data and the other which does not need dimensions
5694 /// specified but where initialization data is mandatory.
5695 /// </remarks>
5696 public class ArrayCreation : Expression {
5697 FullNamedExpression requested_base_type;
5698 ArrayList initializers;
5701 // The list of Argument types.
5702 // This is used to construct the `newarray' or constructor signature
5704 protected ArrayList arguments;
5706 protected Type array_element_type;
5707 bool expect_initializers = false;
5708 int num_arguments = 0;
5709 protected int dimensions;
5710 protected readonly string rank;
5712 protected ArrayList array_data;
5714 IDictionary bounds;
5716 // The number of constants in array initializers
5717 int const_initializers_count;
5718 bool only_constant_initializers;
5720 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5722 this.requested_base_type = requested_base_type;
5723 this.initializers = initializers;
5724 this.rank = rank;
5725 loc = l;
5727 arguments = new ArrayList (exprs.Count);
5729 foreach (Expression e in exprs) {
5730 arguments.Add (e);
5731 num_arguments++;
5735 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5737 this.requested_base_type = requested_base_type;
5738 this.initializers = initializers;
5739 this.rank = rank;
5740 loc = l;
5742 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5744 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5746 //dimensions = tmp.Length - 1;
5747 expect_initializers = true;
5750 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
5752 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
5755 bool CheckIndices (ResolveContext ec, ArrayList probe, int idx, bool specified_dims, int child_bounds)
5757 if (specified_dims) {
5758 Expression a = (Expression) arguments [idx];
5759 a = a.Resolve (ec);
5760 if (a == null)
5761 return false;
5763 Constant c = a as Constant;
5764 if (c != null) {
5765 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Location);
5768 if (c == null) {
5769 ec.Report.Error (150, a.Location, "A constant value is expected");
5770 return false;
5773 int value = (int) c.GetValue ();
5775 if (value != probe.Count) {
5776 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value);
5777 return false;
5780 bounds [idx] = value;
5783 only_constant_initializers = true;
5784 for (int i = 0; i < probe.Count; ++i) {
5785 object o = probe [i];
5786 if (o is ArrayList) {
5787 ArrayList sub_probe = o as ArrayList;
5788 if (idx + 1 >= dimensions){
5789 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5790 return false;
5793 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
5794 if (!ret)
5795 return false;
5796 } else if (child_bounds > 1) {
5797 ec.Report.Error (846, ((Expression) o).Location, "A nested array initializer was expected");
5798 } else {
5799 Expression element = ResolveArrayElement (ec, (Expression) o);
5800 if (element == null)
5801 continue;
5803 // Initializers with the default values can be ignored
5804 Constant c = element as Constant;
5805 if (c != null) {
5806 if (c.IsDefaultInitializer (array_element_type)) {
5807 element = null;
5809 else {
5810 ++const_initializers_count;
5812 } else {
5813 only_constant_initializers = false;
5816 array_data.Add (element);
5820 return true;
5823 public override Expression CreateExpressionTree (ResolveContext ec)
5825 Arguments args;
5827 if (array_data == null) {
5828 args = new Arguments (arguments.Count + 1);
5829 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5830 foreach (Expression a in arguments)
5831 args.Add (new Argument (a.CreateExpressionTree (ec)));
5833 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
5836 if (dimensions > 1) {
5837 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5838 return null;
5841 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
5842 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5843 if (array_data != null) {
5844 for (int i = 0; i < array_data.Count; ++i) {
5845 Expression e = (Expression) array_data [i];
5846 if (e == null)
5847 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5849 args.Add (new Argument (e.CreateExpressionTree (ec)));
5853 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
5856 public void UpdateIndices ()
5858 int i = 0;
5859 for (ArrayList probe = initializers; probe != null;) {
5860 if (probe.Count > 0 && probe [0] is ArrayList) {
5861 Expression e = new IntConstant (probe.Count, Location.Null);
5862 arguments.Add (e);
5864 bounds [i++] = probe.Count;
5866 probe = (ArrayList) probe [0];
5868 } else {
5869 Expression e = new IntConstant (probe.Count, Location.Null);
5870 arguments.Add (e);
5872 bounds [i++] = probe.Count;
5873 return;
5879 Expression first_emit;
5880 LocalTemporary first_emit_temp;
5882 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
5884 element = element.Resolve (ec);
5885 if (element == null)
5886 return null;
5888 if (element is CompoundAssign.TargetExpression) {
5889 if (first_emit != null)
5890 throw new InternalErrorException ("Can only handle one mutator at a time");
5891 first_emit = element;
5892 element = first_emit_temp = new LocalTemporary (element.Type);
5895 return Convert.ImplicitConversionRequired (
5896 ec, element, array_element_type, loc);
5899 protected bool ResolveInitializers (ResolveContext ec)
5901 if (initializers == null) {
5902 return !expect_initializers;
5906 // We use this to store all the date values in the order in which we
5907 // will need to store them in the byte blob later
5909 array_data = new ArrayList ();
5910 bounds = new System.Collections.Specialized.HybridDictionary ();
5912 if (arguments != null)
5913 return CheckIndices (ec, initializers, 0, true, dimensions);
5915 arguments = new ArrayList ();
5917 if (!CheckIndices (ec, initializers, 0, false, dimensions))
5918 return false;
5920 UpdateIndices ();
5922 return true;
5926 // Resolved the type of the array
5928 bool ResolveArrayType (ResolveContext ec)
5930 if (requested_base_type == null) {
5931 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5932 return false;
5935 if (requested_base_type is VarExpr) {
5936 ec.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5937 return false;
5940 StringBuilder array_qualifier = new StringBuilder (rank);
5943 // `In the first form allocates an array instace of the type that results
5944 // from deleting each of the individual expression from the expression list'
5946 if (num_arguments > 0) {
5947 array_qualifier.Append ("[");
5948 for (int i = num_arguments-1; i > 0; i--)
5949 array_qualifier.Append (",");
5950 array_qualifier.Append ("]");
5954 // Lookup the type
5956 TypeExpr array_type_expr;
5957 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5958 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5959 if (array_type_expr == null)
5960 return false;
5962 type = array_type_expr.Type;
5963 array_element_type = TypeManager.GetElementType (type);
5964 dimensions = type.GetArrayRank ();
5966 return true;
5969 public override Expression DoResolve (ResolveContext ec)
5971 if (type != null)
5972 return this;
5974 if (!ResolveArrayType (ec))
5975 return null;
5978 // First step is to validate the initializers and fill
5979 // in any missing bits
5981 if (!ResolveInitializers (ec))
5982 return null;
5984 for (int i = 0; i < arguments.Count; ++i) {
5985 Expression e = ((Expression) arguments[i]).Resolve (ec);
5986 if (e == null)
5987 continue;
5989 arguments [i] = ConvertExpressionToArrayIndex (ec, e);
5992 eclass = ExprClass.Value;
5993 return this;
5996 MethodInfo GetArrayMethod (int arguments)
5998 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
6000 Type[] arg_types = new Type[arguments];
6001 for (int i = 0; i < arguments; i++)
6002 arg_types[i] = TypeManager.int32_type;
6004 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6005 arg_types);
6007 if (mi == null) {
6008 RootContext.ToplevelTypes.Compiler.Report.Error (-6, "New invocation: Can not find a constructor for " +
6009 "this argument list");
6010 return null;
6013 return mi;
6016 byte [] MakeByteBlob ()
6018 int factor;
6019 byte [] data;
6020 byte [] element;
6021 int count = array_data.Count;
6023 Type element_type = array_element_type;
6024 if (TypeManager.IsEnumType (element_type))
6025 element_type = TypeManager.GetEnumUnderlyingType (element_type);
6027 factor = GetTypeSize (element_type);
6028 if (factor == 0)
6029 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6031 data = new byte [(count * factor + 3) & ~3];
6032 int idx = 0;
6034 for (int i = 0; i < count; ++i) {
6035 object v = array_data [i];
6037 if (v is EnumConstant)
6038 v = ((EnumConstant) v).Child;
6040 if (v is Constant && !(v is StringConstant))
6041 v = ((Constant) v).GetValue ();
6042 else {
6043 idx += factor;
6044 continue;
6047 if (element_type == TypeManager.int64_type){
6048 if (!(v is Expression)){
6049 long val = (long) v;
6051 for (int j = 0; j < factor; ++j) {
6052 data [idx + j] = (byte) (val & 0xFF);
6053 val = (val >> 8);
6056 } else if (element_type == TypeManager.uint64_type){
6057 if (!(v is Expression)){
6058 ulong val = (ulong) v;
6060 for (int j = 0; j < factor; ++j) {
6061 data [idx + j] = (byte) (val & 0xFF);
6062 val = (val >> 8);
6065 } else if (element_type == TypeManager.float_type) {
6066 if (!(v is Expression)){
6067 element = BitConverter.GetBytes ((float) v);
6069 for (int j = 0; j < factor; ++j)
6070 data [idx + j] = element [j];
6071 if (!BitConverter.IsLittleEndian)
6072 System.Array.Reverse (data, idx, 4);
6074 } else if (element_type == TypeManager.double_type) {
6075 if (!(v is Expression)){
6076 element = BitConverter.GetBytes ((double) v);
6078 for (int j = 0; j < factor; ++j)
6079 data [idx + j] = element [j];
6081 // FIXME: Handle the ARM float format.
6082 if (!BitConverter.IsLittleEndian)
6083 System.Array.Reverse (data, idx, 8);
6085 } else if (element_type == TypeManager.char_type){
6086 if (!(v is Expression)){
6087 int val = (int) ((char) v);
6089 data [idx] = (byte) (val & 0xff);
6090 data [idx+1] = (byte) (val >> 8);
6092 } else if (element_type == TypeManager.short_type){
6093 if (!(v is Expression)){
6094 int val = (int) ((short) v);
6096 data [idx] = (byte) (val & 0xff);
6097 data [idx+1] = (byte) (val >> 8);
6099 } else if (element_type == TypeManager.ushort_type){
6100 if (!(v is Expression)){
6101 int val = (int) ((ushort) v);
6103 data [idx] = (byte) (val & 0xff);
6104 data [idx+1] = (byte) (val >> 8);
6106 } else if (element_type == TypeManager.int32_type) {
6107 if (!(v is Expression)){
6108 int val = (int) v;
6110 data [idx] = (byte) (val & 0xff);
6111 data [idx+1] = (byte) ((val >> 8) & 0xff);
6112 data [idx+2] = (byte) ((val >> 16) & 0xff);
6113 data [idx+3] = (byte) (val >> 24);
6115 } else if (element_type == TypeManager.uint32_type) {
6116 if (!(v is Expression)){
6117 uint val = (uint) v;
6119 data [idx] = (byte) (val & 0xff);
6120 data [idx+1] = (byte) ((val >> 8) & 0xff);
6121 data [idx+2] = (byte) ((val >> 16) & 0xff);
6122 data [idx+3] = (byte) (val >> 24);
6124 } else if (element_type == TypeManager.sbyte_type) {
6125 if (!(v is Expression)){
6126 sbyte val = (sbyte) v;
6127 data [idx] = (byte) val;
6129 } else if (element_type == TypeManager.byte_type) {
6130 if (!(v is Expression)){
6131 byte val = (byte) v;
6132 data [idx] = (byte) val;
6134 } else if (element_type == TypeManager.bool_type) {
6135 if (!(v is Expression)){
6136 bool val = (bool) v;
6137 data [idx] = (byte) (val ? 1 : 0);
6139 } else if (element_type == TypeManager.decimal_type){
6140 if (!(v is Expression)){
6141 int [] bits = Decimal.GetBits ((decimal) v);
6142 int p = idx;
6144 // FIXME: For some reason, this doesn't work on the MS runtime.
6145 int [] nbits = new int [4];
6146 nbits [0] = bits [3];
6147 nbits [1] = bits [2];
6148 nbits [2] = bits [0];
6149 nbits [3] = bits [1];
6151 for (int j = 0; j < 4; j++){
6152 data [p++] = (byte) (nbits [j] & 0xff);
6153 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6154 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6155 data [p++] = (byte) (nbits [j] >> 24);
6158 } else {
6159 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6162 idx += factor;
6165 return data;
6168 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6170 array_element_type = storey.MutateType (array_element_type);
6171 type = storey.MutateType (type);
6172 if (arguments != null) {
6173 foreach (Expression e in arguments)
6174 e.MutateHoistedGenericType (storey);
6177 if (array_data != null) {
6178 foreach (Expression e in array_data) {
6179 // Don't mutate values optimized away
6180 if (e == null)
6181 continue;
6183 e.MutateHoistedGenericType (storey);
6189 // Emits the initializers for the array
6191 void EmitStaticInitializers (EmitContext ec)
6193 // FIXME: This should go to Resolve !
6194 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6195 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6196 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6197 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6198 if (TypeManager.void_initializearray_array_fieldhandle == null)
6199 return;
6203 // First, the static data
6205 FieldBuilder fb;
6206 ILGenerator ig = ec.ig;
6208 byte [] data = MakeByteBlob ();
6210 fb = RootContext.MakeStaticData (data);
6212 ig.Emit (OpCodes.Dup);
6213 ig.Emit (OpCodes.Ldtoken, fb);
6214 ig.Emit (OpCodes.Call,
6215 TypeManager.void_initializearray_array_fieldhandle);
6219 // Emits pieces of the array that can not be computed at compile
6220 // time (variables and string locations).
6222 // This always expect the top value on the stack to be the array
6224 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6226 ILGenerator ig = ec.ig;
6227 int dims = bounds.Count;
6228 int [] current_pos = new int [dims];
6230 MethodInfo set = null;
6232 if (dims != 1){
6233 Type [] args = new Type [dims + 1];
6235 for (int j = 0; j < dims; j++)
6236 args [j] = TypeManager.int32_type;
6237 args [dims] = array_element_type;
6239 set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
6240 type, "Set",
6241 CallingConventions.HasThis | CallingConventions.Standard,
6242 TypeManager.void_type, args);
6245 for (int i = 0; i < array_data.Count; i++){
6247 Expression e = (Expression)array_data [i];
6249 // Constant can be initialized via StaticInitializer
6250 if (e != null && !(!emitConstants && e is Constant)) {
6251 Type etype = e.Type;
6253 ig.Emit (OpCodes.Dup);
6255 for (int idx = 0; idx < dims; idx++)
6256 IntConstant.EmitInt (ig, current_pos [idx]);
6259 // If we are dealing with a struct, get the
6260 // address of it, so we can store it.
6262 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6263 (!TypeManager.IsBuiltinOrEnum (etype) ||
6264 etype == TypeManager.decimal_type)) {
6266 ig.Emit (OpCodes.Ldelema, etype);
6269 e.Emit (ec);
6271 if (dims == 1) {
6272 bool is_stobj, has_type_arg;
6273 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6274 if (is_stobj)
6275 ig.Emit (OpCodes.Stobj, etype);
6276 else if (has_type_arg)
6277 ig.Emit (op, etype);
6278 else
6279 ig.Emit (op);
6280 } else
6281 ig.Emit (OpCodes.Call, set);
6286 // Advance counter
6288 for (int j = dims - 1; j >= 0; j--){
6289 current_pos [j]++;
6290 if (current_pos [j] < (int) bounds [j])
6291 break;
6292 current_pos [j] = 0;
6297 public override void Emit (EmitContext ec)
6299 ILGenerator ig = ec.ig;
6301 if (first_emit != null) {
6302 first_emit.Emit (ec);
6303 first_emit_temp.Store (ec);
6306 foreach (Expression e in arguments)
6307 e.Emit (ec);
6309 if (arguments.Count == 1)
6310 ig.Emit (OpCodes.Newarr, TypeManager.TypeToReflectionType (array_element_type));
6311 else {
6312 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6315 if (initializers == null)
6316 return;
6318 // Emit static initializer for arrays which have contain more than 4 items and
6319 // the static initializer will initialize at least 25% of array values.
6320 // NOTE: const_initializers_count does not contain default constant values.
6321 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6322 (TypeManager.IsPrimitiveType (array_element_type) || TypeManager.IsEnumType (array_element_type))) {
6323 EmitStaticInitializers (ec);
6325 if (!only_constant_initializers)
6326 EmitDynamicInitializers (ec, false);
6327 } else {
6328 EmitDynamicInitializers (ec, true);
6331 if (first_emit_temp != null)
6332 first_emit_temp.Release (ec);
6335 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
6337 if (arguments.Count != 1) {
6338 // ec.Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6339 return base.GetAttributableValue (ec, null, out value);
6342 if (array_data == null) {
6343 Expression arg = (Expression) arguments[0];
6344 object arg_value;
6345 if (arg.GetAttributableValue (ec, arg.Type, out arg_value) && arg_value is int && (int)arg_value == 0) {
6346 value = Array.CreateInstance (array_element_type, 0);
6347 return true;
6350 // ec.Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6351 return base.GetAttributableValue (ec, null, out value);
6354 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6355 object element_value;
6356 for (int i = 0; i < ret.Length; ++i)
6358 Expression e = (Expression)array_data [i];
6360 // Is null when an initializer is optimized (value == predefined value)
6361 if (e == null)
6362 continue;
6364 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6365 value = null;
6366 return false;
6368 ret.SetValue (element_value, i);
6370 value = ret;
6371 return true;
6374 protected override void CloneTo (CloneContext clonectx, Expression t)
6376 ArrayCreation target = (ArrayCreation) t;
6378 if (requested_base_type != null)
6379 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6381 if (arguments != null){
6382 target.arguments = new ArrayList (arguments.Count);
6383 foreach (Expression e in arguments)
6384 target.arguments.Add (e.Clone (clonectx));
6387 if (initializers != null){
6388 target.initializers = new ArrayList (initializers.Count);
6389 foreach (object initializer in initializers)
6390 if (initializer is ArrayList) {
6391 ArrayList this_al = (ArrayList)initializer;
6392 ArrayList al = new ArrayList (this_al.Count);
6393 target.initializers.Add (al);
6394 foreach (Expression e in this_al)
6395 al.Add (e.Clone (clonectx));
6396 } else {
6397 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6404 // Represents an implicitly typed array epxression
6406 public class ImplicitlyTypedArrayCreation : ArrayCreation
6408 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6409 : base (null, rank, initializers, loc)
6411 if (rank.Length > 2) {
6412 while (rank [++dimensions] == ',');
6413 } else {
6414 dimensions = 1;
6418 public override Expression DoResolve (ResolveContext ec)
6420 if (type != null)
6421 return this;
6423 if (!ResolveInitializers (ec))
6424 return null;
6426 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6427 array_element_type == TypeManager.void_type || array_element_type == InternalType.AnonymousMethod ||
6428 array_element_type == InternalType.MethodGroup ||
6429 arguments.Count != dimensions) {
6430 Error_NoBestType (ec);
6431 return null;
6435 // At this point we found common base type for all initializer elements
6436 // but we have to be sure that all static initializer elements are of
6437 // same type
6439 UnifyInitializerElement (ec);
6441 type = TypeManager.GetConstructedType (array_element_type, rank);
6442 eclass = ExprClass.Value;
6443 return this;
6446 void Error_NoBestType (ResolveContext ec)
6448 ec.Report.Error (826, loc,
6449 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6453 // Converts static initializer only
6455 void UnifyInitializerElement (ResolveContext ec)
6457 for (int i = 0; i < array_data.Count; ++i) {
6458 Expression e = (Expression)array_data[i];
6459 if (e != null)
6460 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6464 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6466 element = element.Resolve (ec);
6467 if (element == null)
6468 return null;
6470 if (array_element_type == null) {
6471 if (element.Type != TypeManager.null_type)
6472 array_element_type = element.Type;
6474 return element;
6477 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6478 return element;
6481 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6482 array_element_type = element.Type;
6483 return element;
6486 Error_NoBestType (ec);
6487 return null;
6491 public sealed class CompilerGeneratedThis : This
6493 public static This Instance = new CompilerGeneratedThis ();
6495 private CompilerGeneratedThis ()
6496 : base (Location.Null)
6500 public CompilerGeneratedThis (Type type, Location loc)
6501 : base (loc)
6503 this.type = type;
6506 public override Expression DoResolve (ResolveContext ec)
6508 eclass = ExprClass.Variable;
6509 if (type == null)
6510 type = ec.CurrentType;
6512 is_struct = type.IsValueType;
6513 return this;
6516 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6518 return null;
6522 /// <summary>
6523 /// Represents the `this' construct
6524 /// </summary>
6526 public class This : VariableReference
6528 sealed class ThisVariable : ILocalVariable
6530 public static readonly ILocalVariable Instance = new ThisVariable ();
6532 public void Emit (EmitContext ec)
6534 ec.ig.Emit (OpCodes.Ldarg_0);
6537 public void EmitAssign (EmitContext ec)
6539 throw new InvalidOperationException ();
6542 public void EmitAddressOf (EmitContext ec)
6544 ec.ig.Emit (OpCodes.Ldarg_0);
6548 Block block;
6549 VariableInfo variable_info;
6550 protected bool is_struct;
6552 public This (Block block, Location loc)
6554 this.loc = loc;
6555 this.block = block;
6558 public This (Location loc)
6560 this.loc = loc;
6563 public override VariableInfo VariableInfo {
6564 get { return variable_info; }
6567 public override bool IsFixed {
6568 get { return false; }
6571 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6573 if (ae == null)
6574 return null;
6576 AnonymousMethodStorey storey = ae.Storey;
6577 while (storey != null) {
6578 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6579 if (temp == null)
6580 return storey.HoistedThis;
6582 storey = temp;
6585 return null;
6588 public override bool IsRef {
6589 get { return is_struct; }
6592 protected override ILocalVariable Variable {
6593 get { return ThisVariable.Instance; }
6596 public static bool IsThisAvailable (ResolveContext ec)
6598 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
6599 return false;
6601 if (ec.CurrentAnonymousMethod == null)
6602 return true;
6604 if (ec.CurrentType.IsValueType && ec.CurrentIterator == null)
6605 return false;
6607 return true;
6610 public bool ResolveBase (ResolveContext ec)
6612 if (eclass != ExprClass.Invalid)
6613 return true;
6615 eclass = ExprClass.Variable;
6616 type = ec.CurrentType;
6618 if (!IsThisAvailable (ec)) {
6619 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6620 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6621 } else if (ec.CurrentAnonymousMethod != null) {
6622 ec.Report.Error (1673, loc,
6623 "Anonymous methods inside structs cannot access instance members of `this'. " +
6624 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6625 } else {
6626 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6630 is_struct = type.IsValueType;
6632 if (block != null) {
6633 if (block.Toplevel.ThisVariable != null)
6634 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6636 AnonymousExpression am = ec.CurrentAnonymousMethod;
6637 if (am != null && ec.IsVariableCapturingRequired) {
6638 am.SetHasThisAccess ();
6642 return true;
6646 // Called from Invocation to check if the invocation is correct
6648 public override void CheckMarshalByRefAccess (ResolveContext ec)
6650 if ((variable_info != null) && !(TypeManager.IsStruct (type) && ec.OmitStructFlowAnalysis) &&
6651 !variable_info.IsAssigned (ec)) {
6652 ec.Report.Error (188, loc,
6653 "The `this' object cannot be used before all of its fields are assigned to");
6654 variable_info.SetAssigned (ec);
6658 public override Expression CreateExpressionTree (ResolveContext ec)
6660 Arguments args = new Arguments (1);
6661 args.Add (new Argument (this));
6663 // Use typeless constant for ldarg.0 to save some
6664 // space and avoid problems with anonymous stories
6665 return CreateExpressionFactoryCall (ec, "Constant", args);
6668 public override Expression DoResolve (ResolveContext ec)
6670 ResolveBase (ec);
6671 return this;
6674 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6676 if (!ResolveBase (ec))
6677 return null;
6679 if (variable_info != null)
6680 variable_info.SetAssigned (ec);
6682 if (ec.CurrentType.IsClass){
6683 if (right_side == EmptyExpression.UnaryAddress)
6684 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6685 else if (right_side == EmptyExpression.OutAccess)
6686 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6687 else
6688 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6691 return this;
6694 public override int GetHashCode()
6696 return block.GetHashCode ();
6699 public override string Name {
6700 get { return "this"; }
6703 public override bool Equals (object obj)
6705 This t = obj as This;
6706 if (t == null)
6707 return false;
6709 return block == t.block;
6712 protected override void CloneTo (CloneContext clonectx, Expression t)
6714 This target = (This) t;
6716 target.block = clonectx.LookupBlock (block);
6719 public override void SetHasAddressTaken ()
6721 // Nothing
6725 /// <summary>
6726 /// Represents the `__arglist' construct
6727 /// </summary>
6728 public class ArglistAccess : Expression
6730 public ArglistAccess (Location loc)
6732 this.loc = loc;
6735 public override Expression CreateExpressionTree (ResolveContext ec)
6737 throw new NotSupportedException ("ET");
6740 public override Expression DoResolve (ResolveContext ec)
6742 eclass = ExprClass.Variable;
6743 type = TypeManager.runtime_argument_handle_type;
6745 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.Toplevel.Parameters.HasArglist) {
6746 ec.Report.Error (190, loc,
6747 "The __arglist construct is valid only within a variable argument method");
6750 return this;
6753 public override void Emit (EmitContext ec)
6755 ec.ig.Emit (OpCodes.Arglist);
6758 protected override void CloneTo (CloneContext clonectx, Expression target)
6760 // nothing.
6764 /// <summary>
6765 /// Represents the `__arglist (....)' construct
6766 /// </summary>
6767 class Arglist : Expression
6769 Arguments Arguments;
6771 public Arglist (Location loc)
6772 : this (null, loc)
6776 public Arglist (Arguments args, Location l)
6778 Arguments = args;
6779 loc = l;
6782 public Type[] ArgumentTypes {
6783 get {
6784 if (Arguments == null)
6785 return Type.EmptyTypes;
6787 Type[] retval = new Type [Arguments.Count];
6788 for (int i = 0; i < retval.Length; i++)
6789 retval [i] = Arguments [i].Expr.Type;
6791 return retval;
6795 public override Expression CreateExpressionTree (ResolveContext ec)
6797 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6798 return null;
6801 public override Expression DoResolve (ResolveContext ec)
6803 eclass = ExprClass.Variable;
6804 type = InternalType.Arglist;
6805 if (Arguments != null) {
6806 bool dynamic; // Can be ignored as there is always only 1 overload
6807 Arguments.Resolve (ec, out dynamic);
6810 return this;
6813 public override void Emit (EmitContext ec)
6815 if (Arguments != null)
6816 Arguments.Emit (ec);
6819 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6821 if (Arguments != null)
6822 Arguments.MutateHoistedGenericType (storey);
6825 protected override void CloneTo (CloneContext clonectx, Expression t)
6827 Arglist target = (Arglist) t;
6829 if (Arguments != null)
6830 target.Arguments = Arguments.Clone (clonectx);
6834 /// <summary>
6835 /// Implements the typeof operator
6836 /// </summary>
6837 public class TypeOf : Expression {
6838 Expression QueriedType;
6839 protected Type typearg;
6841 public TypeOf (Expression queried_type, Location l)
6843 QueriedType = queried_type;
6844 loc = l;
6847 public override Expression CreateExpressionTree (ResolveContext ec)
6849 Arguments args = new Arguments (2);
6850 args.Add (new Argument (this));
6851 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6852 return CreateExpressionFactoryCall (ec, "Constant", args);
6855 public override Expression DoResolve (ResolveContext ec)
6857 if (eclass != ExprClass.Invalid)
6858 return this;
6860 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6861 if (texpr == null)
6862 return null;
6864 typearg = texpr.Type;
6866 if (typearg == TypeManager.void_type) {
6867 ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6868 } else if (typearg.IsPointer && !ec.IsUnsafe){
6869 UnsafeError (ec, loc);
6870 } else if (texpr is DynamicTypeExpr) {
6871 ec.Report.Error (1962, QueriedType.Location,
6872 "The typeof operator cannot be used on the dynamic type");
6875 type = TypeManager.type_type;
6877 return DoResolveBase ();
6880 protected Expression DoResolveBase ()
6882 if (TypeManager.system_type_get_type_from_handle == null) {
6883 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6884 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6887 // Even though what is returned is a type object, it's treated as a value by the compiler.
6888 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6889 eclass = ExprClass.Value;
6890 return this;
6893 public override void Emit (EmitContext ec)
6895 ec.ig.Emit (OpCodes.Ldtoken, TypeManager.TypeToReflectionType (typearg));
6896 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6899 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
6901 if (TypeManager.ContainsGenericParameters (typearg) &&
6902 !TypeManager.IsGenericTypeDefinition (typearg)) {
6903 ec.Report.SymbolRelatedToPreviousError (typearg);
6904 ec.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6905 TypeManager.CSharpName (typearg));
6906 value = null;
6907 return false;
6910 if (value_type == TypeManager.object_type) {
6911 value = (object)typearg;
6912 return true;
6914 value = typearg;
6915 return true;
6918 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6920 typearg = storey.MutateType (typearg);
6923 public Type TypeArgument {
6924 get {
6925 return typearg;
6929 protected override void CloneTo (CloneContext clonectx, Expression t)
6931 TypeOf target = (TypeOf) t;
6932 if (QueriedType != null)
6933 target.QueriedType = QueriedType.Clone (clonectx);
6937 /// <summary>
6938 /// Implements the `typeof (void)' operator
6939 /// </summary>
6940 public class TypeOfVoid : TypeOf {
6941 public TypeOfVoid (Location l) : base (null, l)
6943 loc = l;
6946 public override Expression DoResolve (ResolveContext ec)
6948 type = TypeManager.type_type;
6949 typearg = TypeManager.void_type;
6951 return DoResolveBase ();
6955 class TypeOfMethod : TypeOfMember
6957 public TypeOfMethod (MethodBase method, Location loc)
6958 : base (method, loc)
6962 public override Expression DoResolve (ResolveContext ec)
6964 if (member is MethodInfo) {
6965 type = TypeManager.methodinfo_type;
6966 if (type == null)
6967 type = TypeManager.methodinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", "MethodInfo", Kind.Class, true);
6968 } else {
6969 type = TypeManager.ctorinfo_type;
6970 if (type == null)
6971 type = TypeManager.ctorinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", "ConstructorInfo", Kind.Class, true);
6974 return base.DoResolve (ec);
6977 public override void Emit (EmitContext ec)
6979 if (member is ConstructorInfo)
6980 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) member);
6981 else
6982 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) member);
6984 base.Emit (ec);
6985 ec.ig.Emit (OpCodes.Castclass, type);
6988 protected override string GetMethodName {
6989 get { return "GetMethodFromHandle"; }
6992 protected override string RuntimeHandleName {
6993 get { return "RuntimeMethodHandle"; }
6996 protected override MethodInfo TypeFromHandle {
6997 get {
6998 return TypeManager.methodbase_get_type_from_handle;
7000 set {
7001 TypeManager.methodbase_get_type_from_handle = value;
7005 protected override MethodInfo TypeFromHandleGeneric {
7006 get {
7007 return TypeManager.methodbase_get_type_from_handle_generic;
7009 set {
7010 TypeManager.methodbase_get_type_from_handle_generic = value;
7014 protected override string TypeName {
7015 get { return "MethodBase"; }
7019 abstract class TypeOfMember : Expression
7021 protected readonly MemberInfo member;
7023 protected TypeOfMember (MemberInfo member, Location loc)
7025 this.member = member;
7026 this.loc = loc;
7029 public override Expression CreateExpressionTree (ResolveContext ec)
7031 Arguments args = new Arguments (2);
7032 args.Add (new Argument (this));
7033 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7034 return CreateExpressionFactoryCall (ec, "Constant", args);
7037 public override Expression DoResolve (ResolveContext ec)
7039 bool is_generic = TypeManager.IsGenericType (member.DeclaringType);
7040 MethodInfo mi = is_generic ? TypeFromHandleGeneric : TypeFromHandle;
7042 if (mi == null) {
7043 Type t = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", TypeName, Kind.Class, true);
7044 Type handle_type = TypeManager.CoreLookupType (ec.Compiler, "System", RuntimeHandleName, Kind.Class, true);
7046 if (t == null || handle_type == null)
7047 return null;
7049 mi = TypeManager.GetPredefinedMethod (t, GetMethodName, loc,
7050 is_generic ?
7051 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7052 new Type[] { handle_type } );
7054 if (is_generic)
7055 TypeFromHandleGeneric = mi;
7056 else
7057 TypeFromHandle = mi;
7060 eclass = ExprClass.Value;
7061 return this;
7064 public override void Emit (EmitContext ec)
7066 bool is_generic = TypeManager.IsGenericType (member.DeclaringType);
7067 MethodInfo mi;
7068 if (is_generic) {
7069 mi = TypeFromHandleGeneric;
7070 ec.ig.Emit (OpCodes.Ldtoken, member.DeclaringType);
7071 } else {
7072 mi = TypeFromHandle;
7075 ec.ig.Emit (OpCodes.Call, mi);
7078 protected abstract string GetMethodName { get; }
7079 protected abstract string RuntimeHandleName { get; }
7080 protected abstract MethodInfo TypeFromHandle { get; set; }
7081 protected abstract MethodInfo TypeFromHandleGeneric { get; set; }
7082 protected abstract string TypeName { get; }
7085 class TypeOfField : TypeOfMember
7087 public TypeOfField (FieldInfo field, Location loc)
7088 : base (field, loc)
7092 public override Expression DoResolve (ResolveContext ec)
7094 if (TypeManager.fieldinfo_type == null)
7095 TypeManager.fieldinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", TypeName, Kind.Class, true);
7097 type = TypeManager.fieldinfo_type;
7098 return base.DoResolve (ec);
7101 public override void Emit (EmitContext ec)
7103 ec.ig.Emit (OpCodes.Ldtoken, (FieldInfo) member);
7104 base.Emit (ec);
7107 protected override string GetMethodName {
7108 get { return "GetFieldFromHandle"; }
7111 protected override string RuntimeHandleName {
7112 get { return "RuntimeFieldHandle"; }
7115 protected override MethodInfo TypeFromHandle {
7116 get {
7117 return TypeManager.fieldinfo_get_field_from_handle;
7119 set {
7120 TypeManager.fieldinfo_get_field_from_handle = value;
7124 protected override MethodInfo TypeFromHandleGeneric {
7125 get {
7126 return TypeManager.fieldinfo_get_field_from_handle_generic;
7128 set {
7129 TypeManager.fieldinfo_get_field_from_handle_generic = value;
7133 protected override string TypeName {
7134 get { return "FieldInfo"; }
7138 /// <summary>
7139 /// Implements the sizeof expression
7140 /// </summary>
7141 public class SizeOf : Expression {
7142 readonly Expression QueriedType;
7143 Type type_queried;
7145 public SizeOf (Expression queried_type, Location l)
7147 this.QueriedType = queried_type;
7148 loc = l;
7151 public override Expression CreateExpressionTree (ResolveContext ec)
7153 Error_PointerInsideExpressionTree (ec);
7154 return null;
7157 public override Expression DoResolve (ResolveContext ec)
7159 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7160 if (texpr == null)
7161 return null;
7163 type_queried = texpr.Type;
7164 if (TypeManager.IsEnumType (type_queried))
7165 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7167 int size_of = GetTypeSize (type_queried);
7168 if (size_of > 0) {
7169 return new IntConstant (size_of, loc);
7172 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7173 return null;
7176 if (!ec.IsUnsafe) {
7177 ec.Report.Error (233, loc,
7178 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7179 TypeManager.CSharpName (type_queried));
7182 type = TypeManager.int32_type;
7183 eclass = ExprClass.Value;
7184 return this;
7187 public override void Emit (EmitContext ec)
7189 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7192 protected override void CloneTo (CloneContext clonectx, Expression t)
7197 /// <summary>
7198 /// Implements the qualified-alias-member (::) expression.
7199 /// </summary>
7200 public class QualifiedAliasMember : MemberAccess
7202 readonly string alias;
7203 public static readonly string GlobalAlias = "global";
7205 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7206 : base (null, identifier, targs, l)
7208 this.alias = alias;
7211 public QualifiedAliasMember (string alias, string identifier, Location l)
7212 : base (null, identifier, l)
7214 this.alias = alias;
7217 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7219 if (alias == GlobalAlias) {
7220 expr = GlobalRootNamespace.Instance;
7221 return base.ResolveAsTypeStep (ec, silent);
7224 int errors = ec.Compiler.Report.Errors;
7225 expr = ec.LookupNamespaceAlias (alias);
7226 if (expr == null) {
7227 if (errors == ec.Compiler.Report.Errors)
7228 ec.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7229 return null;
7232 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7233 if (fne == null)
7234 return null;
7236 if (expr.eclass == ExprClass.Type) {
7237 if (!silent) {
7238 ec.Compiler.Report.Error (431, loc,
7239 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7241 return null;
7244 return fne;
7247 public override Expression DoResolve (ResolveContext ec)
7249 return ResolveAsTypeStep (ec, false);
7252 protected override void Error_IdentifierNotFound (IMemberContext rc, FullNamedExpression expr_type, string identifier)
7254 rc.Compiler.Report.Error (687, loc,
7255 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7256 GetSignatureForError ());
7259 public override string GetSignatureForError ()
7261 string name = Name;
7262 if (targs != null) {
7263 name = TypeManager.RemoveGenericArity (Name) + "<" +
7264 targs.GetSignatureForError () + ">";
7267 return alias + "::" + name;
7270 protected override void CloneTo (CloneContext clonectx, Expression t)
7272 // Nothing
7276 /// <summary>
7277 /// Implements the member access expression
7278 /// </summary>
7279 public class MemberAccess : ATypeNameExpression {
7280 protected Expression expr;
7282 public MemberAccess (Expression expr, string id)
7283 : base (id, expr.Location)
7285 this.expr = expr;
7288 public MemberAccess (Expression expr, string identifier, Location loc)
7289 : base (identifier, loc)
7291 this.expr = expr;
7294 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7295 : base (identifier, args, loc)
7297 this.expr = expr;
7300 Expression DoResolve (ResolveContext ec, Expression right_side)
7302 if (type != null)
7303 throw new Exception ();
7306 // Resolve the expression with flow analysis turned off, we'll do the definite
7307 // assignment checks later. This is because we don't know yet what the expression
7308 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7309 // definite assignment check on the actual field and not on the whole struct.
7312 SimpleName original = expr as SimpleName;
7313 Expression expr_resolved = expr.Resolve (ec,
7314 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7315 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7317 if (expr_resolved == null)
7318 return null;
7320 string LookupIdentifier = MemberName.MakeName (Name, targs);
7322 Namespace ns = expr_resolved as Namespace;
7323 if (ns != null) {
7324 FullNamedExpression retval = ns.Lookup (ec.Compiler, LookupIdentifier, loc);
7326 if (retval == null)
7327 ns.Error_NamespaceDoesNotExist (loc, LookupIdentifier, ec.Report);
7328 else if (targs != null)
7329 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
7331 return retval;
7334 Type expr_type = expr_resolved.Type;
7335 if (TypeManager.IsDynamicType (expr_type)) {
7336 Arguments args = new Arguments (2);
7337 args.Add (new Argument (expr_resolved.Resolve (ec)));
7338 if (right_side != null)
7339 args.Add (new Argument (right_side));
7341 return new DynamicMemberBinder (right_side != null, Name, args, loc).Resolve (ec);
7344 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7345 expr_type == TypeManager.null_type || expr_type == InternalType.AnonymousMethod) {
7346 Unary.Error_OperatorCannotBeApplied (ec, loc, ".", expr_type);
7347 return null;
7350 Constant c = expr_resolved as Constant;
7351 if (c != null && c.GetValue () == null) {
7352 ec.Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7353 "System.NullReferenceException");
7356 if (targs != null) {
7357 if (!targs.Resolve (ec))
7358 return null;
7361 Expression member_lookup;
7362 member_lookup = MemberLookup (ec.Compiler,
7363 ec.CurrentType, expr_type, expr_type, Name, loc);
7365 if (member_lookup == null && targs != null) {
7366 member_lookup = MemberLookup (ec.Compiler,
7367 ec.CurrentType, expr_type, expr_type, LookupIdentifier, loc);
7370 if (member_lookup == null) {
7371 ExprClass expr_eclass = expr_resolved.eclass;
7374 // Extension methods are not allowed on all expression types
7376 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7377 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7378 expr_eclass == ExprClass.EventAccess) {
7379 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
7380 if (ex_method_lookup != null) {
7381 ex_method_lookup.ExtensionExpression = expr_resolved;
7383 if (targs != null) {
7384 ex_method_lookup.SetTypeArguments (ec, targs);
7387 return ex_method_lookup.DoResolve (ec);
7391 expr = expr_resolved;
7392 member_lookup = Error_MemberLookupFailed (ec,
7393 ec.CurrentType, expr_type, expr_type, Name, null,
7394 AllMemberTypes, AllBindingFlags);
7395 if (member_lookup == null)
7396 return null;
7399 TypeExpr texpr = member_lookup as TypeExpr;
7400 if (texpr != null) {
7401 if (!(expr_resolved is TypeExpr) &&
7402 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7403 ec.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7404 Name, member_lookup.GetSignatureForError ());
7405 return null;
7408 if (!texpr.CheckAccessLevel (ec.MemberContext)) {
7409 ec.Report.SymbolRelatedToPreviousError (member_lookup.Type);
7410 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type), ec.Report);
7411 return null;
7414 GenericTypeExpr ct = expr_resolved as GenericTypeExpr;
7415 if (ct != null) {
7417 // When looking up a nested type in a generic instance
7418 // via reflection, we always get a generic type definition
7419 // and not a generic instance - so we have to do this here.
7421 // See gtest-172-lib.cs and gtest-172.cs for an example.
7424 TypeArguments nested_targs;
7425 if (HasTypeArguments) {
7426 nested_targs = ct.TypeArguments.Clone ();
7427 nested_targs.Add (targs);
7428 } else {
7429 nested_targs = ct.TypeArguments;
7432 ct = new GenericTypeExpr (member_lookup.Type, nested_targs, loc);
7434 return ct.ResolveAsTypeStep (ec, false);
7437 return member_lookup;
7440 MemberExpr me = (MemberExpr) member_lookup;
7441 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7442 if (me == null)
7443 return null;
7445 if (targs != null) {
7446 me.SetTypeArguments (ec, targs);
7449 if (original != null && !TypeManager.IsValueType (expr_type)) {
7450 if (me.IsInstance) {
7451 LocalVariableReference var = expr_resolved as LocalVariableReference;
7452 if (var != null && !var.VerifyAssigned (ec))
7453 return null;
7457 // The following DoResolve/DoResolveLValue will do the definite assignment
7458 // check.
7460 if (right_side != null)
7461 return me.DoResolveLValue (ec, right_side);
7462 else
7463 return me.DoResolve (ec);
7466 public override Expression DoResolve (ResolveContext ec)
7468 return DoResolve (ec, null);
7471 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7473 return DoResolve (ec, right_side);
7476 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7478 return ResolveNamespaceOrType (ec, silent);
7481 public FullNamedExpression ResolveNamespaceOrType (IMemberContext rc, bool silent)
7483 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7485 if (expr_resolved == null)
7486 return null;
7488 string LookupIdentifier = MemberName.MakeName (Name, targs);
7490 Namespace ns = expr_resolved as Namespace;
7491 if (ns != null) {
7492 FullNamedExpression retval = ns.Lookup (rc.Compiler, LookupIdentifier, loc);
7494 if (retval == null && !silent)
7495 ns.Error_NamespaceDoesNotExist (loc, LookupIdentifier, rc.Compiler.Report);
7496 else if (targs != null)
7497 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7499 return retval;
7502 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7503 if (tnew_expr == null)
7504 return null;
7506 Type expr_type = tnew_expr.Type;
7507 if (TypeManager.IsGenericParameter (expr_type)) {
7508 rc.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7509 tnew_expr.GetSignatureForError ());
7510 return null;
7513 Expression member_lookup = MemberLookup (rc.Compiler,
7514 rc.CurrentType, expr_type, expr_type, LookupIdentifier,
7515 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7516 if (member_lookup == null) {
7517 if (silent)
7518 return null;
7520 Error_IdentifierNotFound (rc, expr_resolved, LookupIdentifier);
7521 return null;
7524 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7525 if (texpr == null)
7526 return null;
7528 TypeArguments the_args = targs;
7529 Type declaring_type = texpr.Type.DeclaringType;
7530 if (TypeManager.HasGenericArguments (declaring_type) && !TypeManager.IsGenericTypeDefinition (expr_type)) {
7531 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7532 expr_type = expr_type.BaseType;
7535 TypeArguments new_args = new TypeArguments ();
7536 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7537 new_args.Add (new TypeExpression (TypeManager.TypeToCoreType (decl), loc));
7539 if (targs != null)
7540 new_args.Add (targs);
7542 the_args = new_args;
7545 if (the_args != null) {
7546 GenericTypeExpr ctype = new GenericTypeExpr (texpr.Type, the_args, loc);
7547 return ctype.ResolveAsTypeStep (rc, false);
7550 return texpr;
7553 protected virtual void Error_IdentifierNotFound (IMemberContext rc, FullNamedExpression expr_type, string identifier)
7555 Expression member_lookup = MemberLookup (rc.Compiler,
7556 rc.CurrentType, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7557 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7559 if (member_lookup != null) {
7560 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7561 if (expr_type == null)
7562 return;
7564 expr_type.Error_TypeArgumentsCannotBeUsed (rc.Compiler.Report, loc);
7565 return;
7568 member_lookup = MemberLookup (rc.Compiler,
7569 rc.CurrentType, expr_type.Type, expr_type.Type, identifier,
7570 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7572 if (member_lookup == null) {
7573 rc.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7574 Name, expr_type.GetSignatureForError ());
7575 } else {
7576 // TODO: Report.SymbolRelatedToPreviousError
7577 member_lookup.Error_UnexpectedKind (rc.Compiler.Report, null, "type", loc);
7581 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
7583 if (RootContext.Version > LanguageVersion.ISO_2 &&
7584 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7585 ec.Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7586 "extension method `{1}' of type `{0}' could be found " +
7587 "(are you missing a using directive or an assembly reference?)",
7588 TypeManager.CSharpName (type), name);
7589 return;
7592 base.Error_TypeDoesNotContainDefinition (ec, type, name);
7595 public override string GetSignatureForError ()
7597 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7600 public Expression Left {
7601 get {
7602 return expr;
7606 protected override void CloneTo (CloneContext clonectx, Expression t)
7608 MemberAccess target = (MemberAccess) t;
7610 target.expr = expr.Clone (clonectx);
7614 /// <summary>
7615 /// Implements checked expressions
7616 /// </summary>
7617 public class CheckedExpr : Expression {
7619 public Expression Expr;
7621 public CheckedExpr (Expression e, Location l)
7623 Expr = e;
7624 loc = l;
7627 public override Expression CreateExpressionTree (ResolveContext ec)
7629 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7630 return Expr.CreateExpressionTree (ec);
7633 public override Expression DoResolve (ResolveContext ec)
7635 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7636 Expr = Expr.Resolve (ec);
7638 if (Expr == null)
7639 return null;
7641 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7642 return Expr;
7644 eclass = Expr.eclass;
7645 type = Expr.Type;
7646 return this;
7649 public override void Emit (EmitContext ec)
7651 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7652 Expr.Emit (ec);
7655 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7657 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7658 Expr.EmitBranchable (ec, target, on_true);
7661 #if NET_4_0
7662 public override SLE.Expression MakeExpression (BuilderContext ctx)
7664 using (ctx.With (BuilderContext.Options.AllCheckStateFlags, true)) {
7665 return Expr.MakeExpression (ctx);
7668 #endif
7670 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7672 Expr.MutateHoistedGenericType (storey);
7675 protected override void CloneTo (CloneContext clonectx, Expression t)
7677 CheckedExpr target = (CheckedExpr) t;
7679 target.Expr = Expr.Clone (clonectx);
7683 /// <summary>
7684 /// Implements the unchecked expression
7685 /// </summary>
7686 public class UnCheckedExpr : Expression {
7688 public Expression Expr;
7690 public UnCheckedExpr (Expression e, Location l)
7692 Expr = e;
7693 loc = l;
7696 public override Expression CreateExpressionTree (ResolveContext ec)
7698 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7699 return Expr.CreateExpressionTree (ec);
7702 public override Expression DoResolve (ResolveContext ec)
7704 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7705 Expr = Expr.Resolve (ec);
7707 if (Expr == null)
7708 return null;
7710 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7711 return Expr;
7713 eclass = Expr.eclass;
7714 type = Expr.Type;
7715 return this;
7718 public override void Emit (EmitContext ec)
7720 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7721 Expr.Emit (ec);
7724 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7726 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7727 Expr.EmitBranchable (ec, target, on_true);
7730 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7732 Expr.MutateHoistedGenericType (storey);
7735 protected override void CloneTo (CloneContext clonectx, Expression t)
7737 UnCheckedExpr target = (UnCheckedExpr) t;
7739 target.Expr = Expr.Clone (clonectx);
7743 /// <summary>
7744 /// An Element Access expression.
7746 /// During semantic analysis these are transformed into
7747 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7748 /// </summary>
7749 public class ElementAccess : Expression {
7750 public Arguments Arguments;
7751 public Expression Expr;
7753 public ElementAccess (Expression e, Arguments args)
7755 Expr = e;
7756 loc = e.Location;
7757 this.Arguments = args;
7760 public override Expression CreateExpressionTree (ResolveContext ec)
7762 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
7763 Expr.CreateExpressionTree (ec));
7765 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
7768 Expression MakePointerAccess (ResolveContext ec, Type t)
7770 if (Arguments.Count != 1){
7771 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
7772 return null;
7775 if (Arguments [0] is NamedArgument)
7776 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
7778 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), t, loc);
7779 return new Indirection (p, loc).Resolve (ec);
7782 public override Expression DoResolve (ResolveContext ec)
7784 Expr = Expr.Resolve (ec);
7785 if (Expr == null)
7786 return null;
7789 // We perform some simple tests, and then to "split" the emit and store
7790 // code we create an instance of a different class, and return that.
7792 // I am experimenting with this pattern.
7794 Type t = Expr.Type;
7796 if (t == TypeManager.array_type){
7797 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7798 return null;
7801 if (t.IsArray)
7802 return (new ArrayAccess (this, loc)).Resolve (ec);
7803 if (t.IsPointer)
7804 return MakePointerAccess (ec, t);
7806 FieldExpr fe = Expr as FieldExpr;
7807 if (fe != null) {
7808 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7809 if (ff != null) {
7810 return MakePointerAccess (ec, ff.ElementType);
7813 return (new IndexerAccess (this, loc)).Resolve (ec);
7816 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7818 Expr = Expr.Resolve (ec);
7819 if (Expr == null)
7820 return null;
7822 type = Expr.Type;
7823 if (type.IsArray)
7824 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7826 if (type.IsPointer)
7827 return MakePointerAccess (ec, type);
7829 if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
7830 Error_CannotModifyIntermediateExpressionValue (ec);
7832 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7835 public override void Emit (EmitContext ec)
7837 throw new Exception ("Should never be reached");
7840 public static void Error_NamedArgument (NamedArgument na, Report Report)
7842 Report.Error (1742, na.Name.Location, "An element access expression cannot use named argument");
7845 public override string GetSignatureForError ()
7847 return Expr.GetSignatureForError ();
7850 protected override void CloneTo (CloneContext clonectx, Expression t)
7852 ElementAccess target = (ElementAccess) t;
7854 target.Expr = Expr.Clone (clonectx);
7855 if (Arguments != null)
7856 target.Arguments = Arguments.Clone (clonectx);
7860 /// <summary>
7861 /// Implements array access
7862 /// </summary>
7863 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
7865 // Points to our "data" repository
7867 ElementAccess ea;
7869 LocalTemporary temp;
7871 bool prepared;
7873 public ArrayAccess (ElementAccess ea_data, Location l)
7875 ea = ea_data;
7876 loc = l;
7879 public override Expression CreateExpressionTree (ResolveContext ec)
7881 return ea.CreateExpressionTree (ec);
7884 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7886 return DoResolve (ec);
7889 public override Expression DoResolve (ResolveContext ec)
7891 #if false
7892 ExprClass eclass = ea.Expr.eclass;
7894 // As long as the type is valid
7895 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7896 eclass == ExprClass.Value)) {
7897 ea.Expr.Error_UnexpectedKind ("variable or value");
7898 return null;
7900 #endif
7902 if (eclass != ExprClass.Invalid)
7903 return this;
7905 // dynamic is used per argument in ConvertExpressionToArrayIndex case
7906 bool dynamic;
7907 ea.Arguments.Resolve (ec, out dynamic);
7909 Type t = ea.Expr.Type;
7910 int rank = ea.Arguments.Count;
7911 if (t.GetArrayRank () != rank) {
7912 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7913 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7914 return null;
7917 type = TypeManager.GetElementType (t);
7918 if (type.IsPointer && !ec.IsUnsafe) {
7919 UnsafeError (ec, ea.Location);
7922 foreach (Argument a in ea.Arguments) {
7923 if (a is NamedArgument)
7924 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
7926 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7929 eclass = ExprClass.Variable;
7931 return this;
7934 /// <summary>
7935 /// Emits the right opcode to load an object of Type `t'
7936 /// from an array of T
7937 /// </summary>
7938 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7940 if (rank > 1) {
7941 MethodInfo get = FetchGetMethod ();
7942 ig.Emit (OpCodes.Call, get);
7943 return;
7946 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7947 ig.Emit (OpCodes.Ldelem_U1);
7948 else if (type == TypeManager.sbyte_type)
7949 ig.Emit (OpCodes.Ldelem_I1);
7950 else if (type == TypeManager.short_type)
7951 ig.Emit (OpCodes.Ldelem_I2);
7952 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7953 ig.Emit (OpCodes.Ldelem_U2);
7954 else if (type == TypeManager.int32_type)
7955 ig.Emit (OpCodes.Ldelem_I4);
7956 else if (type == TypeManager.uint32_type)
7957 ig.Emit (OpCodes.Ldelem_U4);
7958 else if (type == TypeManager.uint64_type)
7959 ig.Emit (OpCodes.Ldelem_I8);
7960 else if (type == TypeManager.int64_type)
7961 ig.Emit (OpCodes.Ldelem_I8);
7962 else if (type == TypeManager.float_type)
7963 ig.Emit (OpCodes.Ldelem_R4);
7964 else if (type == TypeManager.double_type)
7965 ig.Emit (OpCodes.Ldelem_R8);
7966 else if (type == TypeManager.intptr_type)
7967 ig.Emit (OpCodes.Ldelem_I);
7968 else if (TypeManager.IsEnumType (type)){
7969 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7970 } else if (TypeManager.IsStruct (type)){
7971 ig.Emit (OpCodes.Ldelema, type);
7972 ig.Emit (OpCodes.Ldobj, type);
7973 } else if (type.IsGenericParameter) {
7974 ig.Emit (OpCodes.Ldelem, type);
7975 } else if (type.IsPointer)
7976 ig.Emit (OpCodes.Ldelem_I);
7977 else
7978 ig.Emit (OpCodes.Ldelem_Ref);
7981 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7983 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7986 /// <summary>
7987 /// Returns the right opcode to store an object of Type `t'
7988 /// from an array of T.
7989 /// </summary>
7990 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7992 has_type_arg = false; is_stobj = false;
7993 t = TypeManager.TypeToCoreType (t);
7994 if (TypeManager.IsEnumType (t))
7995 t = TypeManager.GetEnumUnderlyingType (t);
7996 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7997 t == TypeManager.bool_type)
7998 return OpCodes.Stelem_I1;
7999 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8000 t == TypeManager.char_type)
8001 return OpCodes.Stelem_I2;
8002 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8003 return OpCodes.Stelem_I4;
8004 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8005 return OpCodes.Stelem_I8;
8006 else if (t == TypeManager.float_type)
8007 return OpCodes.Stelem_R4;
8008 else if (t == TypeManager.double_type)
8009 return OpCodes.Stelem_R8;
8010 else if (t == TypeManager.intptr_type) {
8011 has_type_arg = true;
8012 is_stobj = true;
8013 return OpCodes.Stobj;
8014 } else if (TypeManager.IsStruct (t)) {
8015 has_type_arg = true;
8016 is_stobj = true;
8017 return OpCodes.Stobj;
8018 } else if (t.IsGenericParameter) {
8019 has_type_arg = true;
8020 return OpCodes.Stelem;
8021 } else if (t.IsPointer)
8022 return OpCodes.Stelem_I;
8023 else
8024 return OpCodes.Stelem_Ref;
8027 MethodInfo FetchGetMethod ()
8029 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8030 int arg_count = ea.Arguments.Count;
8031 Type [] args = new Type [arg_count];
8032 MethodInfo get;
8034 for (int i = 0; i < arg_count; i++){
8035 //args [i++] = a.Type;
8036 args [i] = TypeManager.int32_type;
8039 get = mb.GetArrayMethod (
8040 ea.Expr.Type, "Get",
8041 CallingConventions.HasThis |
8042 CallingConventions.Standard,
8043 type, args);
8044 return get;
8048 MethodInfo FetchAddressMethod ()
8050 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8051 int arg_count = ea.Arguments.Count;
8052 Type [] args = new Type [arg_count];
8053 MethodInfo address;
8054 Type ret_type;
8056 ret_type = TypeManager.GetReferenceType (type);
8058 for (int i = 0; i < arg_count; i++){
8059 //args [i++] = a.Type;
8060 args [i] = TypeManager.int32_type;
8063 address = mb.GetArrayMethod (
8064 ea.Expr.Type, "Address",
8065 CallingConventions.HasThis |
8066 CallingConventions.Standard,
8067 ret_type, args);
8069 return address;
8073 // Load the array arguments into the stack.
8075 void LoadArrayAndArguments (EmitContext ec)
8077 ea.Expr.Emit (ec);
8079 for (int i = 0; i < ea.Arguments.Count; ++i) {
8080 ea.Arguments [i].Emit (ec);
8084 public void Emit (EmitContext ec, bool leave_copy)
8086 int rank = ea.Expr.Type.GetArrayRank ();
8087 ILGenerator ig = ec.ig;
8089 if (prepared) {
8090 LoadFromPtr (ig, this.type);
8091 } else {
8092 LoadArrayAndArguments (ec);
8093 EmitLoadOpcode (ig, type, rank);
8096 if (leave_copy) {
8097 ig.Emit (OpCodes.Dup);
8098 temp = new LocalTemporary (this.type);
8099 temp.Store (ec);
8103 public override void Emit (EmitContext ec)
8105 Emit (ec, false);
8108 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8110 int rank = ea.Expr.Type.GetArrayRank ();
8111 ILGenerator ig = ec.ig;
8112 Type t = source.Type;
8113 prepared = prepare_for_load;
8115 if (prepared) {
8116 AddressOf (ec, AddressOp.LoadStore);
8117 ec.ig.Emit (OpCodes.Dup);
8118 } else {
8119 LoadArrayAndArguments (ec);
8122 if (rank == 1) {
8123 bool is_stobj, has_type_arg;
8124 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8126 if (!prepared) {
8128 // The stobj opcode used by value types will need
8129 // an address on the stack, not really an array/array
8130 // pair
8132 if (is_stobj)
8133 ig.Emit (OpCodes.Ldelema, t);
8136 source.Emit (ec);
8137 if (leave_copy) {
8138 ec.ig.Emit (OpCodes.Dup);
8139 temp = new LocalTemporary (this.type);
8140 temp.Store (ec);
8143 if (prepared)
8144 StoreFromPtr (ig, t);
8145 else if (is_stobj)
8146 ig.Emit (OpCodes.Stobj, t);
8147 else if (has_type_arg)
8148 ig.Emit (op, t);
8149 else
8150 ig.Emit (op);
8151 } else {
8152 source.Emit (ec);
8153 if (leave_copy) {
8154 ec.ig.Emit (OpCodes.Dup);
8155 temp = new LocalTemporary (this.type);
8156 temp.Store (ec);
8159 if (prepared) {
8160 StoreFromPtr (ig, t);
8161 } else {
8162 int arg_count = ea.Arguments.Count;
8163 Type [] args = new Type [arg_count + 1];
8164 for (int i = 0; i < arg_count; i++) {
8165 //args [i++] = a.Type;
8166 args [i] = TypeManager.int32_type;
8168 args [arg_count] = type;
8170 MethodInfo set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
8171 ea.Expr.Type, "Set",
8172 CallingConventions.HasThis |
8173 CallingConventions.Standard,
8174 TypeManager.void_type, args);
8176 ig.Emit (OpCodes.Call, set);
8180 if (temp != null) {
8181 temp.Emit (ec);
8182 temp.Release (ec);
8186 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8188 if (!source.Emit (ec, this)) {
8189 if (leave_copy)
8190 throw new NotImplementedException ();
8192 return;
8195 throw new NotImplementedException ();
8198 public void AddressOf (EmitContext ec, AddressOp mode)
8200 int rank = ea.Expr.Type.GetArrayRank ();
8201 ILGenerator ig = ec.ig;
8203 LoadArrayAndArguments (ec);
8205 if (rank == 1){
8206 ig.Emit (OpCodes.Ldelema, type);
8207 } else {
8208 MethodInfo address = FetchAddressMethod ();
8209 ig.Emit (OpCodes.Call, address);
8213 #if NET_4_0
8214 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
8216 return SLE.Expression.ArrayAccess (
8217 ea.Expr.MakeExpression (ctx),
8218 Arguments.MakeExpression (ea.Arguments, ctx));
8221 public override SLE.Expression MakeExpression (BuilderContext ctx)
8223 return SLE.Expression.ArrayIndex (
8224 ea.Expr.MakeExpression (ctx),
8225 Arguments.MakeExpression (ea.Arguments, ctx));
8227 #endif
8229 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8231 type = storey.MutateType (type);
8232 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8236 /// <summary>
8237 /// Expressions that represent an indexer call.
8238 /// </summary>
8239 public class IndexerAccess : Expression, IDynamicAssign
8241 class IndexerMethodGroupExpr : MethodGroupExpr
8243 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8244 : base (null, loc)
8246 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8249 public override string Name {
8250 get {
8251 return "this";
8255 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8258 // Here is the trick, decrease number of arguments by 1 when only
8259 // available property method is setter. This makes overload resolution
8260 // work correctly for indexers.
8263 if (method.Name [0] == 'g')
8264 return parameters.Count;
8266 return parameters.Count - 1;
8270 class Indexers
8272 // Contains either property getter or setter
8273 public ArrayList Methods;
8274 public ArrayList Properties;
8276 Indexers ()
8280 void Append (Type caller_type, MemberInfo [] mi)
8282 if (mi == null)
8283 return;
8285 foreach (PropertyInfo property in mi) {
8286 MethodInfo accessor = property.GetGetMethod (true);
8287 if (accessor == null)
8288 accessor = property.GetSetMethod (true);
8290 if (Methods == null) {
8291 Methods = new ArrayList ();
8292 Properties = new ArrayList ();
8295 Methods.Add (accessor);
8296 Properties.Add (property);
8300 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8302 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8304 return TypeManager.MemberLookup (
8305 caller_type, caller_type, lookup_type, MemberTypes.Property,
8306 BindingFlags.Public | BindingFlags.Instance |
8307 BindingFlags.DeclaredOnly, p_name, null);
8310 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8312 Indexers ix = new Indexers ();
8314 if (TypeManager.IsGenericParameter (lookup_type)) {
8315 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8316 if (gc == null)
8317 return ix;
8319 if (gc.HasClassConstraint) {
8320 Type class_contraint = gc.ClassConstraint;
8321 while (class_contraint != TypeManager.object_type && class_contraint != null) {
8322 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, class_contraint));
8323 class_contraint = class_contraint.BaseType;
8327 Type[] ifaces = gc.InterfaceConstraints;
8328 foreach (Type itype in ifaces)
8329 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8331 return ix;
8334 Type copy = lookup_type;
8335 while (copy != TypeManager.object_type && copy != null){
8336 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8337 copy = copy.BaseType;
8340 if (lookup_type.IsInterface) {
8341 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8342 if (ifaces != null) {
8343 foreach (Type itype in ifaces)
8344 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8348 return ix;
8353 // Points to our "data" repository
8355 MethodInfo get, set;
8356 bool is_base_indexer;
8357 bool prepared;
8358 LocalTemporary temp;
8359 LocalTemporary prepared_value;
8360 Expression set_expr;
8362 protected Type indexer_type;
8363 protected Type current_type;
8364 protected Expression instance_expr;
8365 protected Arguments arguments;
8367 public IndexerAccess (ElementAccess ea, Location loc)
8368 : this (ea.Expr, false, loc)
8370 this.arguments = ea.Arguments;
8373 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8374 Location loc)
8376 this.instance_expr = instance_expr;
8377 this.is_base_indexer = is_base_indexer;
8378 this.eclass = ExprClass.Value;
8379 this.loc = loc;
8382 static string GetAccessorName (bool isSet)
8384 return isSet ? "set" : "get";
8387 public override Expression CreateExpressionTree (ResolveContext ec)
8389 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8390 instance_expr.CreateExpressionTree (ec),
8391 new TypeOfMethod (get, loc));
8393 return CreateExpressionFactoryCall (ec, "Call", args);
8396 protected virtual void CommonResolve (ResolveContext ec)
8398 indexer_type = instance_expr.Type;
8399 current_type = ec.CurrentType;
8402 public override Expression DoResolve (ResolveContext ec)
8404 return ResolveAccessor (ec, null);
8407 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8409 if (right_side == EmptyExpression.OutAccess) {
8410 ec.Report.Error (206, loc,
8411 "A property or indexer may not be passed as an out or ref parameter");
8412 return null;
8415 // if the indexer returns a value type, and we try to set a field in it
8416 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8417 Error_CannotModifyIntermediateExpressionValue (ec);
8420 return ResolveAccessor (ec, right_side);
8423 Expression ResolveAccessor (ResolveContext ec, Expression right_side)
8425 CommonResolve (ec);
8427 bool dynamic;
8428 arguments.Resolve (ec, out dynamic);
8429 if (dynamic || TypeManager.IsDynamicType (indexer_type)) {
8430 int additional = right_side == null ? 1 : 2;
8431 Arguments args = new Arguments (arguments.Count + additional);
8432 if (is_base_indexer) {
8433 ec.Report.Error (1972, loc, "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8434 } else {
8435 args.Add (new Argument (instance_expr));
8437 args.AddRange (arguments);
8438 if (right_side != null)
8439 args.Add (new Argument (right_side));
8441 return new DynamicIndexBinder (right_side != null, args, loc).Resolve (ec);
8444 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8445 if (ilist.Methods == null) {
8446 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8447 TypeManager.CSharpName (indexer_type));
8448 return null;
8451 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8452 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8453 if (mg == null)
8454 return null;
8456 MethodInfo mi = (MethodInfo) mg;
8457 PropertyInfo pi = null;
8458 for (int i = 0; i < ilist.Methods.Count; ++i) {
8459 if (ilist.Methods [i] == mi) {
8460 pi = (PropertyInfo) ilist.Properties [i];
8461 break;
8465 type = TypeManager.TypeToCoreType (pi.PropertyType);
8466 if (type.IsPointer && !ec.IsUnsafe)
8467 UnsafeError (ec, loc);
8469 MethodInfo accessor;
8470 if (right_side == null) {
8471 accessor = get = pi.GetGetMethod (true);
8472 } else {
8473 accessor = set = pi.GetSetMethod (true);
8474 if (accessor == null && pi.GetGetMethod (true) != null) {
8475 ec.Report.SymbolRelatedToPreviousError (pi);
8476 ec.Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8477 TypeManager.GetFullNameSignature (pi));
8478 return null;
8481 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8484 if (accessor == null) {
8485 ec.Report.SymbolRelatedToPreviousError (pi);
8486 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8487 TypeManager.GetFullNameSignature (pi), GetAccessorName (right_side != null));
8488 return null;
8492 // Only base will allow this invocation to happen.
8494 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8495 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (pi));
8498 bool must_do_cs1540_check;
8499 if (!IsAccessorAccessible (ec.CurrentType, accessor, out must_do_cs1540_check)) {
8500 if (set == null)
8501 set = pi.GetSetMethod (true);
8502 else
8503 get = pi.GetGetMethod (true);
8505 if (set != null && get != null &&
8506 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8507 ec.Report.SymbolRelatedToPreviousError (accessor);
8508 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8509 TypeManager.GetFullNameSignature (pi), GetAccessorName (right_side != null));
8510 } else {
8511 ec.Report.SymbolRelatedToPreviousError (pi);
8512 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi), ec.Report);
8516 instance_expr.CheckMarshalByRefAccess (ec);
8517 eclass = ExprClass.IndexerAccess;
8518 return this;
8521 public override void Emit (EmitContext ec)
8523 Emit (ec, false);
8526 public void Emit (EmitContext ec, bool leave_copy)
8528 if (prepared) {
8529 prepared_value.Emit (ec);
8530 } else {
8531 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8532 arguments, loc, false, false);
8535 if (leave_copy) {
8536 ec.ig.Emit (OpCodes.Dup);
8537 temp = new LocalTemporary (Type);
8538 temp.Store (ec);
8543 // source is ignored, because we already have a copy of it from the
8544 // LValue resolution and we have already constructed a pre-cached
8545 // version of the arguments (ea.set_arguments);
8547 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8549 prepared = prepare_for_load;
8550 Expression value = set_expr;
8552 if (prepared) {
8553 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8554 arguments, loc, true, false);
8556 prepared_value = new LocalTemporary (type);
8557 prepared_value.Store (ec);
8558 source.Emit (ec);
8559 prepared_value.Release (ec);
8561 if (leave_copy) {
8562 ec.ig.Emit (OpCodes.Dup);
8563 temp = new LocalTemporary (Type);
8564 temp.Store (ec);
8566 } else if (leave_copy) {
8567 temp = new LocalTemporary (Type);
8568 source.Emit (ec);
8569 temp.Store (ec);
8570 value = temp;
8573 if (!prepared)
8574 arguments.Add (new Argument (value));
8576 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8578 if (temp != null) {
8579 temp.Emit (ec);
8580 temp.Release (ec);
8584 public override string GetSignatureForError ()
8586 return TypeManager.CSharpSignature (get != null ? get : set, false);
8589 #if NET_4_0
8590 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
8592 var value = new[] { set_expr.MakeExpression (ctx) };
8593 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
8595 return SLE.Expression.Block (
8596 SLE.Expression.Call (instance_expr.MakeExpression (ctx), set, args),
8597 value [0]);
8600 public override SLE.Expression MakeExpression (BuilderContext ctx)
8602 var args = Arguments.MakeExpression (arguments, ctx);
8603 return SLE.Expression.Call (instance_expr.MakeExpression (ctx), get, args);
8605 #endif
8607 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8609 if (get != null)
8610 get = storey.MutateGenericMethod (get);
8611 if (set != null)
8612 set = storey.MutateGenericMethod (set);
8614 instance_expr.MutateHoistedGenericType (storey);
8615 if (arguments != null)
8616 arguments.MutateHoistedGenericType (storey);
8618 type = storey.MutateType (type);
8621 protected override void CloneTo (CloneContext clonectx, Expression t)
8623 IndexerAccess target = (IndexerAccess) t;
8625 if (arguments != null)
8626 target.arguments = arguments.Clone (clonectx);
8628 if (instance_expr != null)
8629 target.instance_expr = instance_expr.Clone (clonectx);
8633 /// <summary>
8634 /// The base operator for method names
8635 /// </summary>
8636 public class BaseAccess : Expression {
8637 public readonly string Identifier;
8638 TypeArguments args;
8640 public BaseAccess (string member, Location l)
8642 this.Identifier = member;
8643 loc = l;
8646 public BaseAccess (string member, TypeArguments args, Location l)
8647 : this (member, l)
8649 this.args = args;
8652 public override Expression CreateExpressionTree (ResolveContext ec)
8654 throw new NotSupportedException ("ET");
8657 public override Expression DoResolve (ResolveContext ec)
8659 Expression c = CommonResolve (ec);
8661 if (c == null)
8662 return null;
8665 // MethodGroups use this opportunity to flag an error on lacking ()
8667 if (!(c is MethodGroupExpr))
8668 return c.Resolve (ec);
8669 return c;
8672 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8674 Expression c = CommonResolve (ec);
8676 if (c == null)
8677 return null;
8680 // MethodGroups use this opportunity to flag an error on lacking ()
8682 if (! (c is MethodGroupExpr))
8683 return c.DoResolveLValue (ec, right_side);
8685 return c;
8688 Expression CommonResolve (ResolveContext ec)
8690 Expression member_lookup;
8691 Type current_type = ec.CurrentType;
8692 Type base_type = current_type.BaseType;
8694 if (!This.IsThisAvailable (ec)) {
8695 if (ec.IsStatic) {
8696 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
8697 } else {
8698 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
8700 return null;
8703 member_lookup = MemberLookup (ec.Compiler, ec.CurrentType, null, base_type, Identifier,
8704 AllMemberTypes, AllBindingFlags, loc);
8705 if (member_lookup == null) {
8706 Error_MemberLookupFailed (ec, ec.CurrentType, base_type, base_type, Identifier,
8707 null, AllMemberTypes, AllBindingFlags);
8708 return null;
8711 Expression left;
8713 if (ec.IsStatic)
8714 left = new TypeExpression (base_type, loc);
8715 else
8716 left = ec.GetThis (loc);
8718 MemberExpr me = member_lookup as MemberExpr;
8719 if (me == null){
8720 if (member_lookup is TypeExpression){
8721 ec.Report.Error (582, loc, "{0}: Can not reference a type through an expression, try `{1}' instead",
8722 Identifier, member_lookup.GetSignatureForError ());
8723 } else {
8724 ec.Report.Error (582, loc, "{0}: Can not reference a {1} through an expression",
8725 Identifier, member_lookup.ExprClassName);
8728 return null;
8731 me = me.ResolveMemberAccess (ec, left, loc, null);
8732 if (me == null)
8733 return null;
8735 me.IsBase = true;
8736 if (args != null) {
8737 args.Resolve (ec);
8738 me.SetTypeArguments (ec, args);
8741 return me;
8744 public override void Emit (EmitContext ec)
8746 throw new Exception ("Should never be called");
8749 protected override void CloneTo (CloneContext clonectx, Expression t)
8751 BaseAccess target = (BaseAccess) t;
8753 if (args != null)
8754 target.args = args.Clone ();
8758 /// <summary>
8759 /// The base indexer operator
8760 /// </summary>
8761 public class BaseIndexerAccess : IndexerAccess {
8762 public BaseIndexerAccess (Arguments args, Location loc)
8763 : base (null, true, loc)
8765 this.arguments = args;
8768 protected override void CommonResolve (ResolveContext ec)
8770 instance_expr = ec.GetThis (loc);
8772 current_type = ec.CurrentType.BaseType;
8773 indexer_type = current_type;
8776 public override Expression CreateExpressionTree (ResolveContext ec)
8778 MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
8779 return base.CreateExpressionTree (ec);
8783 /// <summary>
8784 /// This class exists solely to pass the Type around and to be a dummy
8785 /// that can be passed to the conversion functions (this is used by
8786 /// foreach implementation to typecast the object return value from
8787 /// get_Current into the proper type. All code has been generated and
8788 /// we only care about the side effect conversions to be performed
8790 /// This is also now used as a placeholder where a no-action expression
8791 /// is needed (the `New' class).
8792 /// </summary>
8793 public class EmptyExpression : Expression {
8794 public static readonly Expression Null = new EmptyExpression ();
8796 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8797 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8798 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8799 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8801 static EmptyExpression temp = new EmptyExpression ();
8802 public static EmptyExpression Grab ()
8804 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8805 temp = null;
8806 return retval;
8809 public static void Release (EmptyExpression e)
8811 temp = e;
8814 EmptyExpression ()
8816 // FIXME: Don't set to object
8817 type = TypeManager.object_type;
8818 eclass = ExprClass.Value;
8819 loc = Location.Null;
8822 public EmptyExpression (Type t)
8824 type = t;
8825 eclass = ExprClass.Value;
8826 loc = Location.Null;
8829 public override Expression CreateExpressionTree (ResolveContext ec)
8831 throw new NotSupportedException ("ET");
8834 public override Expression DoResolve (ResolveContext ec)
8836 return this;
8839 public override void Emit (EmitContext ec)
8841 // nothing, as we only exist to not do anything.
8844 public override void EmitSideEffect (EmitContext ec)
8849 // This is just because we might want to reuse this bad boy
8850 // instead of creating gazillions of EmptyExpressions.
8851 // (CanImplicitConversion uses it)
8853 public void SetType (Type t)
8855 type = t;
8860 // Empty statement expression
8862 public sealed class EmptyExpressionStatement : ExpressionStatement
8864 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8866 private EmptyExpressionStatement ()
8868 eclass = ExprClass.Value;
8869 loc = Location.Null;
8872 public override Expression CreateExpressionTree (ResolveContext ec)
8874 return null;
8877 public override void EmitStatement (EmitContext ec)
8879 // Do nothing
8882 public override Expression DoResolve (ResolveContext ec)
8884 type = TypeManager.object_type;
8885 return this;
8888 public override void Emit (EmitContext ec)
8890 // Do nothing
8894 public class UserCast : Expression {
8895 MethodInfo method;
8896 Expression source;
8898 public UserCast (MethodInfo method, Expression source, Location l)
8900 this.method = method;
8901 this.source = source;
8902 type = TypeManager.TypeToCoreType (method.ReturnType);
8903 loc = l;
8906 public Expression Source {
8907 get {
8908 return source;
8912 public override Expression CreateExpressionTree (ResolveContext ec)
8914 Arguments args = new Arguments (3);
8915 args.Add (new Argument (source.CreateExpressionTree (ec)));
8916 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8917 args.Add (new Argument (new TypeOfMethod (method, loc)));
8918 return CreateExpressionFactoryCall (ec, "Convert", args);
8921 public override Expression DoResolve (ResolveContext ec)
8923 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
8924 if (oa != null)
8925 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
8927 eclass = ExprClass.Value;
8928 return this;
8931 public override void Emit (EmitContext ec)
8933 source.Emit (ec);
8934 ec.ig.Emit (OpCodes.Call, method);
8937 public override string GetSignatureForError ()
8939 return TypeManager.CSharpSignature (method);
8942 #if NET_4_0
8943 public override SLE.Expression MakeExpression (BuilderContext ctx)
8945 return SLE.Expression.Convert (source.MakeExpression (ctx), type, method);
8947 #endif
8949 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8951 source.MutateHoistedGenericType (storey);
8952 method = storey.MutateGenericMethod (method);
8956 // <summary>
8957 // This class is used to "construct" the type during a typecast
8958 // operation. Since the Type.GetType class in .NET can parse
8959 // the type specification, we just use this to construct the type
8960 // one bit at a time.
8961 // </summary>
8962 public class ComposedCast : TypeExpr {
8963 FullNamedExpression left;
8964 string dim;
8966 public ComposedCast (FullNamedExpression left, string dim)
8967 : this (left, dim, left.Location)
8971 public ComposedCast (FullNamedExpression left, string dim, Location l)
8973 this.left = left;
8974 this.dim = dim;
8975 loc = l;
8978 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
8980 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8981 if (lexpr == null)
8982 return null;
8984 Type ltype = lexpr.Type;
8985 if ((dim.Length > 0) && (dim [0] == '?')) {
8986 TypeExpr nullable = new Nullable.NullableType (lexpr, loc);
8987 if (dim.Length > 1)
8988 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8989 return nullable.ResolveAsTypeTerminal (ec, false);
8992 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8993 return null;
8995 if (dim.Length != 0 && dim [0] == '[') {
8996 if (TypeManager.IsSpecialType (ltype)) {
8997 ec.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8998 return null;
9001 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
9002 ec.Compiler.Report.SymbolRelatedToPreviousError (ltype);
9003 ec.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9004 TypeManager.CSharpName (ltype));
9008 if (dim != "")
9009 type = TypeManager.GetConstructedType (ltype, dim);
9010 else
9011 type = ltype;
9013 if (type == null)
9014 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
9016 if (type.IsPointer && !ec.IsUnsafe){
9017 UnsafeError (ec.Compiler.Report, loc);
9020 eclass = ExprClass.Type;
9021 return this;
9024 public override string GetSignatureForError ()
9026 return left.GetSignatureForError () + dim;
9029 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
9031 return ResolveAsBaseTerminal (ec, silent);
9035 public class FixedBufferPtr : Expression {
9036 Expression array;
9038 public FixedBufferPtr (Expression array, Type array_type, Location l)
9040 this.array = array;
9041 this.loc = l;
9043 type = TypeManager.GetPointerType (array_type);
9044 eclass = ExprClass.Value;
9047 public override Expression CreateExpressionTree (ResolveContext ec)
9049 Error_PointerInsideExpressionTree (ec);
9050 return null;
9053 public override void Emit(EmitContext ec)
9055 array.Emit (ec);
9058 public override Expression DoResolve (ResolveContext ec)
9061 // We are born fully resolved
9063 return this;
9069 // This class is used to represent the address of an array, used
9070 // only by the Fixed statement, this generates "&a [0]" construct
9071 // for fixed (char *pa = a)
9073 public class ArrayPtr : FixedBufferPtr {
9074 Type array_type;
9076 public ArrayPtr (Expression array, Type array_type, Location l):
9077 base (array, array_type, l)
9079 this.array_type = array_type;
9082 public override void Emit (EmitContext ec)
9084 base.Emit (ec);
9086 ILGenerator ig = ec.ig;
9087 IntLiteral.EmitInt (ig, 0);
9088 ig.Emit (OpCodes.Ldelema, array_type);
9093 // Encapsulates a conversion rules required for array indexes
9095 public class ArrayIndexCast : TypeCast
9097 public ArrayIndexCast (Expression expr)
9098 : base (expr, expr.Type)
9100 if (type == TypeManager.int32_type)
9101 throw new ArgumentException ("unnecessary conversion");
9104 public override Expression CreateExpressionTree (ResolveContext ec)
9106 Arguments args = new Arguments (2);
9107 args.Add (new Argument (child.CreateExpressionTree (ec)));
9108 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9109 return CreateExpressionFactoryCall (ec, "ConvertChecked", args);
9112 public override void Emit (EmitContext ec)
9114 child.Emit (ec);
9116 if (type == TypeManager.uint32_type)
9117 ec.ig.Emit (OpCodes.Conv_U);
9118 else if (type == TypeManager.int64_type)
9119 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9120 else if (type == TypeManager.uint64_type)
9121 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9122 else
9123 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9126 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
9128 return child.GetAttributableValue (ec, value_type, out value);
9133 // Implements the `stackalloc' keyword
9135 public class StackAlloc : Expression {
9136 Type otype;
9137 Expression t;
9138 Expression count;
9140 public StackAlloc (Expression type, Expression count, Location l)
9142 t = type;
9143 this.count = count;
9144 loc = l;
9147 public override Expression CreateExpressionTree (ResolveContext ec)
9149 throw new NotSupportedException ("ET");
9152 public override Expression DoResolve (ResolveContext ec)
9154 count = count.Resolve (ec);
9155 if (count == null)
9156 return null;
9158 if (count.Type != TypeManager.uint32_type){
9159 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9160 if (count == null)
9161 return null;
9164 Constant c = count as Constant;
9165 if (c != null && c.IsNegative) {
9166 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9169 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9170 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9173 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9174 if (texpr == null)
9175 return null;
9177 otype = texpr.Type;
9179 if (!TypeManager.VerifyUnManaged (otype, loc))
9180 return null;
9182 type = TypeManager.GetPointerType (otype);
9183 eclass = ExprClass.Value;
9185 return this;
9188 public override void Emit (EmitContext ec)
9190 int size = GetTypeSize (otype);
9191 ILGenerator ig = ec.ig;
9193 count.Emit (ec);
9195 if (size == 0)
9196 ig.Emit (OpCodes.Sizeof, otype);
9197 else
9198 IntConstant.EmitInt (ig, size);
9200 ig.Emit (OpCodes.Mul_Ovf_Un);
9201 ig.Emit (OpCodes.Localloc);
9204 protected override void CloneTo (CloneContext clonectx, Expression t)
9206 StackAlloc target = (StackAlloc) t;
9207 target.count = count.Clone (clonectx);
9208 target.t = t.Clone (clonectx);
9213 // An object initializer expression
9215 public class ElementInitializer : Assign
9217 public readonly string Name;
9219 public ElementInitializer (string name, Expression initializer, Location loc)
9220 : base (null, initializer, loc)
9222 this.Name = name;
9225 protected override void CloneTo (CloneContext clonectx, Expression t)
9227 ElementInitializer target = (ElementInitializer) t;
9228 target.source = source.Clone (clonectx);
9231 public override Expression CreateExpressionTree (ResolveContext ec)
9233 Arguments args = new Arguments (2);
9234 FieldExpr fe = target as FieldExpr;
9235 if (fe != null)
9236 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9237 else
9238 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9240 args.Add (new Argument (source.CreateExpressionTree (ec)));
9241 return CreateExpressionFactoryCall (ec,
9242 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9243 args);
9246 public override Expression DoResolve (ResolveContext ec)
9248 if (source == null)
9249 return EmptyExpressionStatement.Instance;
9251 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9252 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9254 if (me == null)
9255 return null;
9257 target = me;
9258 me.InstanceExpression = ec.CurrentInitializerVariable;
9260 if (source is CollectionOrObjectInitializers) {
9261 Expression previous = ec.CurrentInitializerVariable;
9262 ec.CurrentInitializerVariable = target;
9263 source = source.Resolve (ec);
9264 ec.CurrentInitializerVariable = previous;
9265 if (source == null)
9266 return null;
9268 eclass = source.eclass;
9269 type = source.Type;
9270 return this;
9273 Expression expr = base.DoResolve (ec);
9274 if (expr == null)
9275 return null;
9278 // Ignore field initializers with default value
9280 Constant c = source as Constant;
9281 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9282 return EmptyExpressionStatement.Instance.DoResolve (ec);
9284 return expr;
9287 protected override Expression Error_MemberLookupFailed (ResolveContext ec, Type type, MemberInfo[] members)
9289 MemberInfo member = members [0];
9290 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9291 ec.Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9292 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9293 else
9294 ec.Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9295 TypeManager.GetFullNameSignature (member));
9297 return null;
9300 public override void EmitStatement (EmitContext ec)
9302 if (source is CollectionOrObjectInitializers)
9303 source.Emit (ec);
9304 else
9305 base.EmitStatement (ec);
9310 // A collection initializer expression
9312 class CollectionElementInitializer : Invocation
9314 public class ElementInitializerArgument : Argument
9316 public ElementInitializerArgument (Expression e)
9317 : base (e)
9322 sealed class AddMemberAccess : MemberAccess
9324 public AddMemberAccess (Expression expr, Location loc)
9325 : base (expr, "Add", loc)
9329 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
9331 if (TypeManager.HasElementType (type))
9332 return;
9334 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9338 public CollectionElementInitializer (Expression argument)
9339 : base (null, new Arguments (1))
9341 base.arguments.Add (new ElementInitializerArgument (argument));
9342 this.loc = argument.Location;
9345 public CollectionElementInitializer (ArrayList arguments, Location loc)
9346 : base (null, new Arguments (arguments.Count))
9348 foreach (Expression e in arguments)
9349 base.arguments.Add (new ElementInitializerArgument (e));
9351 this.loc = loc;
9354 public override Expression CreateExpressionTree (ResolveContext ec)
9356 Arguments args = new Arguments (2);
9357 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9359 ArrayList expr_initializers = new ArrayList (arguments.Count);
9360 foreach (Argument a in arguments)
9361 expr_initializers.Add (a.CreateExpressionTree (ec));
9363 args.Add (new Argument (new ArrayCreation (
9364 CreateExpressionTypeExpression (ec, loc), "[]", expr_initializers, loc)));
9365 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9368 protected override void CloneTo (CloneContext clonectx, Expression t)
9370 CollectionElementInitializer target = (CollectionElementInitializer) t;
9371 if (arguments != null)
9372 target.arguments = arguments.Clone (clonectx);
9375 public override Expression DoResolve (ResolveContext ec)
9377 if (eclass != ExprClass.Invalid)
9378 return this;
9380 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9382 return base.DoResolve (ec);
9387 // A block of object or collection initializers
9389 public class CollectionOrObjectInitializers : ExpressionStatement
9391 ArrayList initializers;
9392 bool is_collection_initialization;
9394 public static readonly CollectionOrObjectInitializers Empty =
9395 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9397 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9399 this.initializers = initializers;
9400 this.loc = loc;
9403 public bool IsEmpty {
9404 get {
9405 return initializers.Count == 0;
9409 public bool IsCollectionInitializer {
9410 get {
9411 return is_collection_initialization;
9415 protected override void CloneTo (CloneContext clonectx, Expression target)
9417 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9419 t.initializers = new ArrayList (initializers.Count);
9420 foreach (Expression e in initializers)
9421 t.initializers.Add (e.Clone (clonectx));
9424 public override Expression CreateExpressionTree (ResolveContext ec)
9426 ArrayList expr_initializers = new ArrayList (initializers.Count);
9427 foreach (Expression e in initializers) {
9428 Expression expr = e.CreateExpressionTree (ec);
9429 if (expr != null)
9430 expr_initializers.Add (expr);
9433 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9436 public override Expression DoResolve (ResolveContext ec)
9438 if (eclass != ExprClass.Invalid)
9439 return this;
9441 ArrayList element_names = null;
9442 for (int i = 0; i < initializers.Count; ++i) {
9443 Expression initializer = (Expression) initializers [i];
9444 ElementInitializer element_initializer = initializer as ElementInitializer;
9446 if (i == 0) {
9447 if (element_initializer != null) {
9448 element_names = new ArrayList (initializers.Count);
9449 element_names.Add (element_initializer.Name);
9450 } else if (initializer is CompletingExpression){
9451 initializer.Resolve (ec);
9452 throw new InternalErrorException ("This line should never be reached");
9453 } else {
9454 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type, TypeManager.ienumerable_type)) {
9455 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9456 "object initializer because type `{1}' does not implement `{2}' interface",
9457 ec.CurrentInitializerVariable.GetSignatureForError (),
9458 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9459 TypeManager.CSharpName (TypeManager.ienumerable_type));
9460 return null;
9462 is_collection_initialization = true;
9464 } else {
9465 if (is_collection_initialization != (element_initializer == null)) {
9466 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9467 is_collection_initialization ? "collection initializer" : "object initializer");
9468 continue;
9471 if (!is_collection_initialization) {
9472 if (element_names.Contains (element_initializer.Name)) {
9473 ec.Report.Error (1912, element_initializer.Location,
9474 "An object initializer includes more than one member `{0}' initialization",
9475 element_initializer.Name);
9476 } else {
9477 element_names.Add (element_initializer.Name);
9482 Expression e = initializer.Resolve (ec);
9483 if (e == EmptyExpressionStatement.Instance)
9484 initializers.RemoveAt (i--);
9485 else
9486 initializers [i] = e;
9489 type = ec.CurrentInitializerVariable.Type;
9490 if (is_collection_initialization) {
9491 if (TypeManager.HasElementType (type)) {
9492 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9493 TypeManager.CSharpName (type));
9497 eclass = ExprClass.Variable;
9498 return this;
9501 public override void Emit (EmitContext ec)
9503 EmitStatement (ec);
9506 public override void EmitStatement (EmitContext ec)
9508 foreach (ExpressionStatement e in initializers)
9509 e.EmitStatement (ec);
9512 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9514 foreach (Expression e in initializers)
9515 e.MutateHoistedGenericType (storey);
9520 // New expression with element/object initializers
9522 public class NewInitialize : New
9525 // This class serves as a proxy for variable initializer target instances.
9526 // A real variable is assigned later when we resolve left side of an
9527 // assignment
9529 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9531 NewInitialize new_instance;
9533 public InitializerTargetExpression (NewInitialize newInstance)
9535 this.type = newInstance.type;
9536 this.loc = newInstance.loc;
9537 this.eclass = newInstance.eclass;
9538 this.new_instance = newInstance;
9541 public override Expression CreateExpressionTree (ResolveContext ec)
9543 // Should not be reached
9544 throw new NotSupportedException ("ET");
9547 public override Expression DoResolve (ResolveContext ec)
9549 return this;
9552 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9554 return this;
9557 public override void Emit (EmitContext ec)
9559 Expression e = (Expression) new_instance.instance;
9560 e.Emit (ec);
9563 #region IMemoryLocation Members
9565 public void AddressOf (EmitContext ec, AddressOp mode)
9567 new_instance.instance.AddressOf (ec, mode);
9570 #endregion
9573 CollectionOrObjectInitializers initializers;
9574 IMemoryLocation instance;
9576 public NewInitialize (Expression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9577 : base (requested_type, arguments, l)
9579 this.initializers = initializers;
9582 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9584 instance = base.EmitAddressOf (ec, Mode);
9586 if (!initializers.IsEmpty)
9587 initializers.Emit (ec);
9589 return instance;
9592 protected override void CloneTo (CloneContext clonectx, Expression t)
9594 base.CloneTo (clonectx, t);
9596 NewInitialize target = (NewInitialize) t;
9597 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9600 public override Expression CreateExpressionTree (ResolveContext ec)
9602 Arguments args = new Arguments (2);
9603 args.Add (new Argument (base.CreateExpressionTree (ec)));
9604 if (!initializers.IsEmpty)
9605 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9607 return CreateExpressionFactoryCall (ec,
9608 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9609 args);
9612 public override Expression DoResolve (ResolveContext ec)
9614 if (eclass != ExprClass.Invalid)
9615 return this;
9617 Expression e = base.DoResolve (ec);
9618 if (type == null)
9619 return null;
9621 Expression previous = ec.CurrentInitializerVariable;
9622 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9623 initializers.Resolve (ec);
9624 ec.CurrentInitializerVariable = previous;
9625 return e;
9628 public override bool Emit (EmitContext ec, IMemoryLocation target)
9630 bool left_on_stack = base.Emit (ec, target);
9632 if (initializers.IsEmpty)
9633 return left_on_stack;
9635 LocalTemporary temp = target as LocalTemporary;
9636 if (temp == null) {
9637 if (!left_on_stack) {
9638 VariableReference vr = target as VariableReference;
9640 // FIXME: This still does not work correctly for pre-set variables
9641 if (vr != null && vr.IsRef)
9642 target.AddressOf (ec, AddressOp.Load);
9644 ((Expression) target).Emit (ec);
9645 left_on_stack = true;
9648 temp = new LocalTemporary (type);
9651 instance = temp;
9652 if (left_on_stack)
9653 temp.Store (ec);
9655 initializers.Emit (ec);
9657 if (left_on_stack) {
9658 temp.Emit (ec);
9659 temp.Release (ec);
9662 return left_on_stack;
9665 public override bool HasInitializer {
9666 get {
9667 return !initializers.IsEmpty;
9671 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9673 base.MutateHoistedGenericType (storey);
9674 initializers.MutateHoistedGenericType (storey);
9678 public class AnonymousTypeDeclaration : Expression
9680 ArrayList parameters;
9681 readonly TypeContainer parent;
9682 static readonly ArrayList EmptyParameters = new ArrayList (0);
9684 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9686 this.parameters = parameters;
9687 this.parent = parent;
9688 this.loc = loc;
9691 protected override void CloneTo (CloneContext clonectx, Expression target)
9693 if (parameters == null)
9694 return;
9696 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9697 t.parameters = new ArrayList (parameters.Count);
9698 foreach (AnonymousTypeParameter atp in parameters)
9699 t.parameters.Add (atp.Clone (clonectx));
9702 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, ArrayList parameters)
9704 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
9705 if (type != null)
9706 return type;
9708 type = AnonymousTypeClass.Create (ec.Compiler, parent, parameters, loc);
9709 if (type == null)
9710 return null;
9712 type.DefineType ();
9713 type.Define ();
9714 type.EmitType ();
9715 if (ec.Report.Errors == 0)
9716 type.CloseType ();
9718 parent.Module.AddAnonymousType (type);
9719 return type;
9722 public override Expression CreateExpressionTree (ResolveContext ec)
9724 throw new NotSupportedException ("ET");
9727 public override Expression DoResolve (ResolveContext ec)
9729 AnonymousTypeClass anonymous_type;
9731 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
9732 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9733 return null;
9736 if (parameters == null) {
9737 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
9738 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9739 null, loc).Resolve (ec);
9742 bool error = false;
9743 Arguments arguments = new Arguments (parameters.Count);
9744 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9745 for (int i = 0; i < parameters.Count; ++i) {
9746 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9747 if (e == null) {
9748 error = true;
9749 continue;
9752 arguments.Add (new Argument (e));
9753 t_args [i] = new TypeExpression (e.Type, e.Location);
9756 if (error)
9757 return null;
9759 anonymous_type = CreateAnonymousType (ec, parameters);
9760 if (anonymous_type == null)
9761 return null;
9763 GenericTypeExpr te = new GenericTypeExpr (anonymous_type.TypeBuilder,
9764 new TypeArguments (t_args), loc);
9766 return new New (te, arguments, loc).Resolve (ec);
9769 public override void Emit (EmitContext ec)
9771 throw new InternalErrorException ("Should not be reached");
9775 public class AnonymousTypeParameter : ShimExpression
9777 public readonly string Name;
9779 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9780 : base (initializer)
9782 this.Name = name;
9783 this.loc = loc;
9786 public AnonymousTypeParameter (Parameter parameter)
9787 : base (new SimpleName (parameter.Name, parameter.Location))
9789 this.Name = parameter.Name;
9790 this.loc = parameter.Location;
9793 public override bool Equals (object o)
9795 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9796 return other != null && Name == other.Name;
9799 public override int GetHashCode ()
9801 return Name.GetHashCode ();
9804 public override Expression DoResolve (ResolveContext ec)
9806 Expression e = expr.Resolve (ec);
9807 if (e == null)
9808 return null;
9810 if (e.eclass == ExprClass.MethodGroup) {
9811 Error_InvalidInitializer (ec, e.ExprClassName);
9812 return null;
9815 type = e.Type;
9816 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9817 type == InternalType.AnonymousMethod || type.IsPointer) {
9818 Error_InvalidInitializer (ec, e.GetSignatureForError ());
9819 return null;
9822 return e;
9825 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
9827 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9828 Name, initializer);