2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 using System.Collections.Generic;
15 using SLE = System.Linq.Expressions;
18 using MetaType = IKVM.Reflection.Type;
19 using IKVM.Reflection;
20 using IKVM.Reflection.Emit;
22 using MetaType = System.Type;
23 using System.Reflection;
24 using System.Reflection.Emit;
30 // This is an user operator expression, automatically created during
33 public class UserOperatorCall : Expression {
34 protected readonly Arguments arguments;
35 protected readonly MethodSpec oper;
36 readonly Func<ResolveContext, Expression, Expression> expr_tree;
38 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
41 this.arguments = args;
42 this.expr_tree = expr_tree;
44 type = oper.ReturnType;
45 eclass = ExprClass.Value;
49 public override Expression CreateExpressionTree (ResolveContext ec)
51 if (expr_tree != null)
52 return expr_tree (ec, new TypeOfMethod (oper, loc));
54 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
55 new NullLiteral (loc),
56 new TypeOfMethod (oper, loc));
58 return CreateExpressionFactoryCall (ec, "Call", args);
61 protected override void CloneTo (CloneContext context, Expression target)
66 protected override Expression DoResolve (ResolveContext ec)
69 // We are born fully resolved
74 public override void Emit (EmitContext ec)
76 Invocation.EmitCall (ec, null, oper, arguments, loc);
79 public override SLE.Expression MakeExpression (BuilderContext ctx)
82 return base.MakeExpression (ctx);
84 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
89 public class ParenthesizedExpression : ShimExpression
91 public ParenthesizedExpression (Expression expr)
97 protected override Expression DoResolve (ResolveContext ec)
99 return expr.Resolve (ec);
102 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
104 return expr.DoResolveLValue (ec, right_side);
109 // Unary implements unary expressions.
111 public class Unary : Expression
113 public enum Operator : byte {
114 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
118 static TypeSpec[][] predefined_operators;
120 public readonly Operator Oper;
121 public Expression Expr;
122 Expression enum_conversion;
124 public Unary (Operator op, Expression expr, Location loc)
132 // This routine will attempt to simplify the unary expression when the
133 // argument is a constant.
135 Constant TryReduceConstant (ResolveContext ec, Constant e)
137 if (e is EmptyConstantCast)
138 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
140 if (e is SideEffectConstant) {
141 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
142 return r == null ? null : new SideEffectConstant (r, e, r.Location);
145 TypeSpec expr_type = e.Type;
148 case Operator.UnaryPlus:
149 // Unary numeric promotions
150 if (expr_type == TypeManager.byte_type)
151 return new IntConstant (((ByteConstant)e).Value, e.Location);
152 if (expr_type == TypeManager.sbyte_type)
153 return new IntConstant (((SByteConstant)e).Value, e.Location);
154 if (expr_type == TypeManager.short_type)
155 return new IntConstant (((ShortConstant)e).Value, e.Location);
156 if (expr_type == TypeManager.ushort_type)
157 return new IntConstant (((UShortConstant)e).Value, e.Location);
158 if (expr_type == TypeManager.char_type)
159 return new IntConstant (((CharConstant)e).Value, e.Location);
161 // Predefined operators
162 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
163 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
164 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
165 expr_type == TypeManager.decimal_type) {
171 case Operator.UnaryNegation:
172 // Unary numeric promotions
173 if (expr_type == TypeManager.byte_type)
174 return new IntConstant (-((ByteConstant)e).Value, e.Location);
175 if (expr_type == TypeManager.sbyte_type)
176 return new IntConstant (-((SByteConstant)e).Value, e.Location);
177 if (expr_type == TypeManager.short_type)
178 return new IntConstant (-((ShortConstant)e).Value, e.Location);
179 if (expr_type == TypeManager.ushort_type)
180 return new IntConstant (-((UShortConstant)e).Value, e.Location);
181 if (expr_type == TypeManager.char_type)
182 return new IntConstant (-((CharConstant)e).Value, e.Location);
184 // Predefined operators
185 if (expr_type == TypeManager.int32_type) {
186 int value = ((IntConstant)e).Value;
187 if (value == int.MinValue) {
188 if (ec.ConstantCheckState) {
189 ConstantFold.Error_CompileTimeOverflow (ec, loc);
194 return new IntConstant (-value, e.Location);
196 if (expr_type == TypeManager.int64_type) {
197 long value = ((LongConstant)e).Value;
198 if (value == long.MinValue) {
199 if (ec.ConstantCheckState) {
200 ConstantFold.Error_CompileTimeOverflow (ec, loc);
205 return new LongConstant (-value, e.Location);
208 if (expr_type == TypeManager.uint32_type) {
209 UIntLiteral uil = e as UIntLiteral;
211 if (uil.Value == int.MaxValue + (uint) 1)
212 return new IntLiteral (int.MinValue, e.Location);
213 return new LongLiteral (-uil.Value, e.Location);
215 return new LongConstant (-((UIntConstant)e).Value, e.Location);
218 if (expr_type == TypeManager.uint64_type) {
219 ULongLiteral ull = e as ULongLiteral;
220 if (ull != null && ull.Value == 9223372036854775808)
221 return new LongLiteral (long.MinValue, e.Location);
225 if (expr_type == TypeManager.float_type) {
226 FloatLiteral fl = e as FloatLiteral;
227 // For better error reporting
229 return new FloatLiteral (-fl.Value, e.Location);
231 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
233 if (expr_type == TypeManager.double_type) {
234 DoubleLiteral dl = e as DoubleLiteral;
235 // For better error reporting
237 return new DoubleLiteral (-dl.Value, e.Location);
239 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
241 if (expr_type == TypeManager.decimal_type)
242 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
246 case Operator.LogicalNot:
247 if (expr_type != TypeManager.bool_type)
250 bool b = (bool)e.GetValue ();
251 return new BoolConstant (!b, e.Location);
253 case Operator.OnesComplement:
254 // Unary numeric promotions
255 if (expr_type == TypeManager.byte_type)
256 return new IntConstant (~((ByteConstant)e).Value, e.Location);
257 if (expr_type == TypeManager.sbyte_type)
258 return new IntConstant (~((SByteConstant)e).Value, e.Location);
259 if (expr_type == TypeManager.short_type)
260 return new IntConstant (~((ShortConstant)e).Value, e.Location);
261 if (expr_type == TypeManager.ushort_type)
262 return new IntConstant (~((UShortConstant)e).Value, e.Location);
263 if (expr_type == TypeManager.char_type)
264 return new IntConstant (~((CharConstant)e).Value, e.Location);
266 // Predefined operators
267 if (expr_type == TypeManager.int32_type)
268 return new IntConstant (~((IntConstant)e).Value, e.Location);
269 if (expr_type == TypeManager.uint32_type)
270 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
271 if (expr_type == TypeManager.int64_type)
272 return new LongConstant (~((LongConstant)e).Value, e.Location);
273 if (expr_type == TypeManager.uint64_type){
274 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
276 if (e is EnumConstant) {
277 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
279 e = new EnumConstant (e, expr_type);
284 throw new Exception ("Can not constant fold: " + Oper.ToString());
287 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
289 eclass = ExprClass.Value;
291 if (predefined_operators == null)
292 CreatePredefinedOperatorsTable ();
294 TypeSpec expr_type = expr.Type;
295 Expression best_expr;
298 // Primitive types first
300 if (TypeManager.IsPrimitiveType (expr_type)) {
301 best_expr = ResolvePrimitivePredefinedType (expr);
302 if (best_expr == null)
305 type = best_expr.Type;
311 // E operator ~(E x);
313 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
314 return ResolveEnumOperator (ec, expr);
316 return ResolveUserType (ec, expr);
319 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr)
321 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
322 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
323 if (best_expr == null)
327 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
329 return EmptyCast.Create (this, type);
332 public override Expression CreateExpressionTree (ResolveContext ec)
334 return CreateExpressionTree (ec, null);
337 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
341 case Operator.AddressOf:
342 Error_PointerInsideExpressionTree (ec);
344 case Operator.UnaryNegation:
345 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
346 method_name = "NegateChecked";
348 method_name = "Negate";
350 case Operator.OnesComplement:
351 case Operator.LogicalNot:
354 case Operator.UnaryPlus:
355 method_name = "UnaryPlus";
358 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
361 Arguments args = new Arguments (2);
362 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
364 args.Add (new Argument (user_op));
366 return CreateExpressionFactoryCall (ec, method_name, args);
369 static void CreatePredefinedOperatorsTable ()
371 predefined_operators = new TypeSpec [(int) Operator.TOP] [];
374 // 7.6.1 Unary plus operator
376 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
377 TypeManager.int32_type, TypeManager.uint32_type,
378 TypeManager.int64_type, TypeManager.uint64_type,
379 TypeManager.float_type, TypeManager.double_type,
380 TypeManager.decimal_type
384 // 7.6.2 Unary minus operator
386 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
387 TypeManager.int32_type,
388 TypeManager.int64_type,
389 TypeManager.float_type, TypeManager.double_type,
390 TypeManager.decimal_type
394 // 7.6.3 Logical negation operator
396 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
397 TypeManager.bool_type
401 // 7.6.4 Bitwise complement operator
403 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
404 TypeManager.int32_type, TypeManager.uint32_type,
405 TypeManager.int64_type, TypeManager.uint64_type
410 // Unary numeric promotions
412 static Expression DoNumericPromotion (Operator op, Expression expr)
414 TypeSpec expr_type = expr.Type;
415 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
416 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
417 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
418 expr_type == TypeManager.char_type)
419 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
421 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
422 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
427 protected override Expression DoResolve (ResolveContext ec)
429 if (Oper == Operator.AddressOf) {
430 return ResolveAddressOf (ec);
433 Expr = Expr.Resolve (ec);
437 if (Expr.Type == InternalType.Dynamic) {
438 Arguments args = new Arguments (1);
439 args.Add (new Argument (Expr));
440 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
443 if (TypeManager.IsNullableType (Expr.Type))
444 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
447 // Attempt to use a constant folding operation.
449 Constant cexpr = Expr as Constant;
451 cexpr = TryReduceConstant (ec, cexpr);
453 return cexpr.Resolve (ec);
456 Expression expr = ResolveOperator (ec, Expr);
458 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
461 // Reduce unary operator on predefined types
463 if (expr == this && Oper == Operator.UnaryPlus)
469 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
474 public override void Emit (EmitContext ec)
476 EmitOperator (ec, type);
479 protected void EmitOperator (EmitContext ec, TypeSpec type)
482 case Operator.UnaryPlus:
486 case Operator.UnaryNegation:
487 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
488 ec.Emit (OpCodes.Ldc_I4_0);
489 if (type == TypeManager.int64_type)
490 ec.Emit (OpCodes.Conv_U8);
492 ec.Emit (OpCodes.Sub_Ovf);
495 ec.Emit (OpCodes.Neg);
500 case Operator.LogicalNot:
502 ec.Emit (OpCodes.Ldc_I4_0);
503 ec.Emit (OpCodes.Ceq);
506 case Operator.OnesComplement:
508 ec.Emit (OpCodes.Not);
511 case Operator.AddressOf:
512 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
516 throw new Exception ("This should not happen: Operator = "
521 // Same trick as in Binary expression
523 if (enum_conversion != null)
524 enum_conversion.Emit (ec);
527 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
529 if (Oper == Operator.LogicalNot)
530 Expr.EmitBranchable (ec, target, !on_true);
532 base.EmitBranchable (ec, target, on_true);
535 public override void EmitSideEffect (EmitContext ec)
537 Expr.EmitSideEffect (ec);
540 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Location loc, string oper, TypeSpec t)
542 ec.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
543 oper, TypeManager.CSharpName (t));
547 // Converts operator to System.Linq.Expressions.ExpressionType enum name
549 string GetOperatorExpressionTypeName ()
552 case Operator.OnesComplement:
553 return "OnesComplement";
554 case Operator.LogicalNot:
556 case Operator.UnaryNegation:
558 case Operator.UnaryPlus:
561 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
565 static bool IsFloat (TypeSpec t)
567 return t == TypeManager.float_type || t == TypeManager.double_type;
571 // Returns a stringified representation of the Operator
573 public static string OperName (Operator oper)
576 case Operator.UnaryPlus:
578 case Operator.UnaryNegation:
580 case Operator.LogicalNot:
582 case Operator.OnesComplement:
584 case Operator.AddressOf:
588 throw new NotImplementedException (oper.ToString ());
591 public override SLE.Expression MakeExpression (BuilderContext ctx)
593 var expr = Expr.MakeExpression (ctx);
594 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
597 case Operator.UnaryNegation:
598 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
599 case Operator.LogicalNot:
600 return SLE.Expression.Not (expr);
602 case Operator.OnesComplement:
603 return SLE.Expression.OnesComplement (expr);
606 throw new NotImplementedException (Oper.ToString ());
610 public static void Reset ()
612 predefined_operators = null;
615 Expression ResolveAddressOf (ResolveContext ec)
618 UnsafeError (ec, loc);
620 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
621 if (Expr == null || Expr.eclass != ExprClass.Variable) {
622 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
626 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
630 IVariableReference vr = Expr as IVariableReference;
633 VariableInfo vi = vr.VariableInfo;
635 if (vi.LocalInfo != null)
636 vi.LocalInfo.SetIsUsed ();
639 // A variable is considered definitely assigned if you take its address.
644 is_fixed = vr.IsFixed;
645 vr.SetHasAddressTaken ();
648 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
651 IFixedExpression fe = Expr as IFixedExpression;
652 is_fixed = fe != null && fe.IsFixed;
655 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
656 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
659 type = PointerContainer.MakeType (Expr.Type);
660 eclass = ExprClass.Value;
664 Expression ResolvePrimitivePredefinedType (Expression expr)
666 expr = DoNumericPromotion (Oper, expr);
667 TypeSpec expr_type = expr.Type;
668 TypeSpec[] predefined = predefined_operators [(int) Oper];
669 foreach (TypeSpec t in predefined) {
677 // Perform user-operator overload resolution
679 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
681 CSharp.Operator.OpType op_type;
683 case Operator.LogicalNot:
684 op_type = CSharp.Operator.OpType.LogicalNot; break;
685 case Operator.OnesComplement:
686 op_type = CSharp.Operator.OpType.OnesComplement; break;
687 case Operator.UnaryNegation:
688 op_type = CSharp.Operator.OpType.UnaryNegation; break;
689 case Operator.UnaryPlus:
690 op_type = CSharp.Operator.OpType.UnaryPlus; break;
692 throw new InternalErrorException (Oper.ToString ());
695 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
699 Arguments args = new Arguments (1);
700 args.Add (new Argument (expr));
702 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
703 var oper = res.ResolveOperator (ec, ref args);
708 Expr = args [0].Expr;
709 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
713 // Unary user type overload resolution
715 Expression ResolveUserType (ResolveContext ec, Expression expr)
717 Expression best_expr = ResolveUserOperator (ec, expr);
718 if (best_expr != null)
721 TypeSpec[] predefined = predefined_operators [(int) Oper];
722 foreach (TypeSpec t in predefined) {
723 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
724 if (oper_expr == null)
728 // decimal type is predefined but has user-operators
730 if (oper_expr.Type == TypeManager.decimal_type)
731 oper_expr = ResolveUserType (ec, oper_expr);
733 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
735 if (oper_expr == null)
738 if (best_expr == null) {
739 best_expr = oper_expr;
743 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
745 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
746 OperName (Oper), TypeManager.CSharpName (expr.Type));
751 best_expr = oper_expr;
754 if (best_expr == null)
758 // HACK: Decimal user-operator is included in standard operators
760 if (best_expr.Type == TypeManager.decimal_type)
764 type = best_expr.Type;
768 protected override void CloneTo (CloneContext clonectx, Expression t)
770 Unary target = (Unary) t;
772 target.Expr = Expr.Clone (clonectx);
777 // Unary operators are turned into Indirection expressions
778 // after semantic analysis (this is so we can take the address
779 // of an indirection).
781 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
783 LocalTemporary temporary;
786 public Indirection (Expression expr, Location l)
792 public override Expression CreateExpressionTree (ResolveContext ec)
794 Error_PointerInsideExpressionTree (ec);
798 protected override void CloneTo (CloneContext clonectx, Expression t)
800 Indirection target = (Indirection) t;
801 target.expr = expr.Clone (clonectx);
804 public override void Emit (EmitContext ec)
809 ec.EmitLoadFromPtr (Type);
812 public void Emit (EmitContext ec, bool leave_copy)
816 ec.Emit (OpCodes.Dup);
817 temporary = new LocalTemporary (expr.Type);
818 temporary.Store (ec);
822 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
824 prepared = prepare_for_load;
828 if (prepare_for_load)
829 ec.Emit (OpCodes.Dup);
833 ec.Emit (OpCodes.Dup);
834 temporary = new LocalTemporary (expr.Type);
835 temporary.Store (ec);
838 ec.EmitStoreFromPtr (type);
840 if (temporary != null) {
842 temporary.Release (ec);
846 public void AddressOf (EmitContext ec, AddressOp Mode)
851 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
853 return DoResolve (ec);
856 protected override Expression DoResolve (ResolveContext ec)
858 expr = expr.Resolve (ec);
863 UnsafeError (ec, loc);
865 var pc = expr.Type as PointerContainer;
868 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
874 if (type.BuildinType == BuildinTypeSpec.Type.Void) {
875 Error_VoidPointerOperation (ec);
879 eclass = ExprClass.Variable;
883 public bool IsFixed {
887 public override string ToString ()
889 return "*(" + expr + ")";
894 /// Unary Mutator expressions (pre and post ++ and --)
898 /// UnaryMutator implements ++ and -- expressions. It derives from
899 /// ExpressionStatement becuase the pre/post increment/decrement
900 /// operators can be used in a statement context.
902 /// FIXME: Idea, we could split this up in two classes, one simpler
903 /// for the common case, and one with the extra fields for more complex
904 /// classes (indexers require temporary access; overloaded require method)
907 public class UnaryMutator : ExpressionStatement
909 class DynamicPostMutator : Expression, IAssignMethod
914 public DynamicPostMutator (Expression expr)
917 this.type = expr.Type;
918 this.loc = expr.Location;
921 public override Expression CreateExpressionTree (ResolveContext ec)
923 throw new NotImplementedException ("ET");
926 protected override Expression DoResolve (ResolveContext rc)
928 eclass = expr.eclass;
932 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
934 expr.DoResolveLValue (ec, right_side);
935 return DoResolve (ec);
938 public override void Emit (EmitContext ec)
943 public void Emit (EmitContext ec, bool leave_copy)
945 throw new NotImplementedException ();
949 // Emits target assignment using unmodified source value
951 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
954 // Allocate temporary variable to keep original value before it's modified
956 temp = new LocalTemporary (type);
960 ((IAssignMethod) expr).EmitAssign (ec, source, false, prepare_for_load);
971 public enum Mode : byte {
978 PreDecrement = IsDecrement,
979 PostIncrement = IsPost,
980 PostDecrement = IsPost | IsDecrement
984 bool is_expr, recurse;
988 // Holds the real operation
989 Expression operation;
991 static TypeSpec[] predefined;
993 public UnaryMutator (Mode m, Expression e, Location loc)
1000 public override Expression CreateExpressionTree (ResolveContext ec)
1002 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1005 void CreatePredefinedOperators ()
1008 // Predefined ++ and -- operators exist for the following types:
1009 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1011 predefined = new TypeSpec[] {
1012 TypeManager.int32_type,
1014 TypeManager.sbyte_type,
1015 TypeManager.byte_type,
1016 TypeManager.short_type,
1017 TypeManager.ushort_type,
1018 TypeManager.uint32_type,
1019 TypeManager.int64_type,
1020 TypeManager.uint64_type,
1021 TypeManager.char_type,
1022 TypeManager.float_type,
1023 TypeManager.double_type,
1024 TypeManager.decimal_type
1028 protected override Expression DoResolve (ResolveContext ec)
1030 expr = expr.Resolve (ec);
1035 if (expr.Type == InternalType.Dynamic) {
1037 // Handle postfix unary operators using local
1038 // temporary variable
1040 if ((mode & Mode.IsPost) != 0)
1041 expr = new DynamicPostMutator (expr);
1043 Arguments args = new Arguments (1);
1044 args.Add (new Argument (expr));
1045 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1048 if (TypeManager.IsNullableType (expr.Type))
1049 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1051 eclass = ExprClass.Value;
1054 if (expr is RuntimeValueExpression) {
1057 // Use itself at the top of the stack
1058 operation = new EmptyExpression (type);
1062 // The operand of the prefix/postfix increment decrement operators
1063 // should be an expression that is classified as a variable,
1064 // a property access or an indexer access
1066 // TODO: Move to parser, expr is ATypeNameExpression
1067 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1068 expr = expr.ResolveLValue (ec, expr);
1070 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1074 // Step 1: Try to find a user operator, it has priority over predefined ones
1076 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1077 var methods = MemberCache.GetUserOperator (type, user_op, false);
1079 if (methods != null) {
1080 Arguments args = new Arguments (1);
1081 args.Add (new Argument (expr));
1083 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1084 var method = res.ResolveOperator (ec, ref args);
1088 args[0].Expr = operation;
1089 operation = new UserOperatorCall (method, args, null, loc);
1090 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1095 // Step 2: Try predefined types
1097 if (predefined == null)
1098 CreatePredefinedOperators ();
1100 // Predefined without user conversion first for speed-up
1101 Expression source = null;
1102 bool primitive_type = false;
1103 foreach (var t in predefined) {
1106 primitive_type = true;
1111 // ++/-- on pointer variables of all types except void*
1112 if (source == null && type.IsPointer) {
1113 if (((PointerContainer) type).Element.BuildinType == BuildinTypeSpec.Type.Void) {
1114 Error_VoidPointerOperation (ec);
1121 if (source == null) {
1122 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1123 foreach (var t in predefined) {
1124 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1125 if (source != null) {
1131 // ++/-- on enum types
1132 if (source == null && type.IsEnum)
1135 if (source == null) {
1136 Unary.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1140 var one = new IntConstant (1, loc);
1141 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1142 operation = new Binary (op, source, one, loc);
1143 operation = operation.Resolve (ec);
1144 if (operation == null)
1145 throw new NotImplementedException ("should not be reached");
1147 if (operation.Type != type) {
1149 operation = Convert.ExplicitNumericConversion (operation, type);
1151 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1157 void EmitCode (EmitContext ec, bool is_expr)
1160 this.is_expr = is_expr;
1161 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1164 public override void Emit (EmitContext ec)
1167 // We use recurse to allow ourselfs to be the source
1168 // of an assignment. This little hack prevents us from
1169 // having to allocate another expression
1172 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1174 operation.Emit (ec);
1180 EmitCode (ec, true);
1183 public override void EmitStatement (EmitContext ec)
1185 EmitCode (ec, false);
1189 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1191 string GetOperatorExpressionTypeName ()
1193 return IsDecrement ? "Decrement" : "Increment";
1197 get { return (mode & Mode.IsDecrement) != 0; }
1202 public override SLE.Expression MakeExpression (BuilderContext ctx)
1204 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1205 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1206 return SLE.Expression.Assign (target, source);
1210 public static void Reset ()
1215 protected override void CloneTo (CloneContext clonectx, Expression t)
1217 UnaryMutator target = (UnaryMutator) t;
1219 target.expr = expr.Clone (clonectx);
1224 /// Base class for the `Is' and `As' classes.
1228 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1231 public abstract class Probe : Expression {
1232 public Expression ProbeType;
1233 protected Expression expr;
1234 protected TypeExpr probe_type_expr;
1236 public Probe (Expression expr, Expression probe_type, Location l)
1238 ProbeType = probe_type;
1243 public Expression Expr {
1249 protected override Expression DoResolve (ResolveContext ec)
1251 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1252 if (probe_type_expr == null)
1255 expr = expr.Resolve (ec);
1259 if (probe_type_expr.Type.IsStatic) {
1260 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1264 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1265 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1270 if (expr.Type == InternalType.AnonymousMethod) {
1271 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1279 protected abstract string OperatorName { get; }
1281 protected override void CloneTo (CloneContext clonectx, Expression t)
1283 Probe target = (Probe) t;
1285 target.expr = expr.Clone (clonectx);
1286 target.ProbeType = ProbeType.Clone (clonectx);
1292 /// Implementation of the `is' operator.
1294 public class Is : Probe {
1295 Nullable.Unwrap expr_unwrap;
1297 public Is (Expression expr, Expression probe_type, Location l)
1298 : base (expr, probe_type, l)
1302 public override Expression CreateExpressionTree (ResolveContext ec)
1304 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1305 expr.CreateExpressionTree (ec),
1306 new TypeOf (probe_type_expr, loc));
1308 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1311 public override void Emit (EmitContext ec)
1313 if (expr_unwrap != null) {
1314 expr_unwrap.EmitCheck (ec);
1319 ec.Emit (OpCodes.Isinst, probe_type_expr.Type);
1320 ec.Emit (OpCodes.Ldnull);
1321 ec.Emit (OpCodes.Cgt_Un);
1324 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1326 if (expr_unwrap != null) {
1327 expr_unwrap.EmitCheck (ec);
1330 ec.Emit (OpCodes.Isinst, probe_type_expr.Type);
1332 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1335 Expression CreateConstantResult (ResolveContext ec, bool result)
1338 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1339 TypeManager.CSharpName (probe_type_expr.Type));
1341 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1342 TypeManager.CSharpName (probe_type_expr.Type));
1344 return ReducedExpression.Create (new BoolConstant (result, loc).Resolve (ec), this);
1347 protected override Expression DoResolve (ResolveContext ec)
1349 if (base.DoResolve (ec) == null)
1352 TypeSpec d = expr.Type;
1353 bool d_is_nullable = false;
1356 // If E is a method group or the null literal, or if the type of E is a reference
1357 // type or a nullable type and the value of E is null, the result is false
1359 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1360 return CreateConstantResult (ec, false);
1362 if (TypeManager.IsNullableType (d)) {
1363 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1364 if (!ut.IsGenericParameter) {
1366 d_is_nullable = true;
1370 type = TypeManager.bool_type;
1371 eclass = ExprClass.Value;
1372 TypeSpec t = probe_type_expr.Type;
1373 bool t_is_nullable = false;
1374 if (TypeManager.IsNullableType (t)) {
1375 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1376 if (!ut.IsGenericParameter) {
1378 t_is_nullable = true;
1382 if (TypeManager.IsStruct (t)) {
1385 // D and T are the same value types but D can be null
1387 if (d_is_nullable && !t_is_nullable) {
1388 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1393 // The result is true if D and T are the same value types
1395 return CreateConstantResult (ec, true);
1398 var tp = d as TypeParameterSpec;
1400 return ResolveGenericParameter (ec, t, tp);
1403 // An unboxing conversion exists
1405 if (Convert.ExplicitReferenceConversionExists (d, t))
1408 if (TypeManager.IsGenericParameter (t))
1409 return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
1411 if (t == InternalType.Dynamic) {
1412 ec.Report.Warning (1981, 3, loc,
1413 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1414 OperatorName, t.GetSignatureForError ());
1417 if (TypeManager.IsStruct (d) && d != TypeManager.void_type) {
1418 if (Convert.ImplicitBoxingConversion (null, d, t) != null)
1419 return CreateConstantResult (ec, true);
1421 if (TypeManager.IsGenericParameter (d))
1422 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1424 if (InflatedTypeSpec.ContainsTypeParameter (d))
1427 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1428 Convert.ExplicitReferenceConversionExists (d, t)) {
1434 return CreateConstantResult (ec, false);
1437 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1439 if (t.IsReferenceType) {
1440 if (TypeManager.IsStruct (d))
1441 return CreateConstantResult (ec, false);
1444 if (TypeManager.IsGenericParameter (expr.Type)) {
1445 if (t.IsValueType && expr.Type == d)
1446 return CreateConstantResult (ec, true);
1448 expr = new BoxedCast (expr, d);
1454 protected override string OperatorName {
1455 get { return "is"; }
1460 /// Implementation of the `as' operator.
1462 public class As : Probe {
1463 Expression resolved_type;
1465 public As (Expression expr, Expression probe_type, Location l)
1466 : base (expr, probe_type, l)
1470 public override Expression CreateExpressionTree (ResolveContext ec)
1472 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1473 expr.CreateExpressionTree (ec),
1474 new TypeOf (probe_type_expr, loc));
1476 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1479 public override void Emit (EmitContext ec)
1483 ec.Emit (OpCodes.Isinst, type);
1485 if (TypeManager.IsGenericParameter (type) || TypeManager.IsNullableType (type))
1486 ec.Emit (OpCodes.Unbox_Any, type);
1489 protected override Expression DoResolve (ResolveContext ec)
1491 if (resolved_type == null) {
1492 resolved_type = base.DoResolve (ec);
1494 if (resolved_type == null)
1498 type = probe_type_expr.Type;
1499 eclass = ExprClass.Value;
1500 TypeSpec etype = expr.Type;
1502 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1503 if (TypeManager.IsGenericParameter (type)) {
1504 ec.Report.Error (413, loc,
1505 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1506 probe_type_expr.GetSignatureForError ());
1508 ec.Report.Error (77, loc,
1509 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1510 TypeManager.CSharpName (type));
1515 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1516 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1519 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1520 if (etype == InternalType.Dynamic) {
1524 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1526 e = EmptyCast.Create (e, type);
1527 return ReducedExpression.Create (e, this).Resolve (ec);
1530 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1531 if (TypeManager.IsGenericParameter (etype))
1532 expr = new BoxedCast (expr, etype);
1537 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1538 expr = new BoxedCast (expr, etype);
1542 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1543 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1548 protected override string OperatorName {
1549 get { return "as"; }
1554 // This represents a typecast in the source language.
1556 public class Cast : ShimExpression {
1557 Expression target_type;
1559 public Cast (Expression cast_type, Expression expr, Location loc)
1562 this.target_type = cast_type;
1566 public Expression TargetType {
1567 get { return target_type; }
1570 protected override Expression DoResolve (ResolveContext ec)
1572 expr = expr.Resolve (ec);
1576 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1582 if (type.IsStatic) {
1583 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1587 eclass = ExprClass.Value;
1589 Constant c = expr as Constant;
1591 c = c.TryReduce (ec, type, loc);
1596 if (type.IsPointer && !ec.IsUnsafe) {
1597 UnsafeError (ec, loc);
1600 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1602 return EmptyCast.Create (res, type);
1607 protected override void CloneTo (CloneContext clonectx, Expression t)
1609 Cast target = (Cast) t;
1611 target.target_type = target_type.Clone (clonectx);
1612 target.expr = expr.Clone (clonectx);
1616 public class ImplicitCast : ShimExpression
1620 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1623 this.loc = expr.Location;
1625 this.arrayAccess = arrayAccess;
1628 protected override Expression DoResolve (ResolveContext ec)
1630 expr = expr.Resolve (ec);
1635 expr = ConvertExpressionToArrayIndex (ec, expr);
1637 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1644 // C# 2.0 Default value expression
1646 public class DefaultValueExpression : Expression
1650 public DefaultValueExpression (Expression expr, Location loc)
1656 public override Expression CreateExpressionTree (ResolveContext ec)
1658 Arguments args = new Arguments (2);
1659 args.Add (new Argument (this));
1660 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1661 return CreateExpressionFactoryCall (ec, "Constant", args);
1664 protected override Expression DoResolve (ResolveContext ec)
1666 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1672 if (type.IsStatic) {
1673 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1677 return new NullLiteral (Location).ConvertImplicitly (ec, type);
1679 if (TypeManager.IsReferenceType (type))
1680 return new NullConstant (type, loc);
1682 Constant c = New.Constantify (type, expr.Location);
1684 return c.Resolve (ec);
1686 eclass = ExprClass.Variable;
1690 public override void Emit (EmitContext ec)
1692 LocalTemporary temp_storage = new LocalTemporary(type);
1694 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1695 ec.Emit(OpCodes.Initobj, type);
1696 temp_storage.Emit(ec);
1699 #if NET_4_0 && !STATIC
1700 public override SLE.Expression MakeExpression (BuilderContext ctx)
1702 return SLE.Expression.Default (type.GetMetaInfo ());
1706 protected override void CloneTo (CloneContext clonectx, Expression t)
1708 DefaultValueExpression target = (DefaultValueExpression) t;
1710 target.expr = expr.Clone (clonectx);
1715 /// Binary operators
1717 public class Binary : Expression, IDynamicBinder
1719 protected class PredefinedOperator {
1720 protected readonly TypeSpec left;
1721 protected readonly TypeSpec right;
1722 public readonly Operator OperatorsMask;
1723 public TypeSpec ReturnType;
1725 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1726 : this (ltype, rtype, op_mask, ltype)
1730 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1731 : this (type, type, op_mask, return_type)
1735 public PredefinedOperator (TypeSpec type, Operator op_mask)
1736 : this (type, type, op_mask, type)
1740 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1742 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1743 throw new InternalErrorException ("Only masked values can be used");
1747 this.OperatorsMask = op_mask;
1748 this.ReturnType = return_type;
1751 public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1753 b.type = ReturnType;
1755 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1756 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1759 // A user operators does not support multiple user conversions, but decimal type
1760 // is considered to be predefined type therefore we apply predefined operators rules
1761 // and then look for decimal user-operator implementation
1763 if (left == TypeManager.decimal_type)
1764 return b.ResolveUserOperator (ec, b.left, b.right);
1766 var c = b.right as Constant;
1768 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1769 return ReducedExpression.Create (b.left, b).Resolve (ec);
1770 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
1771 return ReducedExpression.Create (b.left, b).Resolve (ec);
1775 c = b.left as Constant;
1777 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1778 return ReducedExpression.Create (b.right, b).Resolve (ec);
1779 if (b.oper == Operator.Multiply && c.IsOneInteger)
1780 return ReducedExpression.Create (b.right, b).Resolve (ec);
1787 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
1790 // We are dealing with primitive types only
1792 return left == ltype && ltype == rtype;
1795 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1798 if (left == lexpr.Type && right == rexpr.Type)
1801 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1802 Convert.ImplicitConversionExists (ec, rexpr, right);
1805 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1808 if (left != null && best_operator.left != null) {
1809 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left, left);
1813 // When second argument is same as the first one, the result is same
1815 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1816 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right, right);
1819 if (result == 0 || result > 2)
1822 return result == 1 ? best_operator : this;
1826 class PredefinedStringOperator : PredefinedOperator {
1827 public PredefinedStringOperator (TypeSpec type, Operator op_mask)
1828 : base (type, op_mask, type)
1830 ReturnType = TypeManager.string_type;
1833 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1834 : base (ltype, rtype, op_mask)
1836 ReturnType = TypeManager.string_type;
1839 public override Expression ConvertResult (ResolveContext ec, Binary b)
1842 // Use original expression for nullable arguments
1844 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1846 b.left = unwrap.Original;
1848 unwrap = b.right as Nullable.Unwrap;
1850 b.right = unwrap.Original;
1852 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1853 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1856 // Start a new concat expression using converted expression
1858 return StringConcat.Create (ec, b.left, b.right, b.loc);
1862 class PredefinedShiftOperator : PredefinedOperator {
1863 public PredefinedShiftOperator (TypeSpec ltype, Operator op_mask) :
1864 base (ltype, TypeManager.int32_type, op_mask)
1868 public override Expression ConvertResult (ResolveContext ec, Binary b)
1870 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1872 Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, TypeManager.int32_type, b.right.Location);
1874 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1877 // b = b.left >> b.right & (0x1f|0x3f)
1879 b.right = new Binary (Operator.BitwiseAnd,
1880 b.right, new IntConstant (right_mask, b.right.Location), b.loc).Resolve (ec);
1883 // Expression tree representation does not use & mask
1885 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1886 b.type = ReturnType;
1889 // Optimize shift by 0
1891 var c = b.right as Constant;
1892 if (c != null && c.IsDefaultValue)
1893 return ReducedExpression.Create (b.left, b).Resolve (ec);
1899 class PredefinedEqualityOperator : PredefinedOperator
1901 MethodSpec equal_method, inequal_method;
1903 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
1904 : base (arg, arg, Operator.EqualityMask, retType)
1908 public override Expression ConvertResult (ResolveContext ec, Binary b)
1910 b.type = ReturnType;
1912 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1913 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1915 Arguments args = new Arguments (2);
1916 args.Add (new Argument (b.left));
1917 args.Add (new Argument (b.right));
1920 if (b.oper == Operator.Equality) {
1921 if (equal_method == null) {
1922 equal_method = TypeManager.GetPredefinedMethod (left,
1923 new MemberFilter (CSharp.Operator.GetMetadataName (CSharp.Operator.OpType.Equality), 0, MemberKind.Operator, null, ReturnType), b.loc);
1926 method = equal_method;
1928 if (inequal_method == null) {
1929 inequal_method = TypeManager.GetPredefinedMethod (left,
1930 new MemberFilter (CSharp.Operator.GetMetadataName (CSharp.Operator.OpType.Inequality), 0, MemberKind.Operator, null, ReturnType), b.loc);
1933 method = inequal_method;
1936 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
1940 class PredefinedPointerOperator : PredefinedOperator
1942 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1943 : base (ltype, rtype, op_mask)
1947 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
1948 : base (ltype, rtype, op_mask, retType)
1952 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1953 : base (type, op_mask, return_type)
1957 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1960 if (!lexpr.Type.IsPointer)
1963 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1967 if (right == null) {
1968 if (!rexpr.Type.IsPointer)
1971 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1978 public override Expression ConvertResult (ResolveContext ec, Binary b)
1981 b.left = EmptyCast.Create (b.left, left);
1982 } else if (right != null) {
1983 b.right = EmptyCast.Create (b.right, right);
1986 TypeSpec r_type = ReturnType;
1987 Expression left_arg, right_arg;
1988 if (r_type == null) {
1991 right_arg = b.right;
1992 r_type = b.left.Type;
1996 r_type = b.right.Type;
2000 right_arg = b.right;
2003 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2008 public enum Operator {
2009 Multiply = 0 | ArithmeticMask,
2010 Division = 1 | ArithmeticMask,
2011 Modulus = 2 | ArithmeticMask,
2012 Addition = 3 | ArithmeticMask | AdditionMask,
2013 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2015 LeftShift = 5 | ShiftMask,
2016 RightShift = 6 | ShiftMask,
2018 LessThan = 7 | ComparisonMask | RelationalMask,
2019 GreaterThan = 8 | ComparisonMask | RelationalMask,
2020 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2021 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2022 Equality = 11 | ComparisonMask | EqualityMask,
2023 Inequality = 12 | ComparisonMask | EqualityMask,
2025 BitwiseAnd = 13 | BitwiseMask,
2026 ExclusiveOr = 14 | BitwiseMask,
2027 BitwiseOr = 15 | BitwiseMask,
2029 LogicalAnd = 16 | LogicalMask,
2030 LogicalOr = 17 | LogicalMask,
2035 ValuesOnlyMask = ArithmeticMask - 1,
2036 ArithmeticMask = 1 << 5,
2038 ComparisonMask = 1 << 7,
2039 EqualityMask = 1 << 8,
2040 BitwiseMask = 1 << 9,
2041 LogicalMask = 1 << 10,
2042 AdditionMask = 1 << 11,
2043 SubtractionMask = 1 << 12,
2044 RelationalMask = 1 << 13
2047 protected enum State
2051 LeftNullLifted = 1 << 2,
2052 RightNullLifted = 1 << 3
2055 readonly Operator oper;
2056 protected Expression left, right;
2057 protected State state;
2058 Expression enum_conversion;
2060 static PredefinedOperator[] standard_operators;
2061 static PredefinedOperator[] equality_operators;
2062 static PredefinedOperator[] pointer_operators;
2064 public Binary (Operator oper, Expression left, Expression right, bool isCompound, Location loc)
2065 : this (oper, left, right, loc)
2068 state |= State.Compound;
2071 public Binary (Operator oper, Expression left, Expression right, Location loc)
2081 public bool IsCompound {
2083 return (state & State.Compound) != 0;
2087 public Operator Oper {
2096 /// Returns a stringified representation of the Operator
2098 string OperName (Operator oper)
2102 case Operator.Multiply:
2105 case Operator.Division:
2108 case Operator.Modulus:
2111 case Operator.Addition:
2114 case Operator.Subtraction:
2117 case Operator.LeftShift:
2120 case Operator.RightShift:
2123 case Operator.LessThan:
2126 case Operator.GreaterThan:
2129 case Operator.LessThanOrEqual:
2132 case Operator.GreaterThanOrEqual:
2135 case Operator.Equality:
2138 case Operator.Inequality:
2141 case Operator.BitwiseAnd:
2144 case Operator.BitwiseOr:
2147 case Operator.ExclusiveOr:
2150 case Operator.LogicalOr:
2153 case Operator.LogicalAnd:
2157 s = oper.ToString ();
2167 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2169 new Binary (oper, left, right, loc).Error_OperatorCannotBeApplied (ec, left, right);
2172 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2175 l = TypeManager.CSharpName (left.Type);
2176 r = TypeManager.CSharpName (right.Type);
2178 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2182 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2184 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2188 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2190 string GetOperatorExpressionTypeName ()
2193 case Operator.Addition:
2194 return IsCompound ? "AddAssign" : "Add";
2195 case Operator.BitwiseAnd:
2196 return IsCompound ? "AndAssign" : "And";
2197 case Operator.BitwiseOr:
2198 return IsCompound ? "OrAssign" : "Or";
2199 case Operator.Division:
2200 return IsCompound ? "DivideAssign" : "Divide";
2201 case Operator.ExclusiveOr:
2202 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2203 case Operator.Equality:
2205 case Operator.GreaterThan:
2206 return "GreaterThan";
2207 case Operator.GreaterThanOrEqual:
2208 return "GreaterThanOrEqual";
2209 case Operator.Inequality:
2211 case Operator.LeftShift:
2212 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2213 case Operator.LessThan:
2215 case Operator.LessThanOrEqual:
2216 return "LessThanOrEqual";
2217 case Operator.LogicalAnd:
2219 case Operator.LogicalOr:
2221 case Operator.Modulus:
2222 return IsCompound ? "ModuloAssign" : "Modulo";
2223 case Operator.Multiply:
2224 return IsCompound ? "MultiplyAssign" : "Multiply";
2225 case Operator.RightShift:
2226 return IsCompound ? "RightShiftAssign" : "RightShift";
2227 case Operator.Subtraction:
2228 return IsCompound ? "SubtractAssign" : "Subtract";
2230 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2234 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2237 case Operator.Addition:
2238 return CSharp.Operator.OpType.Addition;
2239 case Operator.BitwiseAnd:
2240 case Operator.LogicalAnd:
2241 return CSharp.Operator.OpType.BitwiseAnd;
2242 case Operator.BitwiseOr:
2243 case Operator.LogicalOr:
2244 return CSharp.Operator.OpType.BitwiseOr;
2245 case Operator.Division:
2246 return CSharp.Operator.OpType.Division;
2247 case Operator.Equality:
2248 return CSharp.Operator.OpType.Equality;
2249 case Operator.ExclusiveOr:
2250 return CSharp.Operator.OpType.ExclusiveOr;
2251 case Operator.GreaterThan:
2252 return CSharp.Operator.OpType.GreaterThan;
2253 case Operator.GreaterThanOrEqual:
2254 return CSharp.Operator.OpType.GreaterThanOrEqual;
2255 case Operator.Inequality:
2256 return CSharp.Operator.OpType.Inequality;
2257 case Operator.LeftShift:
2258 return CSharp.Operator.OpType.LeftShift;
2259 case Operator.LessThan:
2260 return CSharp.Operator.OpType.LessThan;
2261 case Operator.LessThanOrEqual:
2262 return CSharp.Operator.OpType.LessThanOrEqual;
2263 case Operator.Modulus:
2264 return CSharp.Operator.OpType.Modulus;
2265 case Operator.Multiply:
2266 return CSharp.Operator.OpType.Multiply;
2267 case Operator.RightShift:
2268 return CSharp.Operator.OpType.RightShift;
2269 case Operator.Subtraction:
2270 return CSharp.Operator.OpType.Subtraction;
2272 throw new InternalErrorException (op.ToString ());
2276 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l)
2281 case Operator.Multiply:
2282 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2283 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2284 opcode = OpCodes.Mul_Ovf;
2285 else if (!IsFloat (l))
2286 opcode = OpCodes.Mul_Ovf_Un;
2288 opcode = OpCodes.Mul;
2290 opcode = OpCodes.Mul;
2294 case Operator.Division:
2296 opcode = OpCodes.Div_Un;
2298 opcode = OpCodes.Div;
2301 case Operator.Modulus:
2303 opcode = OpCodes.Rem_Un;
2305 opcode = OpCodes.Rem;
2308 case Operator.Addition:
2309 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2310 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2311 opcode = OpCodes.Add_Ovf;
2312 else if (!IsFloat (l))
2313 opcode = OpCodes.Add_Ovf_Un;
2315 opcode = OpCodes.Add;
2317 opcode = OpCodes.Add;
2320 case Operator.Subtraction:
2321 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2322 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2323 opcode = OpCodes.Sub_Ovf;
2324 else if (!IsFloat (l))
2325 opcode = OpCodes.Sub_Ovf_Un;
2327 opcode = OpCodes.Sub;
2329 opcode = OpCodes.Sub;
2332 case Operator.RightShift:
2334 opcode = OpCodes.Shr_Un;
2336 opcode = OpCodes.Shr;
2339 case Operator.LeftShift:
2340 opcode = OpCodes.Shl;
2343 case Operator.Equality:
2344 opcode = OpCodes.Ceq;
2347 case Operator.Inequality:
2348 ec.Emit (OpCodes.Ceq);
2349 ec.Emit (OpCodes.Ldc_I4_0);
2351 opcode = OpCodes.Ceq;
2354 case Operator.LessThan:
2356 opcode = OpCodes.Clt_Un;
2358 opcode = OpCodes.Clt;
2361 case Operator.GreaterThan:
2363 opcode = OpCodes.Cgt_Un;
2365 opcode = OpCodes.Cgt;
2368 case Operator.LessThanOrEqual:
2369 if (IsUnsigned (l) || IsFloat (l))
2370 ec.Emit (OpCodes.Cgt_Un);
2372 ec.Emit (OpCodes.Cgt);
2373 ec.Emit (OpCodes.Ldc_I4_0);
2375 opcode = OpCodes.Ceq;
2378 case Operator.GreaterThanOrEqual:
2379 if (IsUnsigned (l) || IsFloat (l))
2380 ec.Emit (OpCodes.Clt_Un);
2382 ec.Emit (OpCodes.Clt);
2384 ec.Emit (OpCodes.Ldc_I4_0);
2386 opcode = OpCodes.Ceq;
2389 case Operator.BitwiseOr:
2390 opcode = OpCodes.Or;
2393 case Operator.BitwiseAnd:
2394 opcode = OpCodes.And;
2397 case Operator.ExclusiveOr:
2398 opcode = OpCodes.Xor;
2402 throw new InternalErrorException (oper.ToString ());
2408 static bool IsUnsigned (TypeSpec t)
2413 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2414 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2417 static bool IsFloat (TypeSpec t)
2419 return t == TypeManager.float_type || t == TypeManager.double_type;
2422 public static void Reset ()
2424 equality_operators = pointer_operators = standard_operators = null;
2427 Expression ResolveOperator (ResolveContext ec)
2429 TypeSpec l = left.Type;
2430 TypeSpec r = right.Type;
2432 bool primitives_only = false;
2434 if (standard_operators == null)
2435 CreateStandardOperatorsTable ();
2438 // Handles predefined primitive types
2440 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2441 if ((oper & Operator.ShiftMask) == 0) {
2442 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2445 primitives_only = true;
2449 if (l.IsPointer || r.IsPointer)
2450 return ResolveOperatorPointer (ec, l, r);
2453 bool lenum = l.IsEnum;
2454 bool renum = r.IsEnum;
2455 if (lenum || renum) {
2456 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2463 if ((oper == Operator.Addition || oper == Operator.Subtraction) && (l.IsDelegate || r.IsDelegate)) {
2465 expr = ResolveOperatorDelegate (ec, l, r);
2467 // TODO: Can this be ambiguous
2473 expr = ResolveUserOperator (ec, left, right);
2477 // Predefined reference types equality
2478 if ((oper & Operator.EqualityMask) != 0) {
2479 expr = ResolveOperatorEquality (ec, l, r);
2485 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2488 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2489 // if 'left' is not an enumeration constant, create one from the type of 'right'
2490 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2493 case Operator.BitwiseOr:
2494 case Operator.BitwiseAnd:
2495 case Operator.ExclusiveOr:
2496 case Operator.Equality:
2497 case Operator.Inequality:
2498 case Operator.LessThan:
2499 case Operator.LessThanOrEqual:
2500 case Operator.GreaterThan:
2501 case Operator.GreaterThanOrEqual:
2502 if (TypeManager.IsEnumType (left.Type))
2505 if (left.IsZeroInteger)
2506 return left.TryReduce (ec, right.Type, loc);
2510 case Operator.Addition:
2511 case Operator.Subtraction:
2514 case Operator.Multiply:
2515 case Operator.Division:
2516 case Operator.Modulus:
2517 case Operator.LeftShift:
2518 case Operator.RightShift:
2519 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2523 Error_OperatorCannotBeApplied (ec, this.left, this.right);
2528 // The `|' operator used on types which were extended is dangerous
2530 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2532 OpcodeCast lcast = left as OpcodeCast;
2533 if (lcast != null) {
2534 if (IsUnsigned (lcast.UnderlyingType))
2538 OpcodeCast rcast = right as OpcodeCast;
2539 if (rcast != null) {
2540 if (IsUnsigned (rcast.UnderlyingType))
2544 if (lcast == null && rcast == null)
2547 // FIXME: consider constants
2549 ec.Report.Warning (675, 3, loc,
2550 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2551 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2554 static void CreatePointerOperatorsTable ()
2556 var temp = new List<PredefinedPointerOperator> ();
2559 // Pointer arithmetic:
2561 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2562 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2563 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2564 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2566 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2567 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2568 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2569 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2572 // T* operator + (int y, T* x);
2573 // T* operator + (uint y, T *x);
2574 // T* operator + (long y, T *x);
2575 // T* operator + (ulong y, T *x);
2577 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2578 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2579 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2580 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2583 // long operator - (T* x, T *y)
2585 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2587 pointer_operators = temp.ToArray ();
2590 static void CreateStandardOperatorsTable ()
2592 var temp = new List<PredefinedOperator> ();
2593 TypeSpec bool_type = TypeManager.bool_type;
2595 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2596 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2597 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2598 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2599 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2600 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2601 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2603 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2604 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2605 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2606 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2607 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2608 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2609 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2611 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2612 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2613 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2615 temp.Add (new PredefinedOperator (bool_type,
2616 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2618 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2619 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2620 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2621 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2623 standard_operators = temp.ToArray ();
2625 var equality = new List<PredefinedOperator> () {
2626 new PredefinedEqualityOperator (TypeManager.string_type, bool_type),
2627 new PredefinedEqualityOperator (TypeManager.delegate_type, bool_type),
2628 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type)
2631 equality_operators = equality.ToArray ();
2635 // Rules used during binary numeric promotion
2637 static bool DoNumericPromotion (ResolveContext rc, ref Expression prim_expr, ref Expression second_expr, TypeSpec type)
2642 Constant c = prim_expr as Constant;
2644 temp = c.ConvertImplicitly (rc, type);
2651 if (type == TypeManager.uint32_type) {
2652 etype = prim_expr.Type;
2653 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2654 type = TypeManager.int64_type;
2656 if (type != second_expr.Type) {
2657 c = second_expr as Constant;
2659 temp = c.ConvertImplicitly (rc, type);
2661 temp = Convert.ImplicitNumericConversion (second_expr, type);
2667 } else if (type == TypeManager.uint64_type) {
2669 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2671 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2672 type == TypeManager.short_type || type == TypeManager.sbyte_type)
2676 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2685 // 7.2.6.2 Binary numeric promotions
2687 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2689 TypeSpec ltype = left.Type;
2690 TypeSpec rtype = right.Type;
2693 foreach (TypeSpec t in ConstantFold.BinaryPromotionsTypes) {
2695 return t == rtype || DoNumericPromotion (ec, ref right, ref left, t);
2698 return t == ltype || DoNumericPromotion (ec, ref left, ref right, t);
2701 TypeSpec int32 = TypeManager.int32_type;
2702 if (ltype != int32) {
2703 Constant c = left as Constant;
2705 temp = c.ConvertImplicitly (ec, int32);
2707 temp = Convert.ImplicitNumericConversion (left, int32);
2714 if (rtype != int32) {
2715 Constant c = right as Constant;
2717 temp = c.ConvertImplicitly (ec, int32);
2719 temp = Convert.ImplicitNumericConversion (right, int32);
2729 protected override Expression DoResolve (ResolveContext ec)
2734 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2735 left = ((ParenthesizedExpression) left).Expr;
2736 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2740 if (left.eclass == ExprClass.Type) {
2741 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2745 left = left.Resolve (ec);
2750 Constant lc = left as Constant;
2752 if (lc != null && lc.Type == TypeManager.bool_type &&
2753 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2754 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2756 // FIXME: resolve right expression as unreachable
2757 // right.Resolve (ec);
2759 ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2763 right = right.Resolve (ec);
2767 eclass = ExprClass.Value;
2768 Constant rc = right as Constant;
2770 // The conversion rules are ignored in enum context but why
2771 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2772 lc = EnumLiftUp (ec, lc, rc, loc);
2774 rc = EnumLiftUp (ec, rc, lc, loc);
2777 if (rc != null && lc != null) {
2778 int prev_e = ec.Report.Errors;
2779 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
2783 if (e != null || ec.Report.Errors != prev_e)
2787 // Comparison warnings
2788 if ((oper & Operator.ComparisonMask) != 0) {
2789 if (left.Equals (right)) {
2790 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2792 CheckUselessComparison (ec, lc, right.Type);
2793 CheckUselessComparison (ec, rc, left.Type);
2796 if (left.Type == InternalType.Dynamic || right.Type == InternalType.Dynamic) {
2798 var rt = right.Type;
2799 if (lt == TypeManager.void_type || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
2800 rt == TypeManager.void_type || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
2801 Error_OperatorCannotBeApplied (ec, left, right);
2808 // Special handling for logical boolean operators which require rhs not to be
2809 // evaluated based on lhs value
2811 if ((oper & Operator.LogicalMask) != 0) {
2812 Expression cond_left, cond_right, expr;
2814 args = new Arguments (2);
2816 if (lt == InternalType.Dynamic) {
2817 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, ec.CurrentBlock, loc);
2819 var cond_args = new Arguments (1);
2820 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left).Resolve (ec)));
2823 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
2824 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
2826 left = temp.CreateReferenceExpression (ec, loc);
2827 if (oper == Operator.LogicalAnd) {
2828 expr = DynamicUnaryConversion.CreateIsFalse (cond_args, loc);
2831 expr = DynamicUnaryConversion.CreateIsTrue (cond_args, loc);
2835 args.Add (new Argument (left));
2836 args.Add (new Argument (right));
2837 cond_right = new DynamicExpressionStatement (this, args, loc);
2839 LocalVariable temp = LocalVariable.CreateCompilerGenerated (TypeManager.bool_type, ec.CurrentBlock, loc);
2841 args.Add (new Argument (temp.CreateReferenceExpression (ec, loc).Resolve (ec)));
2842 args.Add (new Argument (right));
2843 right = new DynamicExpressionStatement (this, args, loc);
2846 // bool && dynamic => (temp = left) ? temp && right : temp;
2847 // bool || dynamic => (temp = left) ? temp : temp || right;
2849 if (oper == Operator.LogicalAnd) {
2851 cond_right = temp.CreateReferenceExpression (ec, loc);
2853 cond_left = temp.CreateReferenceExpression (ec, loc);
2857 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left));
2860 return new Conditional (expr, cond_left, cond_right, loc).Resolve (ec);
2863 args = new Arguments (2);
2864 args.Add (new Argument (left));
2865 args.Add (new Argument (right));
2866 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
2869 if (ec.Module.Compiler.Settings.Version >= LanguageVersion.ISO_2 &&
2870 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2871 (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
2872 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2873 (TypeManager.IsValueType (right.Type) && left is NullLiteral))) {
2874 var lifted = new Nullable.LiftedBinaryOperator (oper, left, right, loc);
2875 lifted.state = state;
2876 return lifted.Resolve (ec);
2879 return DoResolveCore (ec, left, right);
2882 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
2884 Expression expr = ResolveOperator (ec);
2886 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
2888 if (left == null || right == null)
2889 throw new InternalErrorException ("Invalid conversion");
2891 if (oper == Operator.BitwiseOr)
2892 CheckBitwiseOrOnSignExtended (ec);
2897 public override SLE.Expression MakeExpression (BuilderContext ctx)
2899 var le = left.MakeExpression (ctx);
2900 var re = right.MakeExpression (ctx);
2901 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
2904 case Operator.Addition:
2905 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
2906 case Operator.BitwiseAnd:
2907 return SLE.Expression.And (le, re);
2908 case Operator.BitwiseOr:
2909 return SLE.Expression.Or (le, re);
2910 case Operator.Division:
2911 return SLE.Expression.Divide (le, re);
2912 case Operator.Equality:
2913 return SLE.Expression.Equal (le, re);
2914 case Operator.ExclusiveOr:
2915 return SLE.Expression.ExclusiveOr (le, re);
2916 case Operator.GreaterThan:
2917 return SLE.Expression.GreaterThan (le, re);
2918 case Operator.GreaterThanOrEqual:
2919 return SLE.Expression.GreaterThanOrEqual (le, re);
2920 case Operator.Inequality:
2921 return SLE.Expression.NotEqual (le, re);
2922 case Operator.LeftShift:
2923 return SLE.Expression.LeftShift (le, re);
2924 case Operator.LessThan:
2925 return SLE.Expression.LessThan (le, re);
2926 case Operator.LessThanOrEqual:
2927 return SLE.Expression.LessThanOrEqual (le, re);
2928 case Operator.LogicalAnd:
2929 return SLE.Expression.AndAlso (le, re);
2930 case Operator.LogicalOr:
2931 return SLE.Expression.OrElse (le, re);
2932 case Operator.Modulus:
2933 return SLE.Expression.Modulo (le, re);
2934 case Operator.Multiply:
2935 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
2936 case Operator.RightShift:
2937 return SLE.Expression.RightShift (le, re);
2938 case Operator.Subtraction:
2939 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
2941 throw new NotImplementedException (oper.ToString ());
2946 // D operator + (D x, D y)
2947 // D operator - (D x, D y)
2949 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
2951 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
2953 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.Null) {
2954 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2959 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.Null)) {
2960 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2971 Arguments args = new Arguments (2);
2972 args.Add (new Argument (left));
2973 args.Add (new Argument (right));
2975 if (oper == Operator.Addition) {
2976 if (TypeManager.delegate_combine_delegate_delegate == null) {
2977 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2978 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2981 method = TypeManager.delegate_combine_delegate_delegate;
2982 } else if (oper == Operator.Subtraction) {
2983 if (TypeManager.delegate_remove_delegate_delegate == null) {
2984 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2985 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2988 method = TypeManager.delegate_remove_delegate_delegate;
2990 return new EmptyExpression (TypeManager.decimal_type);
2993 MethodGroupExpr mg = MethodGroupExpr.CreatePredefined (method, TypeManager.delegate_type, loc);
2994 Expression expr = new UserOperatorCall (mg.BestCandidate, args, CreateExpressionTree, loc);
2995 return new ClassCast (expr, l);
2999 // Enumeration operators
3001 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3004 // bool operator == (E x, E y);
3005 // bool operator != (E x, E y);
3006 // bool operator < (E x, E y);
3007 // bool operator > (E x, E y);
3008 // bool operator <= (E x, E y);
3009 // bool operator >= (E x, E y);
3011 // E operator & (E x, E y);
3012 // E operator | (E x, E y);
3013 // E operator ^ (E x, E y);
3015 // U operator - (E e, E f)
3016 // E operator - (E e, U x)
3017 // E operator - (U x, E e) // LAMESPEC: Not covered by the specification
3019 // E operator + (E e, U x)
3020 // E operator + (U x, E e)
3022 Expression ltemp = left;
3023 Expression rtemp = right;
3024 TypeSpec underlying_type;
3025 TypeSpec underlying_type_result;
3030 // LAMESPEC: There is never ambiguous conversion between enum operators
3031 // the one which contains more enum parameters always wins even if there
3032 // is an implicit conversion involved
3034 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3036 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3037 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
3044 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3045 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
3055 if ((oper & Operator.BitwiseMask) != 0) {
3057 underlying_type_result = underlying_type;
3060 underlying_type_result = null;
3062 } else if (oper == Operator.Subtraction) {
3064 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3065 if (ltype != rtype) {
3066 expr = Convert.ImplicitConversion (ec, left, rtype, left.Location);
3068 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3074 res_type = underlying_type;
3079 res_type = underlying_type;
3082 underlying_type_result = underlying_type;
3084 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3085 expr = Convert.ImplicitConversion (ec, right, ltype, right.Location);
3086 if (expr == null || expr is EnumConstant) {
3087 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3093 res_type = underlying_type;
3097 underlying_type_result = underlying_type;
3101 } else if (oper == Operator.Addition) {
3103 underlying_type = EnumSpec.GetUnderlyingType (ltype);
3106 if (rtype != underlying_type && (state & (State.RightNullLifted | State.LeftNullLifted)) == 0) {
3107 expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3114 underlying_type = EnumSpec.GetUnderlyingType (rtype);
3116 if (ltype != underlying_type) {
3117 expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3125 underlying_type_result = underlying_type;
3130 // Unwrap the constant correctly, so DoBinaryOperatorPromotion can do the magic
3131 // with constants and expressions
3132 if (left.Type != underlying_type) {
3133 if (left is Constant)
3134 left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
3136 left = EmptyCast.Create (left, underlying_type);
3139 if (right.Type != underlying_type) {
3140 if (right is Constant)
3141 right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
3143 right = EmptyCast.Create (right, underlying_type);
3147 // C# specification uses explicit cast syntax which means binary promotion
3148 // should happen, however it seems that csc does not do that
3150 if (!DoBinaryOperatorPromotion (ec)) {
3156 if (underlying_type_result != null && left.Type != underlying_type_result) {
3157 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (left.Type), underlying_type_result);
3160 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
3172 // If the return type of the selected operator is implicitly convertible to the type of x
3174 if (Convert.ImplicitConversionExists (ec, expr, ltype))
3178 // Otherwise, if the selected operator is a predefined operator, if the return type of the
3179 // selected operator is explicitly convertible to the type of x, and if y is implicitly
3180 // convertible to the type of x or the operator is a shift operator, then the operation
3181 // is evaluated as x = (T)(x op y), where T is the type of x
3183 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
3187 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
3194 // 7.9.6 Reference type equality operators
3196 Expression ResolveOperatorEquality (ResolveContext ec, TypeSpec l, TypeSpec r)
3199 type = TypeManager.bool_type;
3202 // a, Both operands are reference-type values or the value null
3203 // b, One operand is a value of type T where T is a type-parameter and
3204 // the other operand is the value null. Furthermore T does not have the
3205 // value type constraint
3207 // LAMESPEC: Very confusing details in the specification, basically any
3208 // reference like type-parameter is allowed
3210 var tparam_l = l as TypeParameterSpec;
3211 var tparam_r = r as TypeParameterSpec;
3212 if (tparam_l != null) {
3213 if (right is NullLiteral && !tparam_l.HasSpecialStruct) {
3214 left = new BoxedCast (left, TypeManager.object_type);
3218 if (!tparam_l.IsReferenceType)
3221 l = tparam_l.GetEffectiveBase ();
3222 left = new BoxedCast (left, l);
3223 } else if (left is NullLiteral && tparam_r == null) {
3224 if (!TypeManager.IsReferenceType (r) || r.Kind == MemberKind.InternalCompilerType)
3230 if (tparam_r != null) {
3231 if (left is NullLiteral && !tparam_r.HasSpecialStruct) {
3232 right = new BoxedCast (right, TypeManager.object_type);
3236 if (!tparam_r.IsReferenceType)
3239 r = tparam_r.GetEffectiveBase ();
3240 right = new BoxedCast (right, r);
3241 } else if (right is NullLiteral) {
3242 if (!TypeManager.IsReferenceType (l) || l.Kind == MemberKind.InternalCompilerType)
3249 // LAMESPEC: method groups can be compared when they convert to other side delegate
3252 if (right.eclass == ExprClass.MethodGroup) {
3253 result = Convert.ImplicitConversion (ec, right, l, loc);
3259 } else if (r.IsDelegate && l != r) {
3262 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3263 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3272 // bool operator != (string a, string b)
3273 // bool operator == (string a, string b)
3275 // bool operator != (Delegate a, Delegate b)
3276 // bool operator == (Delegate a, Delegate b)
3278 // bool operator != (bool a, bool b)
3279 // bool operator == (bool a, bool b)
3281 // LAMESPEC: Reference equality comparison can apply to value types when
3282 // they implement an implicit conversion to any of types above.
3284 if (r != TypeManager.object_type && l != TypeManager.object_type) {
3285 result = ResolveOperatorPredefined (ec, equality_operators, false, null);
3291 // bool operator != (object a, object b)
3292 // bool operator == (object a, object b)
3294 // An explicit reference conversion exists from the
3295 // type of either operand to the type of the other operand.
3298 // Optimize common path
3300 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3303 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3304 !Convert.ExplicitReferenceConversionExists (r, l))
3307 // Reject allowed explicit conversions like int->object
3308 if (!TypeManager.IsReferenceType (l) || !TypeManager.IsReferenceType (r))
3311 if (l == TypeManager.string_type || l == TypeManager.delegate_type || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3312 ec.Report.Warning (253, 2, loc,
3313 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3314 l.GetSignatureForError ());
3316 if (r == TypeManager.string_type || r == TypeManager.delegate_type || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3317 ec.Report.Warning (252, 2, loc,
3318 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3319 r.GetSignatureForError ());
3325 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3328 // bool operator == (void* x, void* y);
3329 // bool operator != (void* x, void* y);
3330 // bool operator < (void* x, void* y);
3331 // bool operator > (void* x, void* y);
3332 // bool operator <= (void* x, void* y);
3333 // bool operator >= (void* x, void* y);
3335 if ((oper & Operator.ComparisonMask) != 0) {
3338 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3345 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3351 type = TypeManager.bool_type;
3355 if (pointer_operators == null)
3356 CreatePointerOperatorsTable ();
3358 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
3362 // Build-in operators method overloading
3364 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, TypeSpec enum_type)
3366 PredefinedOperator best_operator = null;
3367 TypeSpec l = left.Type;
3368 TypeSpec r = right.Type;
3369 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3371 foreach (PredefinedOperator po in operators) {
3372 if ((po.OperatorsMask & oper_mask) == 0)
3375 if (primitives_only) {
3376 if (!po.IsPrimitiveApplicable (l, r))
3379 if (!po.IsApplicable (ec, left, right))
3383 if (best_operator == null) {
3385 if (primitives_only)
3391 best_operator = po.ResolveBetterOperator (ec, best_operator);
3393 if (best_operator == null) {
3394 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3395 OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
3402 if (best_operator == null)
3405 Expression expr = best_operator.ConvertResult (ec, this);
3408 // Optimize &/&& constant expressions with 0 value
3410 if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
3411 Constant rc = right as Constant;
3412 Constant lc = left as Constant;
3413 if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
3415 // The result is a constant with side-effect
3417 Constant side_effect = rc == null ?
3418 new SideEffectConstant (lc, right, loc) :
3419 new SideEffectConstant (rc, left, loc);
3421 return ReducedExpression.Create (side_effect.Resolve (ec), expr);
3425 if (enum_type == null)
3429 // HACK: required by enum_conversion
3431 expr.Type = enum_type;
3432 return EmptyCast.Create (expr, enum_type);
3436 // Performs user-operator overloading
3438 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression left, Expression right)
3440 var op = ConvertBinaryToUserOperator (oper);
3442 if (TypeManager.IsNullableType (l))
3443 l = Nullable.NullableInfo.GetUnderlyingType (l);
3445 if (TypeManager.IsNullableType (r))
3446 r = Nullable.NullableInfo.GetUnderlyingType (r);
3448 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
3449 IList<MemberSpec> right_operators = null;
3452 right_operators = MemberCache.GetUserOperator (r, op, false);
3453 if (right_operators == null && left_operators == null)
3455 } else if (left_operators == null) {
3459 Arguments args = new Arguments (2);
3460 Argument larg = new Argument (left);
3462 Argument rarg = new Argument (right);
3466 // User-defined operator implementations always take precedence
3467 // over predefined operator implementations
3469 if (left_operators != null && right_operators != null) {
3470 left_operators = CombineUserOperators (left_operators, right_operators);
3471 } else if (right_operators != null) {
3472 left_operators = right_operators;
3475 var res = new OverloadResolver (left_operators, OverloadResolver.Restrictions.ProbingOnly |
3476 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded, loc);
3478 var oper_method = res.ResolveOperator (ec, ref args);
3479 if (oper_method == null)
3482 var llifted = (state & State.LeftNullLifted) != 0;
3483 var rlifted = (state & State.RightNullLifted) != 0;
3484 if ((Oper & Operator.EqualityMask) != 0) {
3485 var parameters = oper_method.Parameters;
3486 // LAMESPEC: No idea why this is not allowed
3487 if ((left is Nullable.Unwrap || right is Nullable.Unwrap) && parameters.Types [0] != parameters.Types [1])
3490 // Binary operation was lifted but we have found a user operator
3491 // which requires value-type argument, we downgrade ourself back to
3493 // LAMESPEC: The user operator is not called (it cannot be we are passing null to struct)
3494 // but compilation succeeds
3495 if ((llifted && !parameters.Types[0].IsStruct) || (rlifted && !parameters.Types[1].IsStruct)) {
3496 state &= ~(State.LeftNullLifted | State.RightNullLifted);
3500 Expression oper_expr;
3502 // TODO: CreateExpressionTree is allocated every time
3503 if ((oper & Operator.LogicalMask) != 0) {
3504 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
3505 oper == Operator.LogicalAnd, loc).Resolve (ec);
3507 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
3511 this.left = larg.Expr;
3514 this.right = rarg.Expr;
3520 // Merge two sets of user operators into one, they are mostly distinguish
3521 // expect when they share base type and it contains an operator
3523 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
3525 var combined = new List<MemberSpec> (left.Count + right.Count);
3526 combined.AddRange (left);
3527 foreach (var r in right) {
3529 foreach (var l in left) {
3530 if (l.DeclaringType == r.DeclaringType) {
3543 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3548 private void CheckUselessComparison (ResolveContext ec, Constant c, TypeSpec type)
3550 if (c == null || !IsTypeIntegral (type)
3551 || c is StringConstant
3552 || c is BoolConstant
3553 || c is FloatConstant
3554 || c is DoubleConstant
3555 || c is DecimalConstant
3561 if (c is ULongConstant) {
3562 ulong uvalue = ((ULongConstant) c).Value;
3563 if (uvalue > long.MaxValue) {
3564 if (type == TypeManager.byte_type ||
3565 type == TypeManager.sbyte_type ||
3566 type == TypeManager.short_type ||
3567 type == TypeManager.ushort_type ||
3568 type == TypeManager.int32_type ||
3569 type == TypeManager.uint32_type ||
3570 type == TypeManager.int64_type ||
3571 type == TypeManager.char_type)
3572 WarnUselessComparison (ec, type);
3575 value = (long) uvalue;
3577 else if (c is ByteConstant)
3578 value = ((ByteConstant) c).Value;
3579 else if (c is SByteConstant)
3580 value = ((SByteConstant) c).Value;
3581 else if (c is ShortConstant)
3582 value = ((ShortConstant) c).Value;
3583 else if (c is UShortConstant)
3584 value = ((UShortConstant) c).Value;
3585 else if (c is IntConstant)
3586 value = ((IntConstant) c).Value;
3587 else if (c is UIntConstant)
3588 value = ((UIntConstant) c).Value;
3589 else if (c is LongConstant)
3590 value = ((LongConstant) c).Value;
3591 else if (c is CharConstant)
3592 value = ((CharConstant)c).Value;
3597 if (IsValueOutOfRange (value, type))
3598 WarnUselessComparison (ec, type);
3601 static bool IsValueOutOfRange (long value, TypeSpec type)
3603 if (IsTypeUnsigned (type) && value < 0)
3605 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3606 type == TypeManager.byte_type && value >= 0x100 ||
3607 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3608 type == TypeManager.ushort_type && value >= 0x10000 ||
3609 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3610 type == TypeManager.uint32_type && value >= 0x100000000;
3613 private static bool IsTypeIntegral (TypeSpec type)
3615 return type == TypeManager.uint64_type ||
3616 type == TypeManager.int64_type ||
3617 type == TypeManager.uint32_type ||
3618 type == TypeManager.int32_type ||
3619 type == TypeManager.ushort_type ||
3620 type == TypeManager.short_type ||
3621 type == TypeManager.sbyte_type ||
3622 type == TypeManager.byte_type ||
3623 type == TypeManager.char_type;
3626 private static bool IsTypeUnsigned (TypeSpec type)
3628 return type == TypeManager.uint64_type ||
3629 type == TypeManager.uint32_type ||
3630 type == TypeManager.ushort_type ||
3631 type == TypeManager.byte_type ||
3632 type == TypeManager.char_type;
3635 private void WarnUselessComparison (ResolveContext ec, TypeSpec type)
3637 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}'",
3638 TypeManager.CSharpName (type));
3642 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3643 /// context of a conditional bool expression. This function will return
3644 /// false if it is was possible to use EmitBranchable, or true if it was.
3646 /// The expression's code is generated, and we will generate a branch to `target'
3647 /// if the resulting expression value is equal to isTrue
3649 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3652 // This is more complicated than it looks, but its just to avoid
3653 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3654 // but on top of that we want for == and != to use a special path
3655 // if we are comparing against null
3657 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
3658 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3661 // put the constant on the rhs, for simplicity
3663 if (left is Constant) {
3664 Expression swap = right;
3670 // brtrue/brfalse works with native int only
3672 if (((Constant) right).IsZeroInteger && right.Type != TypeManager.int64_type && right.Type != TypeManager.uint64_type) {
3673 left.EmitBranchable (ec, target, my_on_true);
3676 if (right.Type == TypeManager.bool_type) {
3677 // right is a boolean, and it's not 'false' => it is 'true'
3678 left.EmitBranchable (ec, target, !my_on_true);
3682 } else if (oper == Operator.LogicalAnd) {
3685 Label tests_end = ec.DefineLabel ();
3687 left.EmitBranchable (ec, tests_end, false);
3688 right.EmitBranchable (ec, target, true);
3689 ec.MarkLabel (tests_end);
3692 // This optimizes code like this
3693 // if (true && i > 4)
3695 if (!(left is Constant))
3696 left.EmitBranchable (ec, target, false);
3698 if (!(right is Constant))
3699 right.EmitBranchable (ec, target, false);
3704 } else if (oper == Operator.LogicalOr){
3706 left.EmitBranchable (ec, target, true);
3707 right.EmitBranchable (ec, target, true);
3710 Label tests_end = ec.DefineLabel ();
3711 left.EmitBranchable (ec, tests_end, true);
3712 right.EmitBranchable (ec, target, false);
3713 ec.MarkLabel (tests_end);
3718 } else if ((oper & Operator.ComparisonMask) == 0) {
3719 base.EmitBranchable (ec, target, on_true);
3726 TypeSpec t = left.Type;
3727 bool is_float = IsFloat (t);
3728 bool is_unsigned = is_float || IsUnsigned (t);
3731 case Operator.Equality:
3733 ec.Emit (OpCodes.Beq, target);
3735 ec.Emit (OpCodes.Bne_Un, target);
3738 case Operator.Inequality:
3740 ec.Emit (OpCodes.Bne_Un, target);
3742 ec.Emit (OpCodes.Beq, target);
3745 case Operator.LessThan:
3747 if (is_unsigned && !is_float)
3748 ec.Emit (OpCodes.Blt_Un, target);
3750 ec.Emit (OpCodes.Blt, target);
3753 ec.Emit (OpCodes.Bge_Un, target);
3755 ec.Emit (OpCodes.Bge, target);
3758 case Operator.GreaterThan:
3760 if (is_unsigned && !is_float)
3761 ec.Emit (OpCodes.Bgt_Un, target);
3763 ec.Emit (OpCodes.Bgt, target);
3766 ec.Emit (OpCodes.Ble_Un, target);
3768 ec.Emit (OpCodes.Ble, target);
3771 case Operator.LessThanOrEqual:
3773 if (is_unsigned && !is_float)
3774 ec.Emit (OpCodes.Ble_Un, target);
3776 ec.Emit (OpCodes.Ble, target);
3779 ec.Emit (OpCodes.Bgt_Un, target);
3781 ec.Emit (OpCodes.Bgt, target);
3785 case Operator.GreaterThanOrEqual:
3787 if (is_unsigned && !is_float)
3788 ec.Emit (OpCodes.Bge_Un, target);
3790 ec.Emit (OpCodes.Bge, target);
3793 ec.Emit (OpCodes.Blt_Un, target);
3795 ec.Emit (OpCodes.Blt, target);
3798 throw new InternalErrorException (oper.ToString ());
3802 public override void Emit (EmitContext ec)
3804 EmitOperator (ec, left.Type);
3807 protected virtual void EmitOperator (EmitContext ec, TypeSpec l)
3810 // Handle short-circuit operators differently
3813 if ((oper & Operator.LogicalMask) != 0) {
3814 Label load_result = ec.DefineLabel ();
3815 Label end = ec.DefineLabel ();
3817 bool is_or = oper == Operator.LogicalOr;
3818 left.EmitBranchable (ec, load_result, is_or);
3820 ec.Emit (OpCodes.Br_S, end);
3822 ec.MarkLabel (load_result);
3823 ec.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3829 // Optimize zero-based operations which cannot be optimized at expression level
3831 if (oper == Operator.Subtraction) {
3832 var lc = left as IntegralConstant;
3833 if (lc != null && lc.IsDefaultValue) {
3835 ec.Emit (OpCodes.Neg);
3842 EmitOperatorOpcode (ec, oper, l);
3845 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3846 // expression because that would wrap lifted binary operation
3848 if (enum_conversion != null)
3849 enum_conversion.Emit (ec);
3852 public override void EmitSideEffect (EmitContext ec)
3854 if ((oper & Operator.LogicalMask) != 0 ||
3855 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3856 base.EmitSideEffect (ec);
3858 left.EmitSideEffect (ec);
3859 right.EmitSideEffect (ec);
3863 protected override void CloneTo (CloneContext clonectx, Expression t)
3865 Binary target = (Binary) t;
3867 target.left = left.Clone (clonectx);
3868 target.right = right.Clone (clonectx);
3871 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3873 Arguments binder_args = new Arguments (4);
3875 MemberAccess sle = new MemberAccess (new MemberAccess (
3876 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3878 CSharpBinderFlags flags = 0;
3879 if (ec.HasSet (ResolveContext.Options.CheckedScope))
3880 flags = CSharpBinderFlags.CheckedContext;
3882 if ((oper & Operator.LogicalMask) != 0)
3883 flags |= CSharpBinderFlags.BinaryOperationLogical;
3885 binder_args.Add (new Argument (new EnumConstant (new IntLiteral ((int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve (loc))));
3886 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3887 binder_args.Add (new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc)));
3888 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
3890 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
3893 public override Expression CreateExpressionTree (ResolveContext ec)
3895 return CreateExpressionTree (ec, null);
3898 Expression CreateExpressionTree (ResolveContext ec, Expression method)
3901 bool lift_arg = false;
3904 case Operator.Addition:
3905 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3906 method_name = "AddChecked";
3908 method_name = "Add";
3910 case Operator.BitwiseAnd:
3911 method_name = "And";
3913 case Operator.BitwiseOr:
3916 case Operator.Division:
3917 method_name = "Divide";
3919 case Operator.Equality:
3920 method_name = "Equal";
3923 case Operator.ExclusiveOr:
3924 method_name = "ExclusiveOr";
3926 case Operator.GreaterThan:
3927 method_name = "GreaterThan";
3930 case Operator.GreaterThanOrEqual:
3931 method_name = "GreaterThanOrEqual";
3934 case Operator.Inequality:
3935 method_name = "NotEqual";
3938 case Operator.LeftShift:
3939 method_name = "LeftShift";
3941 case Operator.LessThan:
3942 method_name = "LessThan";
3945 case Operator.LessThanOrEqual:
3946 method_name = "LessThanOrEqual";
3949 case Operator.LogicalAnd:
3950 method_name = "AndAlso";
3952 case Operator.LogicalOr:
3953 method_name = "OrElse";
3955 case Operator.Modulus:
3956 method_name = "Modulo";
3958 case Operator.Multiply:
3959 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3960 method_name = "MultiplyChecked";
3962 method_name = "Multiply";
3964 case Operator.RightShift:
3965 method_name = "RightShift";
3967 case Operator.Subtraction:
3968 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3969 method_name = "SubtractChecked";
3971 method_name = "Subtract";
3975 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3978 Arguments args = new Arguments (2);
3979 args.Add (new Argument (left.CreateExpressionTree (ec)));
3980 args.Add (new Argument (right.CreateExpressionTree (ec)));
3981 if (method != null) {
3983 args.Add (new Argument (new BoolLiteral (false, loc)));
3985 args.Add (new Argument (method));
3988 return CreateExpressionFactoryCall (ec, method_name, args);
3993 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3994 // b, c, d... may be strings or objects.
3996 public class StringConcat : Expression {
3997 Arguments arguments;
3998 static IList<MemberSpec> concat_members;
4000 public StringConcat (Expression left, Expression right, Location loc)
4003 type = TypeManager.string_type;
4004 eclass = ExprClass.Value;
4006 arguments = new Arguments (2);
4009 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4011 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4012 throw new ArgumentException ();
4014 var s = new StringConcat (left, right, loc);
4015 s.Append (rc, left);
4016 s.Append (rc, right);
4020 public override Expression CreateExpressionTree (ResolveContext ec)
4022 Argument arg = arguments [0];
4023 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4027 // Creates nested calls tree from an array of arguments used for IL emit
4029 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4031 Arguments concat_args = new Arguments (2);
4032 Arguments add_args = new Arguments (3);
4034 concat_args.Add (left);
4035 add_args.Add (new Argument (left_etree));
4037 concat_args.Add (arguments [pos]);
4038 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4040 var methods = CreateConcatMethodCandidates ();
4041 if (methods == null)
4044 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4045 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4049 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4051 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4052 if (++pos == arguments.Count)
4055 left = new Argument (new EmptyExpression (method.ReturnType));
4056 return CreateExpressionAddCall (ec, left, expr, pos);
4059 protected override Expression DoResolve (ResolveContext ec)
4064 void Append (ResolveContext rc, Expression operand)
4069 StringConstant sc = operand as StringConstant;
4071 if (arguments.Count != 0) {
4072 Argument last_argument = arguments [arguments.Count - 1];
4073 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4074 if (last_expr_constant != null) {
4075 last_argument.Expr = new StringConstant (
4076 last_expr_constant.Value + sc.Value, sc.Location).Resolve (rc);
4082 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4084 StringConcat concat_oper = operand as StringConcat;
4085 if (concat_oper != null) {
4086 arguments.AddRange (concat_oper.arguments);
4091 arguments.Add (new Argument (operand));
4094 IList<MemberSpec> CreateConcatMethodCandidates ()
4096 if (concat_members == null) {
4097 concat_members = MemberCache.FindMembers (type, "Concat", true);
4100 return concat_members;
4103 public override void Emit (EmitContext ec)
4105 var members = CreateConcatMethodCandidates ();
4106 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4107 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4109 Invocation.EmitCall (ec, null, method, arguments, loc);
4112 public override SLE.Expression MakeExpression (BuilderContext ctx)
4114 if (arguments.Count != 2)
4115 throw new NotImplementedException ("arguments.Count != 2");
4117 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4118 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4121 public static void Reset ()
4123 concat_members = null;
4128 // User-defined conditional logical operator
4130 public class ConditionalLogicalOperator : UserOperatorCall {
4131 readonly bool is_and;
4132 Expression oper_expr;
4134 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4135 : base (oper, arguments, expr_tree, loc)
4137 this.is_and = is_and;
4138 eclass = ExprClass.Unresolved;
4141 protected override Expression DoResolve (ResolveContext ec)
4143 AParametersCollection pd = oper.Parameters;
4144 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4145 ec.Report.Error (217, loc,
4146 "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",
4147 oper.GetSignatureForError ());
4151 Expression left_dup = new EmptyExpression (type);
4152 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4153 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4154 if (op_true == null || op_false == null) {
4155 ec.Report.Error (218, loc,
4156 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4157 TypeManager.CSharpName (type), oper.GetSignatureForError ());
4161 oper_expr = is_and ? op_false : op_true;
4162 eclass = ExprClass.Value;
4166 public override void Emit (EmitContext ec)
4168 Label end_target = ec.DefineLabel ();
4171 // Emit and duplicate left argument
4173 arguments [0].Expr.Emit (ec);
4174 ec.Emit (OpCodes.Dup);
4175 arguments.RemoveAt (0);
4177 oper_expr.EmitBranchable (ec, end_target, true);
4179 ec.MarkLabel (end_target);
4183 public class PointerArithmetic : Expression {
4184 Expression left, right;
4188 // We assume that `l' is always a pointer
4190 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4199 public override Expression CreateExpressionTree (ResolveContext ec)
4201 Error_PointerInsideExpressionTree (ec);
4205 protected override Expression DoResolve (ResolveContext ec)
4207 eclass = ExprClass.Variable;
4209 var pc = left.Type as PointerContainer;
4210 if (pc != null && pc.Element.BuildinType == BuildinTypeSpec.Type.Void) {
4211 Error_VoidPointerOperation (ec);
4218 public override void Emit (EmitContext ec)
4220 TypeSpec op_type = left.Type;
4222 // It must be either array or fixed buffer
4224 if (TypeManager.HasElementType (op_type)) {
4225 element = TypeManager.GetElementType (op_type);
4227 FieldExpr fe = left as FieldExpr;
4229 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
4234 int size = GetTypeSize (element);
4235 TypeSpec rtype = right.Type;
4237 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4239 // handle (pointer - pointer)
4243 ec.Emit (OpCodes.Sub);
4247 ec.Emit (OpCodes.Sizeof, element);
4250 ec.Emit (OpCodes.Div);
4252 ec.Emit (OpCodes.Conv_I8);
4255 // handle + and - on (pointer op int)
4257 Constant left_const = left as Constant;
4258 if (left_const != null) {
4260 // Optimize ((T*)null) pointer operations
4262 if (left_const.IsDefaultValue) {
4263 left = EmptyExpression.Null;
4271 var right_const = right as Constant;
4272 if (right_const != null) {
4274 // Optimize 0-based arithmetic
4276 if (right_const.IsDefaultValue)
4280 right = new IntConstant (size, right.Location);
4282 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
4284 // TODO: Should be the checks resolve context sensitive?
4285 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
4286 right = new Binary (Binary.Operator.Multiply, right, right_const, loc).Resolve (rc);
4292 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
4293 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
4294 ec.Emit (OpCodes.Conv_I);
4295 } else if (rtype == TypeManager.uint32_type) {
4296 ec.Emit (OpCodes.Conv_U);
4299 if (right_const == null && size != 1){
4301 ec.Emit (OpCodes.Sizeof, element);
4304 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
4305 ec.Emit (OpCodes.Conv_I8);
4307 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4310 if (left_const == null) {
4311 if (rtype == TypeManager.int64_type)
4312 ec.Emit (OpCodes.Conv_I);
4313 else if (rtype == TypeManager.uint64_type)
4314 ec.Emit (OpCodes.Conv_U);
4316 Binary.EmitOperatorOpcode (ec, op, op_type);
4323 // A boolean-expression is an expression that yields a result
4326 public class BooleanExpression : ShimExpression
4328 public BooleanExpression (Expression expr)
4331 this.loc = expr.Location;
4334 public override Expression CreateExpressionTree (ResolveContext ec)
4336 // TODO: We should emit IsTrue (v4) instead of direct user operator
4337 // call but that would break csc compatibility
4338 return base.CreateExpressionTree (ec);
4341 protected override Expression DoResolve (ResolveContext ec)
4343 // A boolean-expression is required to be of a type
4344 // that can be implicitly converted to bool or of
4345 // a type that implements operator true
4347 expr = expr.Resolve (ec);
4351 Assign ass = expr as Assign;
4352 if (ass != null && ass.Source is Constant) {
4353 ec.Report.Warning (665, 3, loc,
4354 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4357 if (expr.Type == TypeManager.bool_type)
4360 if (expr.Type == InternalType.Dynamic) {
4361 Arguments args = new Arguments (1);
4362 args.Add (new Argument (expr));
4363 return DynamicUnaryConversion.CreateIsTrue (args, loc).Resolve (ec);
4366 type = TypeManager.bool_type;
4367 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4368 if (converted != null)
4372 // If no implicit conversion to bool exists, try using `operator true'
4374 converted = GetOperatorTrue (ec, expr, loc);
4375 if (converted == null) {
4376 expr.Error_ValueCannotBeConverted (ec, loc, type, false);
4384 public class BooleanExpressionFalse : Unary
4386 public BooleanExpressionFalse (Expression expr)
4387 : base (Operator.LogicalNot, expr, expr.Location)
4391 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
4393 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
4398 /// Implements the ternary conditional operator (?:)
4400 public class Conditional : Expression {
4401 Expression expr, true_expr, false_expr;
4403 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
4406 this.true_expr = true_expr;
4407 this.false_expr = false_expr;
4411 public Expression Expr {
4417 public Expression TrueExpr {
4423 public Expression FalseExpr {
4429 public override Expression CreateExpressionTree (ResolveContext ec)
4431 Arguments args = new Arguments (3);
4432 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4433 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4434 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4435 return CreateExpressionFactoryCall (ec, "Condition", args);
4438 protected override Expression DoResolve (ResolveContext ec)
4440 expr = expr.Resolve (ec);
4441 true_expr = true_expr.Resolve (ec);
4442 false_expr = false_expr.Resolve (ec);
4444 if (true_expr == null || false_expr == null || expr == null)
4447 eclass = ExprClass.Value;
4448 TypeSpec true_type = true_expr.Type;
4449 TypeSpec false_type = false_expr.Type;
4453 // First, if an implicit conversion exists from true_expr
4454 // to false_expr, then the result type is of type false_expr.Type
4456 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
4457 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4458 if (conv != null && true_type != InternalType.Dynamic) {
4460 // Check if both can convert implicitly to each other's type
4464 if (false_type != InternalType.Dynamic && Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
4465 ec.Report.Error (172, true_expr.Location,
4466 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
4467 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
4472 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4475 ec.Report.Error (173, true_expr.Location,
4476 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4477 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4482 // Dead code optimalization
4483 Constant c = expr as Constant;
4485 bool is_false = c.IsDefaultValue;
4486 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
4487 return ReducedExpression.Create (
4488 is_false ? false_expr : true_expr, this,
4489 false_expr is Constant && true_expr is Constant).Resolve (ec);
4495 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
4500 public override void Emit (EmitContext ec)
4502 Label false_target = ec.DefineLabel ();
4503 Label end_target = ec.DefineLabel ();
4505 expr.EmitBranchable (ec, false_target, false);
4506 true_expr.Emit (ec);
4508 if (type.IsInterface) {
4509 LocalBuilder temp = ec.GetTemporaryLocal (type);
4510 ec.Emit (OpCodes.Stloc, temp);
4511 ec.Emit (OpCodes.Ldloc, temp);
4512 ec.FreeTemporaryLocal (temp, type);
4515 ec.Emit (OpCodes.Br, end_target);
4516 ec.MarkLabel (false_target);
4517 false_expr.Emit (ec);
4518 ec.MarkLabel (end_target);
4521 protected override void CloneTo (CloneContext clonectx, Expression t)
4523 Conditional target = (Conditional) t;
4525 target.expr = expr.Clone (clonectx);
4526 target.true_expr = true_expr.Clone (clonectx);
4527 target.false_expr = false_expr.Clone (clonectx);
4531 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4532 LocalTemporary temp;
4535 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4537 public abstract bool IsLockedByStatement { get; set; }
4539 public abstract bool IsFixed { get; }
4540 public abstract bool IsRef { get; }
4541 public abstract string Name { get; }
4542 public abstract void SetHasAddressTaken ();
4545 // Variable IL data, it has to be protected to encapsulate hoisted variables
4547 protected abstract ILocalVariable Variable { get; }
4550 // Variable flow-analysis data
4552 public abstract VariableInfo VariableInfo { get; }
4555 public virtual void AddressOf (EmitContext ec, AddressOp mode)
4557 HoistedVariable hv = GetHoistedVariable (ec);
4559 hv.AddressOf (ec, mode);
4563 Variable.EmitAddressOf (ec);
4566 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
4568 if (IsLockedByStatement) {
4569 rc.Report.Warning (728, 2, loc,
4570 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
4577 public override void Emit (EmitContext ec)
4582 public override void EmitSideEffect (EmitContext ec)
4588 // This method is used by parameters that are references, that are
4589 // being passed as references: we only want to pass the pointer (that
4590 // is already stored in the parameter, not the address of the pointer,
4591 // and not the value of the variable).
4593 public void EmitLoad (EmitContext ec)
4598 public void Emit (EmitContext ec, bool leave_copy)
4600 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4602 HoistedVariable hv = GetHoistedVariable (ec);
4604 hv.Emit (ec, leave_copy);
4612 // If we are a reference, we loaded on the stack a pointer
4613 // Now lets load the real value
4615 ec.EmitLoadFromPtr (type);
4619 ec.Emit (OpCodes.Dup);
4622 temp = new LocalTemporary (Type);
4628 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4629 bool prepare_for_load)
4631 HoistedVariable hv = GetHoistedVariable (ec);
4633 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4637 New n_source = source as New;
4638 if (n_source != null) {
4639 if (!n_source.Emit (ec, this)) {
4643 ec.EmitLoadFromPtr (type);
4655 ec.Emit (OpCodes.Dup);
4657 temp = new LocalTemporary (Type);
4663 ec.EmitStoreFromPtr (type);
4665 Variable.EmitAssign (ec);
4674 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4676 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4679 public HoistedVariable GetHoistedVariable (EmitContext ec)
4681 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4684 public override string GetSignatureForError ()
4689 public bool IsHoisted {
4690 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4695 // Resolved reference to a local variable
4697 public class LocalVariableReference : VariableReference
4699 public LocalVariable local_info;
4701 public LocalVariableReference (LocalVariable li, Location l)
4703 this.local_info = li;
4707 public override VariableInfo VariableInfo {
4708 get { return local_info.VariableInfo; }
4711 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4713 return local_info.HoistedVariant;
4719 // A local variable is always fixed
4721 public override bool IsFixed {
4727 public override bool IsLockedByStatement {
4729 return local_info.IsLocked;
4732 local_info.IsLocked = value;
4736 public override bool IsRef {
4737 get { return false; }
4740 public override string Name {
4741 get { return local_info.Name; }
4746 public bool VerifyAssigned (ResolveContext ec)
4748 VariableInfo variable_info = local_info.VariableInfo;
4749 return variable_info == null || variable_info.IsAssigned (ec, loc);
4752 public override void SetHasAddressTaken ()
4754 local_info.AddressTaken = true;
4757 public override Expression CreateExpressionTree (ResolveContext ec)
4759 HoistedVariable hv = GetHoistedVariable (ec);
4761 return hv.CreateExpressionTree ();
4763 Arguments arg = new Arguments (1);
4764 arg.Add (new Argument (this));
4765 return CreateExpressionFactoryCall (ec, "Constant", arg);
4768 void DoResolveBase (ResolveContext ec)
4770 VerifyAssigned (ec);
4773 // If we are referencing a variable from the external block
4774 // flag it for capturing
4776 if (ec.MustCaptureVariable (local_info)) {
4777 if (local_info.AddressTaken)
4778 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4780 if (ec.IsVariableCapturingRequired) {
4781 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4782 storey.CaptureLocalVariable (ec, local_info);
4786 eclass = ExprClass.Variable;
4787 type = local_info.Type;
4790 protected override Expression DoResolve (ResolveContext ec)
4792 local_info.SetIsUsed ();
4798 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4801 if (right_side == EmptyExpression.OutAccess.Instance)
4802 local_info.SetIsUsed ();
4804 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
4807 if (right_side == EmptyExpression.OutAccess.Instance) {
4808 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4809 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4810 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4811 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4812 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4813 } else if (right_side == EmptyExpression.UnaryAddress) {
4814 code = 459; msg = "Cannot take the address of {1} `{0}'";
4816 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4818 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4819 } else if (VariableInfo != null) {
4820 VariableInfo.SetAssigned (ec);
4825 return base.DoResolveLValue (ec, right_side);
4828 public override int GetHashCode ()
4830 return local_info.GetHashCode ();
4833 public override bool Equals (object obj)
4835 LocalVariableReference lvr = obj as LocalVariableReference;
4839 return local_info == lvr.local_info;
4842 protected override ILocalVariable Variable {
4843 get { return local_info; }
4846 public override string ToString ()
4848 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4851 protected override void CloneTo (CloneContext clonectx, Expression t)
4858 /// This represents a reference to a parameter in the intermediate
4861 public class ParameterReference : VariableReference
4863 protected ParametersBlock.ParameterInfo pi;
4865 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
4873 public override bool IsLockedByStatement {
4878 pi.IsLocked = value;
4882 public override bool IsRef {
4883 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4886 bool HasOutModifier {
4887 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4890 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4892 return pi.Parameter.HoistedVariant;
4896 // A ref or out parameter is classified as a moveable variable, even
4897 // if the argument given for the parameter is a fixed variable
4899 public override bool IsFixed {
4900 get { return !IsRef; }
4903 public override string Name {
4904 get { return Parameter.Name; }
4907 public Parameter Parameter {
4908 get { return pi.Parameter; }
4911 public override VariableInfo VariableInfo {
4912 get { return pi.VariableInfo; }
4915 protected override ILocalVariable Variable {
4916 get { return Parameter; }
4921 public bool IsAssigned (ResolveContext ec, Location loc)
4923 // HACK: Variables are not captured in probing mode
4924 if (ec.IsInProbingMode)
4927 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4930 ec.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4934 public override void SetHasAddressTaken ()
4936 Parameter.HasAddressTaken = true;
4939 void SetAssigned (ResolveContext ec)
4941 if (HasOutModifier && ec.DoFlowAnalysis)
4942 ec.CurrentBranching.SetAssigned (VariableInfo);
4945 bool DoResolveBase (ResolveContext ec)
4947 type = pi.ParameterType;
4948 eclass = ExprClass.Variable;
4951 // If we are referencing a parameter from the external block
4952 // flag it for capturing
4954 if (ec.MustCaptureVariable (pi)) {
4955 if (Parameter.HasAddressTaken)
4956 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4959 ec.Report.Error (1628, loc,
4960 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4961 Name, ec.CurrentAnonymousMethod.ContainerType);
4964 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
4965 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
4966 storey.CaptureParameter (ec, this);
4973 public override int GetHashCode ()
4975 return Name.GetHashCode ();
4978 public override bool Equals (object obj)
4980 ParameterReference pr = obj as ParameterReference;
4984 return Name == pr.Name;
4987 public override void AddressOf (EmitContext ec, AddressOp mode)
4990 // ParameterReferences might already be a reference
4997 base.AddressOf (ec, mode);
5000 protected override void CloneTo (CloneContext clonectx, Expression target)
5006 public override Expression CreateExpressionTree (ResolveContext ec)
5008 HoistedVariable hv = GetHoistedVariable (ec);
5010 return hv.CreateExpressionTree ();
5012 return Parameter.ExpressionTreeVariableReference ();
5016 // Notice that for ref/out parameters, the type exposed is not the
5017 // same type exposed externally.
5020 // externally we expose "int&"
5021 // here we expose "int".
5023 // We record this in "is_ref". This means that the type system can treat
5024 // the type as it is expected, but when we generate the code, we generate
5025 // the alternate kind of code.
5027 protected override Expression DoResolve (ResolveContext ec)
5029 if (!DoResolveBase (ec))
5032 // HACK: Variables are not captured in probing mode
5033 if (ec.IsInProbingMode)
5036 if (HasOutModifier && ec.DoFlowAnalysis &&
5037 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
5043 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5045 if (!DoResolveBase (ec))
5049 return base.DoResolveLValue (ec, right_side);
5052 static public void EmitLdArg (EmitContext ec, int x)
5055 case 0: ec.Emit (OpCodes.Ldarg_0); break;
5056 case 1: ec.Emit (OpCodes.Ldarg_1); break;
5057 case 2: ec.Emit (OpCodes.Ldarg_2); break;
5058 case 3: ec.Emit (OpCodes.Ldarg_3); break;
5060 if (x > byte.MaxValue)
5061 ec.Emit (OpCodes.Ldarg, x);
5063 ec.Emit (OpCodes.Ldarg_S, (byte) x);
5070 /// Invocation of methods or delegates.
5072 public class Invocation : ExpressionStatement
5074 protected Arguments arguments;
5075 protected Expression expr;
5076 protected MethodGroupExpr mg;
5078 public Invocation (Expression expr, Arguments arguments)
5081 this.arguments = arguments;
5083 loc = expr.Location;
5087 public Arguments Arguments {
5093 public Expression Expression {
5100 protected override void CloneTo (CloneContext clonectx, Expression t)
5102 Invocation target = (Invocation) t;
5104 if (arguments != null)
5105 target.arguments = arguments.Clone (clonectx);
5107 target.expr = expr.Clone (clonectx);
5111 public override Expression CreateExpressionTree (ResolveContext ec)
5113 Expression instance = mg.IsInstance ?
5114 mg.InstanceExpression.CreateExpressionTree (ec) :
5115 new NullLiteral (loc);
5117 var args = Arguments.CreateForExpressionTree (ec, arguments,
5119 mg.CreateExpressionTree (ec));
5121 return CreateExpressionFactoryCall (ec, "Call", args);
5124 protected override Expression DoResolve (ResolveContext ec)
5126 Expression member_expr;
5127 var atn = expr as ATypeNameExpression;
5129 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
5130 if (member_expr != null)
5131 member_expr = member_expr.Resolve (ec);
5133 member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5136 if (member_expr == null)
5140 // Next, evaluate all the expressions in the argument list
5142 bool dynamic_arg = false;
5143 if (arguments != null)
5144 arguments.Resolve (ec, out dynamic_arg);
5146 TypeSpec expr_type = member_expr.Type;
5147 if (expr_type == InternalType.Dynamic)
5148 return DoResolveDynamic (ec, member_expr);
5150 mg = member_expr as MethodGroupExpr;
5151 Expression invoke = null;
5154 if (expr_type != null && TypeManager.IsDelegateType (expr_type)) {
5155 invoke = new DelegateInvocation (member_expr, arguments, loc);
5156 invoke = invoke.Resolve (ec);
5157 if (invoke == null || !dynamic_arg)
5160 if (member_expr is RuntimeValueExpression) {
5161 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
5162 member_expr.Type.GetSignatureForError ()); ;
5166 MemberExpr me = member_expr as MemberExpr;
5168 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5172 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
5173 member_expr.GetSignatureForError ());
5178 if (invoke == null) {
5179 mg = DoResolveOverload (ec);
5185 return DoResolveDynamic (ec, member_expr);
5187 var method = mg.BestCandidate;
5188 type = mg.BestCandidateReturnType;
5190 if (arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
5192 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5194 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5198 IsSpecialMethodInvocation (ec, method, loc);
5200 eclass = ExprClass.Value;
5204 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
5207 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
5209 args = dmb.Arguments;
5210 if (arguments != null)
5211 args.AddRange (arguments);
5212 } else if (mg == null) {
5213 if (arguments == null)
5214 args = new Arguments (1);
5218 args.Insert (0, new Argument (memberExpr));
5222 ec.Report.Error (1971, loc,
5223 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
5228 if (arguments == null)
5229 args = new Arguments (1);
5233 MemberAccess ma = expr as MemberAccess;
5235 var left_type = ma.LeftExpression as TypeExpr;
5236 if (left_type != null) {
5237 args.Insert (0, new Argument (new TypeOf (left_type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5240 // Any value type has to be pass as by-ref to get back the same
5241 // instance on which the member was called
5243 var mod = TypeManager.IsValueType (ma.LeftExpression.Type) ? Argument.AType.Ref : Argument.AType.None;
5244 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
5246 } else { // is SimpleName
5248 args.Insert (0, new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc).Resolve (ec), Argument.AType.DynamicTypeName));
5250 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5255 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5258 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5260 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
5263 static MetaType[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
5265 AParametersCollection pd = mb.Parameters;
5267 Argument a = arguments[pd.Count - 1];
5268 Arglist list = (Arglist) a.Expr;
5270 return list.ArgumentTypes;
5274 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
5275 // or the type dynamic, then the member is invocable
5277 public static bool IsMemberInvocable (MemberSpec member)
5279 switch (member.Kind) {
5280 case MemberKind.Event:
5282 case MemberKind.Field:
5283 case MemberKind.Property:
5284 var m = member as IInterfaceMemberSpec;
5285 return m.MemberType.IsDelegate || m.MemberType == InternalType.Dynamic;
5291 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
5293 if (!method.IsReservedMethod)
5296 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
5299 ec.Report.SymbolRelatedToPreviousError (method);
5300 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5301 method.GetSignatureForError ());
5307 // Used to decide whether call or callvirt is needed
5309 static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
5312 // There are 2 scenarious where we emit callvirt
5314 // Case 1: A method is virtual and it's not used to call base
5315 // Case 2: A method instance expression can be null. In this casen callvirt ensures
5316 // correct NRE exception when the method is called
5318 var decl_type = method.DeclaringType;
5319 if (decl_type.IsStruct || decl_type.IsEnum)
5322 if (instance is BaseThis)
5326 // It's non-virtual and will never be null
5328 if (!method.IsVirtual && (instance is This || instance is New || instance is ArrayCreation || instance is DelegateCreation))
5335 /// is_base tells whether we want to force the use of the `call'
5336 /// opcode instead of using callvirt. Call is required to call
5337 /// a specific method, while callvirt will always use the most
5338 /// recent method in the vtable.
5340 /// is_static tells whether this is an invocation on a static method
5342 /// instance_expr is an expression that represents the instance
5343 /// it must be non-null if is_static is false.
5345 /// method is the method to invoke.
5347 /// Arguments is the list of arguments to pass to the method or constructor.
5349 public static void EmitCall (EmitContext ec, Expression instance_expr,
5350 MethodSpec method, Arguments Arguments, Location loc)
5352 EmitCall (ec, instance_expr, method, Arguments, loc, false, false);
5355 // `dup_args' leaves an extra copy of the arguments on the stack
5356 // `omit_args' does not leave any arguments at all.
5357 // So, basically, you could make one call with `dup_args' set to true,
5358 // and then another with `omit_args' set to true, and the two calls
5359 // would have the same set of arguments. However, each argument would
5360 // only have been evaluated once.
5361 public static void EmitCall (EmitContext ec, Expression instance_expr,
5362 MethodSpec method, Arguments Arguments, Location loc,
5363 bool dup_args, bool omit_args)
5365 LocalTemporary this_arg = null;
5367 // Speed up the check by not doing it on not allowed targets
5368 if (method.ReturnType == TypeManager.void_type && method.IsConditionallyExcluded (loc))
5372 TypeSpec iexpr_type;
5374 if (method.IsStatic) {
5376 call_op = OpCodes.Call;
5378 iexpr_type = instance_expr.Type;
5380 if (IsVirtualCallRequired (instance_expr, method)) {
5381 call_op = OpCodes.Callvirt;
5383 call_op = OpCodes.Call;
5387 // If this is ourselves, push "this"
5390 TypeSpec t = iexpr_type;
5393 // Push the instance expression
5395 if ((iexpr_type.IsStruct && (call_op == OpCodes.Callvirt || (call_op == OpCodes.Call && method.DeclaringType == iexpr_type))) ||
5396 iexpr_type.IsGenericParameter || TypeManager.IsNullableType (method.DeclaringType)) {
5398 // If the expression implements IMemoryLocation, then
5399 // we can optimize and use AddressOf on the
5402 // If not we have to use some temporary storage for
5404 var iml = instance_expr as IMemoryLocation;
5406 iml.AddressOf (ec, AddressOp.LoadStore);
5408 LocalTemporary temp = new LocalTemporary (iexpr_type);
5409 instance_expr.Emit (ec);
5411 temp.AddressOf (ec, AddressOp.Load);
5414 // avoid the overhead of doing this all the time.
5416 t = ReferenceContainer.MakeType (iexpr_type);
5417 } else if (iexpr_type.IsEnum || iexpr_type.IsStruct) {
5418 instance_expr.Emit (ec);
5419 ec.Emit (OpCodes.Box, iexpr_type);
5420 t = iexpr_type = TypeManager.object_type;
5422 instance_expr.Emit (ec);
5426 ec.Emit (OpCodes.Dup);
5427 if (Arguments != null && Arguments.Count != 0) {
5428 this_arg = new LocalTemporary (t);
5429 this_arg.Store (ec);
5435 if (!omit_args && Arguments != null) {
5436 var dup_arg_exprs = Arguments.Emit (ec, dup_args);
5440 foreach (var dup in dup_arg_exprs) {
5442 lt = dup as LocalTemporary;
5449 if (call_op == OpCodes.Callvirt && (iexpr_type.IsGenericParameter || iexpr_type.IsStruct)) {
5450 ec.Emit (OpCodes.Constrained, iexpr_type);
5453 if (method.Parameters.HasArglist) {
5454 var varargs_types = GetVarargsTypes (method, Arguments);
5455 ec.Emit (call_op, method, varargs_types);
5462 // and DoFoo is not virtual, you can omit the callvirt,
5463 // because you don't need the null checking behavior.
5465 ec.Emit (call_op, method);
5468 public override void Emit (EmitContext ec)
5470 mg.EmitCall (ec, arguments);
5473 public override void EmitStatement (EmitContext ec)
5478 // Pop the return value if there is one
5480 if (type != TypeManager.void_type)
5481 ec.Emit (OpCodes.Pop);
5484 public override SLE.Expression MakeExpression (BuilderContext ctx)
5486 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
5489 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
5492 throw new NotSupportedException ();
5494 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5495 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
5501 // Implements simple new expression
5503 public class New : ExpressionStatement, IMemoryLocation
5505 protected Arguments arguments;
5508 // During bootstrap, it contains the RequestedType,
5509 // but if `type' is not null, it *might* contain a NewDelegate
5510 // (because of field multi-initialization)
5512 protected Expression RequestedType;
5514 protected MethodSpec method;
5516 public New (Expression requested_type, Arguments arguments, Location l)
5518 RequestedType = requested_type;
5519 this.arguments = arguments;
5524 public Arguments Arguments {
5531 // Returns true for resolved `new S()'
5533 public bool IsDefaultStruct {
5535 return arguments == null && type.IsStruct && GetType () == typeof (New);
5542 /// Converts complex core type syntax like 'new int ()' to simple constant
5544 public static Constant Constantify (TypeSpec t, Location loc)
5546 if (t == TypeManager.int32_type)
5547 return new IntConstant (0, loc);
5548 if (t == TypeManager.uint32_type)
5549 return new UIntConstant (0, loc);
5550 if (t == TypeManager.int64_type)
5551 return new LongConstant (0, loc);
5552 if (t == TypeManager.uint64_type)
5553 return new ULongConstant (0, loc);
5554 if (t == TypeManager.float_type)
5555 return new FloatConstant (0, loc);
5556 if (t == TypeManager.double_type)
5557 return new DoubleConstant (0, loc);
5558 if (t == TypeManager.short_type)
5559 return new ShortConstant (0, loc);
5560 if (t == TypeManager.ushort_type)
5561 return new UShortConstant (0, loc);
5562 if (t == TypeManager.sbyte_type)
5563 return new SByteConstant (0, loc);
5564 if (t == TypeManager.byte_type)
5565 return new ByteConstant (0, loc);
5566 if (t == TypeManager.char_type)
5567 return new CharConstant ('\0', loc);
5568 if (t == TypeManager.bool_type)
5569 return new BoolConstant (false, loc);
5570 if (t == TypeManager.decimal_type)
5571 return new DecimalConstant (0, loc);
5572 if (TypeManager.IsEnumType (t))
5573 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
5574 if (TypeManager.IsNullableType (t))
5575 return Nullable.LiftedNull.Create (t, loc);
5581 // Checks whether the type is an interface that has the
5582 // [ComImport, CoClass] attributes and must be treated
5585 public Expression CheckComImport (ResolveContext ec)
5587 if (!type.IsInterface)
5591 // Turn the call into:
5592 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5594 var real_class = type.MemberDefinition.GetAttributeCoClass ();
5595 if (real_class == null)
5598 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
5599 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5600 return cast.Resolve (ec);
5603 public override Expression CreateExpressionTree (ResolveContext ec)
5606 if (method == null) {
5607 args = new Arguments (1);
5608 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5610 args = Arguments.CreateForExpressionTree (ec,
5611 arguments, new TypeOfMethod (method, loc));
5614 return CreateExpressionFactoryCall (ec, "New", args);
5617 protected override Expression DoResolve (ResolveContext ec)
5619 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5624 eclass = ExprClass.Value;
5626 if (type.IsPointer) {
5627 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5628 TypeManager.CSharpName (type));
5632 if (arguments == null) {
5633 Constant c = Constantify (type, RequestedType.Location);
5635 return ReducedExpression.Create (c.Resolve (ec), this);
5638 if (TypeManager.IsDelegateType (type)) {
5639 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
5642 var tparam = type as TypeParameterSpec;
5643 if (tparam != null) {
5645 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
5646 // where type parameter constraint is inflated to struct
5648 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !tparam.BaseType.IsStruct) {
5649 ec.Report.Error (304, loc,
5650 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
5651 TypeManager.CSharpName (type));
5654 if ((arguments != null) && (arguments.Count != 0)) {
5655 ec.Report.Error (417, loc,
5656 "`{0}': cannot provide arguments when creating an instance of a variable type",
5657 TypeManager.CSharpName (type));
5663 if (type.IsStatic) {
5664 ec.Report.SymbolRelatedToPreviousError (type);
5665 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5669 if (type.IsInterface || type.IsAbstract){
5670 if (!TypeManager.IsGenericType (type)) {
5671 RequestedType = CheckComImport (ec);
5672 if (RequestedType != null)
5673 return RequestedType;
5676 ec.Report.SymbolRelatedToPreviousError (type);
5677 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5682 // Any struct always defines parameterless constructor
5684 if (type.IsStruct && arguments == null)
5688 if (arguments != null) {
5689 arguments.Resolve (ec, out dynamic);
5694 method = ConstructorLookup (ec, type, ref arguments, loc);
5697 arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5698 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
5704 bool DoEmitTypeParameter (EmitContext ec)
5706 var activator = ec.Module.PredefinedTypes.Activator;
5707 var t = activator.Resolve (loc);
5711 if (TypeManager.activator_create_instance == null) {
5712 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5713 t, MemberFilter.Method ("CreateInstance", 1, ParametersCompiled.EmptyReadOnlyParameters, null), loc);
5716 var ctor_factory = TypeManager.activator_create_instance.MakeGenericMethod (ec.MemberContext, type);
5717 var tparam = (TypeParameterSpec) type;
5719 if (tparam.IsReferenceType) {
5720 ec.Emit (OpCodes.Call, ctor_factory);
5724 // Allow DoEmit() to be called multiple times.
5725 // We need to create a new LocalTemporary each time since
5726 // you can't share LocalBuilders among ILGeneators.
5727 LocalTemporary temp = new LocalTemporary (type);
5729 Label label_activator = ec.DefineLabel ();
5730 Label label_end = ec.DefineLabel ();
5732 temp.AddressOf (ec, AddressOp.Store);
5733 ec.Emit (OpCodes.Initobj, type);
5736 ec.Emit (OpCodes.Box, type);
5737 ec.Emit (OpCodes.Brfalse, label_activator);
5739 temp.AddressOf (ec, AddressOp.Store);
5740 ec.Emit (OpCodes.Initobj, type);
5742 ec.Emit (OpCodes.Br_S, label_end);
5744 ec.MarkLabel (label_activator);
5746 ec.Emit (OpCodes.Call, ctor_factory);
5747 ec.MarkLabel (label_end);
5752 // This Emit can be invoked in two contexts:
5753 // * As a mechanism that will leave a value on the stack (new object)
5754 // * As one that wont (init struct)
5756 // If we are dealing with a ValueType, we have a few
5757 // situations to deal with:
5759 // * The target is a ValueType, and we have been provided
5760 // the instance (this is easy, we are being assigned).
5762 // * The target of New is being passed as an argument,
5763 // to a boxing operation or a function that takes a
5766 // In this case, we need to create a temporary variable
5767 // that is the argument of New.
5769 // Returns whether a value is left on the stack
5771 // *** Implementation note ***
5773 // To benefit from this optimization, each assignable expression
5774 // has to manually cast to New and call this Emit.
5776 // TODO: It's worth to implement it for arrays and fields
5778 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5780 bool is_value_type = TypeManager.IsValueType (type);
5781 VariableReference vr = target as VariableReference;
5783 if (target != null && is_value_type && (vr != null || method == null)) {
5784 target.AddressOf (ec, AddressOp.Store);
5785 } else if (vr != null && vr.IsRef) {
5789 if (arguments != null)
5790 arguments.Emit (ec);
5792 if (is_value_type) {
5793 if (method == null) {
5794 ec.Emit (OpCodes.Initobj, type);
5799 ec.Emit (OpCodes.Call, method);
5804 if (type is TypeParameterSpec)
5805 return DoEmitTypeParameter (ec);
5807 ec.Emit (OpCodes.Newobj, method);
5811 public override void Emit (EmitContext ec)
5813 LocalTemporary v = null;
5814 if (method == null && TypeManager.IsValueType (type)) {
5815 // TODO: Use temporary variable from pool
5816 v = new LocalTemporary (type);
5823 public override void EmitStatement (EmitContext ec)
5825 LocalTemporary v = null;
5826 if (method == null && TypeManager.IsValueType (type)) {
5827 // TODO: Use temporary variable from pool
5828 v = new LocalTemporary (type);
5832 ec.Emit (OpCodes.Pop);
5835 public void AddressOf (EmitContext ec, AddressOp mode)
5837 EmitAddressOf (ec, mode);
5840 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5842 LocalTemporary value_target = new LocalTemporary (type);
5844 if (type is TypeParameterSpec) {
5845 DoEmitTypeParameter (ec);
5846 value_target.Store (ec);
5847 value_target.AddressOf (ec, mode);
5848 return value_target;
5851 if (!TypeManager.IsStruct (type)){
5853 // We throw an exception. So far, I believe we only need to support
5855 // foreach (int j in new StructType ())
5858 throw new Exception ("AddressOf should not be used for classes");
5861 value_target.AddressOf (ec, AddressOp.Store);
5863 if (method == null) {
5864 ec.Emit (OpCodes.Initobj, type);
5866 if (arguments != null)
5867 arguments.Emit (ec);
5869 ec.Emit (OpCodes.Call, method);
5872 value_target.AddressOf (ec, mode);
5873 return value_target;
5876 protected override void CloneTo (CloneContext clonectx, Expression t)
5878 New target = (New) t;
5880 target.RequestedType = RequestedType.Clone (clonectx);
5881 if (arguments != null){
5882 target.arguments = arguments.Clone (clonectx);
5886 public override SLE.Expression MakeExpression (BuilderContext ctx)
5889 return base.MakeExpression (ctx);
5891 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
5897 // Array initializer expression, the expression is allowed in
5898 // variable or field initialization only which makes it tricky as
5899 // the type has to be infered based on the context either from field
5900 // type or variable type (think of multiple declarators)
5902 public class ArrayInitializer : Expression
5904 List<Expression> elements;
5905 BlockVariableDeclaration variable;
5907 public ArrayInitializer (List<Expression> init, Location loc)
5913 public ArrayInitializer (int count, Location loc)
5914 : this (new List<Expression> (count), loc)
5918 public ArrayInitializer (Location loc)
5926 get { return elements.Count; }
5929 public Expression this [int index] {
5931 return elements [index];
5935 public BlockVariableDeclaration VariableDeclaration {
5946 public void Add (Expression expr)
5948 elements.Add (expr);
5951 public override Expression CreateExpressionTree (ResolveContext ec)
5953 throw new NotSupportedException ("ET");
5956 protected override void CloneTo (CloneContext clonectx, Expression t)
5958 var target = (ArrayInitializer) t;
5960 target.elements = new List<Expression> (elements.Count);
5961 foreach (var element in elements)
5962 target.elements.Add (element.Clone (clonectx));
5965 protected override Expression DoResolve (ResolveContext rc)
5967 var current_field = rc.CurrentMemberDefinition as FieldBase;
5968 TypeExpression type;
5969 if (current_field != null) {
5970 type = new TypeExpression (current_field.MemberType, current_field.Location);
5971 } else if (variable != null) {
5972 if (variable.TypeExpression is VarExpr) {
5973 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5974 return EmptyExpression.Null;
5977 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
5979 throw new NotImplementedException ("Unexpected array initializer context");
5982 return new ArrayCreation (type, this).Resolve (rc);
5985 public override void Emit (EmitContext ec)
5987 throw new InternalErrorException ("Missing Resolve call");
5992 /// 14.5.10.2: Represents an array creation expression.
5996 /// There are two possible scenarios here: one is an array creation
5997 /// expression that specifies the dimensions and optionally the
5998 /// initialization data and the other which does not need dimensions
5999 /// specified but where initialization data is mandatory.
6001 public class ArrayCreation : Expression
6003 FullNamedExpression requested_base_type;
6004 ArrayInitializer initializers;
6007 // The list of Argument types.
6008 // This is used to construct the `newarray' or constructor signature
6010 protected List<Expression> arguments;
6012 protected TypeSpec array_element_type;
6013 int num_arguments = 0;
6014 protected int dimensions;
6015 protected readonly ComposedTypeSpecifier rank;
6016 Expression first_emit;
6017 LocalTemporary first_emit_temp;
6019 protected List<Expression> array_data;
6021 Dictionary<int, int> bounds;
6023 // The number of constants in array initializers
6024 int const_initializers_count;
6025 bool only_constant_initializers;
6027 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6028 : this (requested_base_type, rank, initializers, l)
6030 arguments = new List<Expression> (exprs);
6031 num_arguments = arguments.Count;
6035 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6037 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6039 this.requested_base_type = requested_base_type;
6041 this.initializers = initializers;
6045 num_arguments = rank.Dimension;
6049 // For compiler generated single dimensional arrays only
6051 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6052 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6057 // For expressions like int[] foo = { 1, 2, 3 };
6059 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6060 : this (requested_base_type, null, initializers, initializers.Location)
6064 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
6066 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
6069 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6071 if (initializers != null && bounds == null) {
6073 // We use this to store all the date values in the order in which we
6074 // will need to store them in the byte blob later
6076 array_data = new List<Expression> ();
6077 bounds = new Dictionary<int, int> ();
6080 if (specified_dims) {
6081 Expression a = arguments [idx];
6086 a = ConvertExpressionToArrayIndex (ec, a);
6092 if (initializers != null) {
6093 Constant c = a as Constant;
6094 if (c == null && a is ArrayIndexCast)
6095 c = ((ArrayIndexCast) a).Child as Constant;
6098 ec.Report.Error (150, a.Location, "A constant value is expected");
6104 value = System.Convert.ToInt32 (c.GetValue ());
6106 ec.Report.Error (150, a.Location, "A constant value is expected");
6110 // TODO: probe.Count does not fit ulong in
6111 if (value != probe.Count) {
6112 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6116 bounds[idx] = value;
6120 if (initializers == null)
6123 for (int i = 0; i < probe.Count; ++i) {
6125 if (o is ArrayInitializer) {
6126 var sub_probe = o as ArrayInitializer;
6127 if (idx + 1 >= dimensions){
6128 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6132 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6135 } else if (child_bounds > 1) {
6136 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6138 Expression element = ResolveArrayElement (ec, o);
6139 if (element == null)
6142 // Initializers with the default values can be ignored
6143 Constant c = element as Constant;
6145 if (!c.IsDefaultInitializer (array_element_type)) {
6146 ++const_initializers_count;
6149 only_constant_initializers = false;
6152 array_data.Add (element);
6159 public override Expression CreateExpressionTree (ResolveContext ec)
6163 if (array_data == null) {
6164 args = new Arguments (arguments.Count + 1);
6165 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
6166 foreach (Expression a in arguments)
6167 args.Add (new Argument (a.CreateExpressionTree (ec)));
6169 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6172 if (dimensions > 1) {
6173 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6177 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6178 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
6179 if (array_data != null) {
6180 for (int i = 0; i < array_data.Count; ++i) {
6181 Expression e = array_data [i];
6182 args.Add (new Argument (e.CreateExpressionTree (ec)));
6186 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6189 public void UpdateIndices ()
6192 for (var probe = initializers; probe != null;) {
6193 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
6194 Expression e = new IntConstant (probe.Count, Location.Null);
6197 bounds [i++] = probe.Count;
6199 probe = (ArrayInitializer) probe[0];
6202 Expression e = new IntConstant (probe.Count, Location.Null);
6205 bounds [i++] = probe.Count;
6211 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
6213 element = element.Resolve (ec);
6214 if (element == null)
6217 if (element is CompoundAssign.TargetExpression) {
6218 if (first_emit != null)
6219 throw new InternalErrorException ("Can only handle one mutator at a time");
6220 first_emit = element;
6221 element = first_emit_temp = new LocalTemporary (element.Type);
6224 return Convert.ImplicitConversionRequired (
6225 ec, element, array_element_type, loc);
6228 protected bool ResolveInitializers (ResolveContext ec)
6230 only_constant_initializers = true;
6232 if (arguments != null) {
6234 for (int i = 0; i < arguments.Count; ++i) {
6235 res &= CheckIndices (ec, initializers, i, true, dimensions);
6236 if (initializers != null)
6243 arguments = new List<Expression> ();
6245 if (!CheckIndices (ec, initializers, 0, false, dimensions))
6254 // Resolved the type of the array
6256 bool ResolveArrayType (ResolveContext ec)
6261 FullNamedExpression array_type_expr;
6262 if (num_arguments > 0) {
6263 array_type_expr = new ComposedCast (requested_base_type, rank);
6265 array_type_expr = requested_base_type;
6268 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6269 if (array_type_expr == null)
6272 type = array_type_expr.Type;
6273 var ac = type as ArrayContainer;
6275 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6279 array_element_type = ac.Element;
6280 dimensions = ac.Rank;
6285 protected override Expression DoResolve (ResolveContext ec)
6290 if (!ResolveArrayType (ec))
6294 // validate the initializers and fill in any missing bits
6296 if (!ResolveInitializers (ec))
6299 eclass = ExprClass.Value;
6303 byte [] MakeByteBlob ()
6308 int count = array_data.Count;
6310 TypeSpec element_type = array_element_type;
6311 if (TypeManager.IsEnumType (element_type))
6312 element_type = EnumSpec.GetUnderlyingType (element_type);
6314 factor = GetTypeSize (element_type);
6316 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6318 data = new byte [(count * factor + 3) & ~3];
6321 for (int i = 0; i < count; ++i) {
6322 object v = array_data [i];
6324 if (v is EnumConstant)
6325 v = ((EnumConstant) v).Child;
6327 if (v is Constant && !(v is StringConstant))
6328 v = ((Constant) v).GetValue ();
6334 if (element_type == TypeManager.int64_type){
6335 if (!(v is Expression)){
6336 long val = (long) v;
6338 for (int j = 0; j < factor; ++j) {
6339 data [idx + j] = (byte) (val & 0xFF);
6343 } else if (element_type == TypeManager.uint64_type){
6344 if (!(v is Expression)){
6345 ulong val = (ulong) v;
6347 for (int j = 0; j < factor; ++j) {
6348 data [idx + j] = (byte) (val & 0xFF);
6352 } else if (element_type == TypeManager.float_type) {
6353 if (!(v is Expression)){
6354 element = BitConverter.GetBytes ((float) v);
6356 for (int j = 0; j < factor; ++j)
6357 data [idx + j] = element [j];
6358 if (!BitConverter.IsLittleEndian)
6359 System.Array.Reverse (data, idx, 4);
6361 } else if (element_type == TypeManager.double_type) {
6362 if (!(v is Expression)){
6363 element = BitConverter.GetBytes ((double) v);
6365 for (int j = 0; j < factor; ++j)
6366 data [idx + j] = element [j];
6368 // FIXME: Handle the ARM float format.
6369 if (!BitConverter.IsLittleEndian)
6370 System.Array.Reverse (data, idx, 8);
6372 } else if (element_type == TypeManager.char_type){
6373 if (!(v is Expression)){
6374 int val = (int) ((char) v);
6376 data [idx] = (byte) (val & 0xff);
6377 data [idx+1] = (byte) (val >> 8);
6379 } else if (element_type == TypeManager.short_type){
6380 if (!(v is Expression)){
6381 int val = (int) ((short) v);
6383 data [idx] = (byte) (val & 0xff);
6384 data [idx+1] = (byte) (val >> 8);
6386 } else if (element_type == TypeManager.ushort_type){
6387 if (!(v is Expression)){
6388 int val = (int) ((ushort) v);
6390 data [idx] = (byte) (val & 0xff);
6391 data [idx+1] = (byte) (val >> 8);
6393 } else if (element_type == TypeManager.int32_type) {
6394 if (!(v is Expression)){
6397 data [idx] = (byte) (val & 0xff);
6398 data [idx+1] = (byte) ((val >> 8) & 0xff);
6399 data [idx+2] = (byte) ((val >> 16) & 0xff);
6400 data [idx+3] = (byte) (val >> 24);
6402 } else if (element_type == TypeManager.uint32_type) {
6403 if (!(v is Expression)){
6404 uint val = (uint) v;
6406 data [idx] = (byte) (val & 0xff);
6407 data [idx+1] = (byte) ((val >> 8) & 0xff);
6408 data [idx+2] = (byte) ((val >> 16) & 0xff);
6409 data [idx+3] = (byte) (val >> 24);
6411 } else if (element_type == TypeManager.sbyte_type) {
6412 if (!(v is Expression)){
6413 sbyte val = (sbyte) v;
6414 data [idx] = (byte) val;
6416 } else if (element_type == TypeManager.byte_type) {
6417 if (!(v is Expression)){
6418 byte val = (byte) v;
6419 data [idx] = (byte) val;
6421 } else if (element_type == TypeManager.bool_type) {
6422 if (!(v is Expression)){
6423 bool val = (bool) v;
6424 data [idx] = (byte) (val ? 1 : 0);
6426 } else if (element_type == TypeManager.decimal_type){
6427 if (!(v is Expression)){
6428 int [] bits = Decimal.GetBits ((decimal) v);
6431 // FIXME: For some reason, this doesn't work on the MS runtime.
6432 int [] nbits = new int [4];
6433 nbits [0] = bits [3];
6434 nbits [1] = bits [2];
6435 nbits [2] = bits [0];
6436 nbits [3] = bits [1];
6438 for (int j = 0; j < 4; j++){
6439 data [p++] = (byte) (nbits [j] & 0xff);
6440 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6441 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6442 data [p++] = (byte) (nbits [j] >> 24);
6446 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6456 public override SLE.Expression MakeExpression (BuilderContext ctx)
6459 return base.MakeExpression (ctx);
6461 var initializers = new SLE.Expression [array_data.Count];
6462 for (var i = 0; i < initializers.Length; i++) {
6463 if (array_data [i] == null)
6464 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
6466 initializers [i] = array_data [i].MakeExpression (ctx);
6469 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
6475 // Emits the initializers for the array
6477 void EmitStaticInitializers (EmitContext ec)
6479 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6480 var helper = ec.CurrentTypeDefinition.Module.PredefinedTypes.RuntimeHelpers.Resolve (loc);
6484 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6485 helper, "InitializeArray", loc,
6486 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6487 if (TypeManager.void_initializearray_array_fieldhandle == null)
6492 // First, the static data
6494 byte [] data = MakeByteBlob ();
6495 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
6497 ec.Emit (OpCodes.Dup);
6498 ec.Emit (OpCodes.Ldtoken, fb);
6499 ec.Emit (OpCodes.Call, TypeManager.void_initializearray_array_fieldhandle);
6504 // Emits pieces of the array that can not be computed at compile
6505 // time (variables and string locations).
6507 // This always expect the top value on the stack to be the array
6509 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6511 int dims = bounds.Count;
6512 var current_pos = new int [dims];
6514 for (int i = 0; i < array_data.Count; i++){
6516 Expression e = array_data [i];
6517 var c = e as Constant;
6519 // Constant can be initialized via StaticInitializer
6520 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
6521 TypeSpec etype = e.Type;
6523 ec.Emit (OpCodes.Dup);
6525 for (int idx = 0; idx < dims; idx++)
6526 ec.EmitInt (current_pos [idx]);
6529 // If we are dealing with a struct, get the
6530 // address of it, so we can store it.
6532 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6533 (!TypeManager.IsBuiltinOrEnum (etype) ||
6534 etype == TypeManager.decimal_type)) {
6536 ec.Emit (OpCodes.Ldelema, etype);
6541 ec.EmitArrayStore ((ArrayContainer) type);
6547 for (int j = dims - 1; j >= 0; j--){
6549 if (current_pos [j] < bounds [j])
6551 current_pos [j] = 0;
6556 public override void Emit (EmitContext ec)
6558 if (first_emit != null) {
6559 first_emit.Emit (ec);
6560 first_emit_temp.Store (ec);
6563 foreach (Expression e in arguments)
6566 ec.EmitArrayNew ((ArrayContainer) type);
6568 if (initializers == null)
6572 // Emit static initializer for arrays which have contain more than 2 items and
6573 // the static initializer will initialize at least 25% of array values or there
6574 // is more than 10 items to be initialized
6575 // NOTE: const_initializers_count does not contain default constant values.
6576 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
6577 (TypeManager.IsPrimitiveType (array_element_type) || TypeManager.IsEnumType (array_element_type))) {
6578 EmitStaticInitializers (ec);
6580 if (!only_constant_initializers)
6581 EmitDynamicInitializers (ec, false);
6585 EmitDynamicInitializers (ec, true);
6588 if (first_emit_temp != null)
6589 first_emit_temp.Release (ec);
6592 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
6594 // no multi dimensional or jagged arrays
6595 if (arguments.Count != 1 || array_element_type.IsArray) {
6596 base.EncodeAttributeValue (rc, enc, targetType);
6600 // No array covariance, except for array -> object
6601 if (type != targetType) {
6602 if (targetType != TypeManager.object_type) {
6603 base.EncodeAttributeValue (rc, enc, targetType);
6607 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
6608 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
6613 // Single dimensional array of 0 size
6614 if (array_data == null) {
6615 IntConstant ic = arguments[0] as IntConstant;
6616 if (ic == null || !ic.IsDefaultValue) {
6617 base.EncodeAttributeValue (rc, enc, targetType);
6625 enc.Encode (array_data.Count);
6626 foreach (var element in array_data) {
6627 element.EncodeAttributeValue (rc, enc, array_element_type);
6631 protected override void CloneTo (CloneContext clonectx, Expression t)
6633 ArrayCreation target = (ArrayCreation) t;
6635 if (requested_base_type != null)
6636 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6638 if (arguments != null){
6639 target.arguments = new List<Expression> (arguments.Count);
6640 foreach (Expression e in arguments)
6641 target.arguments.Add (e.Clone (clonectx));
6644 if (initializers != null)
6645 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
6650 // Represents an implicitly typed array epxression
6652 class ImplicitlyTypedArrayCreation : ArrayCreation
6654 sealed class InferenceContext : TypeInferenceContext
6656 class ExpressionBoundInfo : BoundInfo
6658 readonly Expression expr;
6660 public ExpressionBoundInfo (Expression expr)
6661 : base (expr.Type, BoundKind.Lower)
6666 public override bool Equals (BoundInfo other)
6668 // We are using expression not type for conversion check
6669 // no optimization based on types is possible
6673 public override Expression GetTypeExpression ()
6679 public void AddExpression (Expression expr)
6681 AddToBounds (new ExpressionBoundInfo (expr), 0);
6685 InferenceContext best_type_inference;
6687 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6688 : base (null, rank, initializers, loc)
6692 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
6693 : base (null, initializers, loc)
6697 protected override Expression DoResolve (ResolveContext ec)
6702 dimensions = rank.Dimension;
6704 best_type_inference = new InferenceContext ();
6706 if (!ResolveInitializers (ec))
6709 best_type_inference.FixAllTypes (ec);
6710 array_element_type = best_type_inference.InferredTypeArguments[0];
6711 best_type_inference = null;
6713 if (array_element_type == null || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
6714 arguments.Count != rank.Dimension) {
6715 ec.Report.Error (826, loc,
6716 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6721 // At this point we found common base type for all initializer elements
6722 // but we have to be sure that all static initializer elements are of
6725 UnifyInitializerElement (ec);
6727 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
6728 eclass = ExprClass.Value;
6733 // Converts static initializer only
6735 void UnifyInitializerElement (ResolveContext ec)
6737 for (int i = 0; i < array_data.Count; ++i) {
6738 Expression e = array_data[i];
6740 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6744 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6746 element = element.Resolve (ec);
6747 if (element != null)
6748 best_type_inference.AddExpression (element);
6754 sealed class CompilerGeneratedThis : This
6756 public static This Instance = new CompilerGeneratedThis ();
6758 private CompilerGeneratedThis ()
6759 : base (Location.Null)
6763 public CompilerGeneratedThis (TypeSpec type, Location loc)
6769 protected override Expression DoResolve (ResolveContext ec)
6771 eclass = ExprClass.Variable;
6773 type = ec.CurrentType;
6778 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6785 /// Represents the `this' construct
6788 public class This : VariableReference
6790 sealed class ThisVariable : ILocalVariable
6792 public static readonly ILocalVariable Instance = new ThisVariable ();
6794 public void Emit (EmitContext ec)
6796 ec.Emit (OpCodes.Ldarg_0);
6799 public void EmitAssign (EmitContext ec)
6801 throw new InvalidOperationException ();
6804 public void EmitAddressOf (EmitContext ec)
6806 ec.Emit (OpCodes.Ldarg_0);
6810 VariableInfo variable_info;
6812 public This (Location loc)
6819 public override string Name {
6820 get { return "this"; }
6823 public override bool IsLockedByStatement {
6831 public override bool IsRef {
6832 get { return type.IsStruct; }
6835 protected override ILocalVariable Variable {
6836 get { return ThisVariable.Instance; }
6839 public override VariableInfo VariableInfo {
6840 get { return variable_info; }
6843 public override bool IsFixed {
6844 get { return false; }
6849 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
6851 if (variable_info != null && !variable_info.IsAssigned (rc)) {
6852 rc.Report.Error (188, loc,
6853 "The `this' object cannot be used before all of its fields are assigned to");
6857 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
6859 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6860 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6861 } else if (ec.CurrentAnonymousMethod != null) {
6862 ec.Report.Error (1673, loc,
6863 "Anonymous methods inside structs cannot access instance members of `this'. " +
6864 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6866 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6870 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6875 AnonymousMethodStorey storey = ae.Storey;
6876 while (storey != null) {
6877 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6879 return storey.HoistedThis;
6887 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
6889 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
6892 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
6895 if (TypeManager.IsStruct (ec.CurrentType) && ec.CurrentIterator == null)
6901 public virtual void ResolveBase (ResolveContext ec)
6903 eclass = ExprClass.Variable;
6904 type = ec.CurrentType;
6906 if (!IsThisAvailable (ec, false)) {
6907 Error_ThisNotAvailable (ec);
6911 var block = ec.CurrentBlock;
6912 if (block != null) {
6913 if (block.ParametersBlock.TopBlock.ThisVariable != null)
6914 variable_info = block.ParametersBlock.TopBlock.ThisVariable.VariableInfo;
6916 AnonymousExpression am = ec.CurrentAnonymousMethod;
6917 if (am != null && ec.IsVariableCapturingRequired) {
6918 am.SetHasThisAccess ();
6923 public override Expression CreateExpressionTree (ResolveContext ec)
6925 Arguments args = new Arguments (1);
6926 args.Add (new Argument (this));
6928 // Use typeless constant for ldarg.0 to save some
6929 // space and avoid problems with anonymous stories
6930 return CreateExpressionFactoryCall (ec, "Constant", args);
6933 protected override Expression DoResolve (ResolveContext ec)
6937 if (variable_info != null && type.IsStruct) {
6938 CheckStructThisDefiniteAssignment (ec);
6944 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6948 if (variable_info != null)
6949 variable_info.SetAssigned (ec);
6952 if (right_side == EmptyExpression.UnaryAddress)
6953 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6954 else if (right_side == EmptyExpression.OutAccess.Instance)
6955 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6957 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6963 public override int GetHashCode()
6965 throw new NotImplementedException ();
6968 public override bool Equals (object obj)
6970 This t = obj as This;
6977 protected override void CloneTo (CloneContext clonectx, Expression t)
6982 public override void SetHasAddressTaken ()
6989 /// Represents the `__arglist' construct
6991 public class ArglistAccess : Expression
6993 public ArglistAccess (Location loc)
6998 public override Expression CreateExpressionTree (ResolveContext ec)
7000 throw new NotSupportedException ("ET");
7003 protected override Expression DoResolve (ResolveContext ec)
7005 eclass = ExprClass.Variable;
7006 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve (loc);
7008 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7009 ec.Report.Error (190, loc,
7010 "The __arglist construct is valid only within a variable argument method");
7016 public override void Emit (EmitContext ec)
7018 ec.Emit (OpCodes.Arglist);
7021 protected override void CloneTo (CloneContext clonectx, Expression target)
7028 /// Represents the `__arglist (....)' construct
7030 public class Arglist : Expression
7032 Arguments Arguments;
7034 public Arglist (Location loc)
7039 public Arglist (Arguments args, Location l)
7045 public MetaType[] ArgumentTypes {
7047 if (Arguments == null)
7048 return MetaType.EmptyTypes;
7050 var retval = new MetaType[Arguments.Count];
7051 for (int i = 0; i < retval.Length; i++)
7052 retval[i] = Arguments[i].Expr.Type.GetMetaInfo ();
7058 public override Expression CreateExpressionTree (ResolveContext ec)
7060 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7064 protected override Expression DoResolve (ResolveContext ec)
7066 eclass = ExprClass.Variable;
7067 type = InternalType.Arglist;
7068 if (Arguments != null) {
7069 bool dynamic; // Can be ignored as there is always only 1 overload
7070 Arguments.Resolve (ec, out dynamic);
7076 public override void Emit (EmitContext ec)
7078 if (Arguments != null)
7079 Arguments.Emit (ec);
7082 protected override void CloneTo (CloneContext clonectx, Expression t)
7084 Arglist target = (Arglist) t;
7086 if (Arguments != null)
7087 target.Arguments = Arguments.Clone (clonectx);
7092 /// Implements the typeof operator
7094 public class TypeOf : Expression {
7095 FullNamedExpression QueriedType;
7098 public TypeOf (FullNamedExpression queried_type, Location l)
7100 QueriedType = queried_type;
7105 public TypeSpec TypeArgument {
7111 public FullNamedExpression TypeExpression {
7119 public override Expression CreateExpressionTree (ResolveContext ec)
7121 Arguments args = new Arguments (2);
7122 args.Add (new Argument (this));
7123 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7124 return CreateExpressionFactoryCall (ec, "Constant", args);
7127 protected override Expression DoResolve (ResolveContext ec)
7132 // Pointer types are allowed without explicit unsafe, they are just tokens
7134 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
7135 texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7141 typearg = texpr.Type;
7143 if (typearg == TypeManager.void_type && !(QueriedType is TypeExpression)) {
7144 ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
7145 } else if (texpr is DynamicTypeExpr) {
7146 ec.Report.Error (1962, QueriedType.Location,
7147 "The typeof operator cannot be used on the dynamic type");
7150 type = TypeManager.type_type;
7151 QueriedType = texpr;
7153 return DoResolveBase ();
7156 protected Expression DoResolveBase ()
7158 if (TypeManager.system_type_get_type_from_handle == null) {
7159 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
7160 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
7163 // Even though what is returned is a type object, it's treated as a value by the compiler.
7164 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7165 eclass = ExprClass.Value;
7169 static bool ContainsDynamicType (TypeSpec type)
7171 if (type == InternalType.Dynamic)
7174 var element_container = type as ElementTypeSpec;
7175 if (element_container != null)
7176 return ContainsDynamicType (element_container.Element);
7178 foreach (var t in type.TypeArguments) {
7179 if (ContainsDynamicType (t)) {
7187 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7189 // Target type is not System.Type therefore must be object
7190 // and we need to use different encoding sequence
7191 if (targetType != type)
7194 if (!(QueriedType is GenericOpenTypeExpr)) {
7196 while (gt != null) {
7197 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
7198 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7199 typearg.GetSignatureForError ());
7203 gt = gt.DeclaringType;
7206 if (ContainsDynamicType (typearg)) {
7207 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7212 enc.EncodeTypeName (typearg);
7215 public override void Emit (EmitContext ec)
7217 ec.Emit (OpCodes.Ldtoken, typearg);
7218 ec.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
7221 protected override void CloneTo (CloneContext clonectx, Expression t)
7223 TypeOf target = (TypeOf) t;
7224 if (QueriedType != null)
7225 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
7229 class TypeOfMethod : TypeOfMember<MethodSpec>
7231 public TypeOfMethod (MethodSpec method, Location loc)
7232 : base (method, loc)
7236 protected override Expression DoResolve (ResolveContext ec)
7238 if (member.IsConstructor) {
7239 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve (loc);
7241 type = ec.Module.PredefinedTypes.MethodInfo.Resolve (loc);
7247 return base.DoResolve (ec);
7250 public override void Emit (EmitContext ec)
7252 ec.Emit (OpCodes.Ldtoken, member);
7255 ec.Emit (OpCodes.Castclass, type);
7258 protected override string GetMethodName {
7259 get { return "GetMethodFromHandle"; }
7262 protected override PredefinedType GetDeclaringType (PredefinedTypes types)
7264 return types.MethodBase;
7267 protected override PredefinedType GetRuntimeHandle (PredefinedTypes types)
7269 return types.RuntimeMethodHandle;
7272 protected override MethodSpec TypeFromHandle {
7274 return TypeManager.methodbase_get_type_from_handle;
7277 TypeManager.methodbase_get_type_from_handle = value;
7281 protected override MethodSpec TypeFromHandleGeneric {
7283 return TypeManager.methodbase_get_type_from_handle_generic;
7286 TypeManager.methodbase_get_type_from_handle_generic = value;
7291 abstract class TypeOfMember<T> : Expression where T : MemberSpec
7293 protected readonly T member;
7295 protected TypeOfMember (T member, Location loc)
7297 this.member = member;
7301 public override Expression CreateExpressionTree (ResolveContext ec)
7303 Arguments args = new Arguments (2);
7304 args.Add (new Argument (this));
7305 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7306 return CreateExpressionFactoryCall (ec, "Constant", args);
7309 protected override Expression DoResolve (ResolveContext ec)
7311 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
7312 var mi = is_generic ? TypeFromHandleGeneric : TypeFromHandle;
7315 TypeSpec declaring_type = GetDeclaringType (ec.Module.PredefinedTypes).Resolve (loc);
7316 TypeSpec handle_type = GetRuntimeHandle (ec.Module.PredefinedTypes).Resolve (loc);
7318 if (handle_type == null || declaring_type == null)
7321 mi = TypeManager.GetPredefinedMethod (declaring_type, GetMethodName, loc,
7323 new TypeSpec[] { handle_type, TypeManager.runtime_handle_type } :
7324 new TypeSpec[] { handle_type } );
7327 TypeFromHandleGeneric = mi;
7329 TypeFromHandle = mi;
7332 eclass = ExprClass.Value;
7336 public override void Emit (EmitContext ec)
7338 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
7341 mi = TypeFromHandleGeneric;
7342 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
7344 mi = TypeFromHandle;
7347 ec.Emit (OpCodes.Call, mi);
7350 protected abstract PredefinedType GetDeclaringType (PredefinedTypes types);
7351 protected abstract string GetMethodName { get; }
7352 protected abstract PredefinedType GetRuntimeHandle (PredefinedTypes types);
7353 protected abstract MethodSpec TypeFromHandle { get; set; }
7354 protected abstract MethodSpec TypeFromHandleGeneric { get; set; }
7357 class TypeOfField : TypeOfMember<FieldSpec>
7359 public TypeOfField (FieldSpec field, Location loc)
7364 protected override Expression DoResolve (ResolveContext ec)
7366 type = ec.Module.PredefinedTypes.FieldInfo.Resolve (loc);
7370 return base.DoResolve (ec);
7373 public override void Emit (EmitContext ec)
7375 ec.Emit (OpCodes.Ldtoken, member);
7379 protected override PredefinedType GetDeclaringType (PredefinedTypes types)
7381 return types.FieldInfo;
7384 protected override string GetMethodName {
7385 get { return "GetFieldFromHandle"; }
7388 protected override PredefinedType GetRuntimeHandle (PredefinedTypes types)
7390 return types.RuntimeFieldHandle;
7393 protected override MethodSpec TypeFromHandle {
7395 return TypeManager.fieldinfo_get_field_from_handle;
7398 TypeManager.fieldinfo_get_field_from_handle = value;
7402 protected override MethodSpec TypeFromHandleGeneric {
7404 return TypeManager.fieldinfo_get_field_from_handle_generic;
7407 TypeManager.fieldinfo_get_field_from_handle_generic = value;
7413 /// Implements the sizeof expression
7415 public class SizeOf : Expression {
7416 readonly Expression QueriedType;
7417 TypeSpec type_queried;
7419 public SizeOf (Expression queried_type, Location l)
7421 this.QueriedType = queried_type;
7425 public override Expression CreateExpressionTree (ResolveContext ec)
7427 Error_PointerInsideExpressionTree (ec);
7431 protected override Expression DoResolve (ResolveContext ec)
7433 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7437 type_queried = texpr.Type;
7438 if (TypeManager.IsEnumType (type_queried))
7439 type_queried = EnumSpec.GetUnderlyingType (type_queried);
7441 int size_of = GetTypeSize (type_queried);
7443 return new IntConstant (size_of, loc).Resolve (ec);
7446 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
7451 ec.Report.Error (233, loc,
7452 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7453 TypeManager.CSharpName (type_queried));
7456 type = TypeManager.int32_type;
7457 eclass = ExprClass.Value;
7461 public override void Emit (EmitContext ec)
7463 ec.Emit (OpCodes.Sizeof, type_queried);
7466 protected override void CloneTo (CloneContext clonectx, Expression t)
7472 /// Implements the qualified-alias-member (::) expression.
7474 public class QualifiedAliasMember : MemberAccess
7476 readonly string alias;
7477 public static readonly string GlobalAlias = "global";
7479 public QualifiedAliasMember (string alias, string identifier, Location l)
7480 : base (null, identifier, l)
7485 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7486 : base (null, identifier, targs, l)
7491 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
7492 : base (null, identifier, arity, l)
7497 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7499 if (alias == GlobalAlias) {
7500 expr = ec.Module.GlobalRootNamespace;
7501 return base.ResolveAsTypeStep (ec, silent);
7504 int errors = ec.Module.Compiler.Report.Errors;
7505 expr = ec.LookupNamespaceAlias (alias);
7507 if (errors == ec.Module.Compiler.Report.Errors)
7508 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7512 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7516 if (expr.eclass == ExprClass.Type) {
7518 ec.Module.Compiler.Report.Error (431, loc,
7519 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7527 protected override Expression DoResolve (ResolveContext ec)
7529 return ResolveAsTypeStep (ec, false);
7532 protected override void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7534 rc.Module.Compiler.Report.Error (687, loc,
7535 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7536 GetSignatureForError ());
7539 public override string GetSignatureForError ()
7542 if (targs != null) {
7543 name = Name + "<" + targs.GetSignatureForError () + ">";
7546 return alias + "::" + name;
7549 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7551 return DoResolve (rc);
7554 protected override void CloneTo (CloneContext clonectx, Expression t)
7561 /// Implements the member access expression
7563 public class MemberAccess : ATypeNameExpression
7565 protected Expression expr;
7567 public MemberAccess (Expression expr, string id)
7568 : base (id, expr.Location)
7573 public MemberAccess (Expression expr, string identifier, Location loc)
7574 : base (identifier, loc)
7579 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7580 : base (identifier, args, loc)
7585 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
7586 : base (identifier, arity, loc)
7591 public Expression LeftExpression {
7597 protected override Expression DoResolve (ResolveContext ec)
7599 return DoResolveName (ec, null);
7602 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7604 return DoResolveName (ec, right_side);
7607 Expression DoResolveName (ResolveContext rc, Expression right_side)
7609 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
7613 if (right_side != null) {
7614 if (e is TypeExpr) {
7615 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
7619 e = e.ResolveLValue (rc, right_side);
7621 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
7627 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7629 var sn = expr as SimpleName;
7630 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
7633 // Resolve the expression with flow analysis turned off, we'll do the definite
7634 // assignment checks later. This is because we don't know yet what the expression
7635 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7636 // definite assignment check on the actual field and not on the whole struct.
7638 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
7640 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
7642 // Call resolve on expression which does have type set as we need expression type
7643 // TODO: I should probably ensure that the type is always set and leave resolve for the final
7644 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
7645 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
7646 expr = expr.Resolve (rc);
7648 } else if (expr is TypeParameterExpr) {
7649 expr.Error_UnexpectedKind (rc, flags, sn.Location);
7653 expr = expr.Resolve (rc, flags);
7660 Namespace ns = expr as Namespace;
7662 FullNamedExpression retval = ns.Lookup (rc, Name, Arity, loc);
7664 if (retval == null) {
7665 ns.Error_NamespaceDoesNotExist (loc, Name, Arity, rc);
7669 if (HasTypeArguments)
7670 return new GenericTypeExpr (retval.Type, targs, loc);
7676 TypeSpec expr_type = expr.Type;
7677 if (expr_type == InternalType.Dynamic) {
7678 me = expr as MemberExpr;
7680 me.ResolveInstanceExpression (rc, null);
7682 Arguments args = new Arguments (1);
7683 args.Add (new Argument (expr));
7684 return new DynamicMemberBinder (Name, args, loc);
7687 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
7688 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
7690 if ((expr_type.Kind & dot_kinds) == 0 || expr_type == TypeManager.void_type) {
7691 if (expr_type == InternalType.Null && rc.IsRuntimeBinder)
7692 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
7694 Unary.Error_OperatorCannotBeApplied (rc, loc, ".", expr_type);
7698 var current_type = rc.CurrentType;
7699 var lookup_arity = Arity;
7700 bool errorMode = false;
7701 Expression member_lookup;
7703 member_lookup = MemberLookup (errorMode ? null : rc, current_type, expr_type, Name, lookup_arity, restrictions, loc);
7704 if (member_lookup == null) {
7706 // Try to look for extension method when member lookup failed
7708 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
7709 NamespaceEntry scope = null;
7710 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity, ref scope);
7711 if (methods != null) {
7712 var emg = new ExtensionMethodGroupExpr (methods, scope, expr, loc);
7713 if (HasTypeArguments) {
7714 if (!targs.Resolve (rc))
7717 emg.SetTypeArguments (rc, targs);
7720 // TODO: it should really skip the checks bellow
7721 return emg.Resolve (rc);
7727 if (member_lookup == null) {
7728 if (expr is TypeExpr)
7729 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
7731 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
7736 if (member_lookup is MethodGroupExpr) {
7737 // Leave it to overload resolution to report correct error
7739 // TODO: rc.SymbolRelatedToPreviousError
7740 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
7745 if (member_lookup != null)
7748 current_type = null;
7750 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
7754 TypeExpr texpr = member_lookup as TypeExpr;
7755 if (texpr != null) {
7756 if (!(expr is TypeExpr)) {
7757 me = expr as MemberExpr;
7758 if (me == null || me.ProbeIdenticalTypeName (rc, expr, sn) == expr) {
7759 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7760 Name, member_lookup.GetSignatureForError ());
7765 if (!texpr.Type.IsAccessible (rc.CurrentType)) {
7766 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
7767 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
7771 if (HasTypeArguments) {
7772 return new GenericTypeExpr (member_lookup.Type, targs, loc);
7775 return member_lookup;
7778 me = member_lookup as MemberExpr;
7780 if (sn != null && me.IsStatic)
7781 expr = me.ProbeIdenticalTypeName (rc, expr, sn);
7783 me = me.ResolveMemberAccess (rc, expr, sn);
7786 if (!targs.Resolve (rc))
7789 me.SetTypeArguments (rc, targs);
7792 if (sn != null && (!TypeManager.IsValueType (expr_type) || me is PropertyExpr)) {
7793 if (me.IsInstance) {
7794 LocalVariableReference var = expr as LocalVariableReference;
7795 if (var != null && !var.VerifyAssigned (rc))
7803 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7805 return ResolveNamespaceOrType (ec, silent);
7808 public FullNamedExpression ResolveNamespaceOrType (IMemberContext rc, bool silent)
7810 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7812 if (expr_resolved == null)
7815 Namespace ns = expr_resolved as Namespace;
7817 FullNamedExpression retval = ns.Lookup (rc, Name, Arity, loc);
7819 if (retval == null) {
7821 ns.Error_NamespaceDoesNotExist (loc, Name, Arity, rc);
7822 } else if (HasTypeArguments) {
7823 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7829 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7830 if (tnew_expr == null)
7833 TypeSpec expr_type = tnew_expr.Type;
7834 if (TypeManager.IsGenericParameter (expr_type)) {
7835 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7836 tnew_expr.GetSignatureForError ());
7840 TypeSpec nested = null;
7841 while (expr_type != null) {
7842 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7843 if (nested == null) {
7847 if (expr_type == tnew_expr.Type) {
7848 Error_IdentifierNotFound (rc, expr_type, Name);
7852 expr_type = tnew_expr.Type;
7853 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7854 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
7858 if (nested.IsAccessible (rc.CurrentType))
7861 // Keep looking after inaccessible candidate
7862 expr_type = nested.DeclaringType.BaseType;
7867 if (HasTypeArguments) {
7868 texpr = new GenericTypeExpr (nested, targs, loc);
7870 texpr = new GenericOpenTypeExpr (nested, loc);
7873 texpr = new TypeExpression (nested, loc);
7876 return texpr.ResolveAsTypeStep (rc, false);
7879 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7881 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
7883 if (nested != null) {
7884 Error_TypeArgumentsCannotBeUsed (rc.Module.Compiler.Report, expr.Location, nested, Arity);
7888 var any_other_member = MemberLookup (null, rc.CurrentType, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
7889 if (any_other_member != null) {
7890 any_other_member.Error_UnexpectedKind (rc.Module.Compiler.Report, null, "type", loc);
7894 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7895 Name, expr_type.GetSignatureForError ());
7898 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
7900 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
7901 ec.Report.SymbolRelatedToPreviousError (type);
7902 ec.Report.Error (1061, loc,
7903 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found (are you missing a using directive or an assembly reference?)",
7904 type.GetSignatureForError (), name);
7908 base.Error_TypeDoesNotContainDefinition (ec, type, name);
7911 public override string GetSignatureForError ()
7913 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7916 protected override void CloneTo (CloneContext clonectx, Expression t)
7918 MemberAccess target = (MemberAccess) t;
7920 target.expr = expr.Clone (clonectx);
7925 /// Implements checked expressions
7927 public class CheckedExpr : Expression {
7929 public Expression Expr;
7931 public CheckedExpr (Expression e, Location l)
7937 public override Expression CreateExpressionTree (ResolveContext ec)
7939 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7940 return Expr.CreateExpressionTree (ec);
7943 protected override Expression DoResolve (ResolveContext ec)
7945 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7946 Expr = Expr.Resolve (ec);
7951 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7954 eclass = Expr.eclass;
7959 public override void Emit (EmitContext ec)
7961 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7965 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7967 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7968 Expr.EmitBranchable (ec, target, on_true);
7971 public override SLE.Expression MakeExpression (BuilderContext ctx)
7973 using (ctx.With (BuilderContext.Options.AllCheckStateFlags, true)) {
7974 return Expr.MakeExpression (ctx);
7978 protected override void CloneTo (CloneContext clonectx, Expression t)
7980 CheckedExpr target = (CheckedExpr) t;
7982 target.Expr = Expr.Clone (clonectx);
7987 /// Implements the unchecked expression
7989 public class UnCheckedExpr : Expression {
7991 public Expression Expr;
7993 public UnCheckedExpr (Expression e, Location l)
7999 public override Expression CreateExpressionTree (ResolveContext ec)
8001 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8002 return Expr.CreateExpressionTree (ec);
8005 protected override Expression DoResolve (ResolveContext ec)
8007 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8008 Expr = Expr.Resolve (ec);
8013 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8016 eclass = Expr.eclass;
8021 public override void Emit (EmitContext ec)
8023 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
8027 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8029 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
8030 Expr.EmitBranchable (ec, target, on_true);
8033 protected override void CloneTo (CloneContext clonectx, Expression t)
8035 UnCheckedExpr target = (UnCheckedExpr) t;
8037 target.Expr = Expr.Clone (clonectx);
8042 /// An Element Access expression.
8044 /// During semantic analysis these are transformed into
8045 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
8047 public class ElementAccess : Expression {
8048 public Arguments Arguments;
8049 public Expression Expr;
8051 public ElementAccess (Expression e, Arguments args, Location loc)
8055 this.Arguments = args;
8059 // We perform some simple tests, and then to "split" the emit and store
8060 // code we create an instance of a different class, and return that.
8062 Expression CreateAccessExpression (ResolveContext ec)
8065 return (new ArrayAccess (this, loc));
8068 return MakePointerAccess (ec, type);
8070 FieldExpr fe = Expr as FieldExpr;
8072 var ff = fe.Spec as FixedFieldSpec;
8074 return MakePointerAccess (ec, ff.ElementType);
8078 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
8079 if (indexers != null || type == InternalType.Dynamic) {
8080 return new IndexerExpr (indexers, type, this);
8083 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8084 type.GetSignatureForError ());
8088 public override Expression CreateExpressionTree (ResolveContext ec)
8090 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
8091 Expr.CreateExpressionTree (ec));
8093 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
8096 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
8098 if (Arguments.Count != 1){
8099 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
8103 if (Arguments [0] is NamedArgument)
8104 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
8106 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
8107 return new Indirection (p, loc);
8110 protected override Expression DoResolve (ResolveContext ec)
8112 Expr = Expr.Resolve (ec);
8118 // TODO: Create 1 result for Resolve and ResolveLValue ?
8119 var res = CreateAccessExpression (ec);
8123 return res.Resolve (ec);
8126 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8128 Expr = Expr.Resolve (ec);
8134 var res = CreateAccessExpression (ec);
8138 return res.ResolveLValue (ec, right_side);
8141 public override void Emit (EmitContext ec)
8143 throw new Exception ("Should never be reached");
8146 public static void Error_NamedArgument (NamedArgument na, Report Report)
8148 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
8151 public override string GetSignatureForError ()
8153 return Expr.GetSignatureForError ();
8156 protected override void CloneTo (CloneContext clonectx, Expression t)
8158 ElementAccess target = (ElementAccess) t;
8160 target.Expr = Expr.Clone (clonectx);
8161 if (Arguments != null)
8162 target.Arguments = Arguments.Clone (clonectx);
8167 /// Implements array access
8169 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
8171 // Points to our "data" repository
8175 LocalTemporary temp, expr_copy;
8176 Expression[] prepared_arguments;
8179 public ArrayAccess (ElementAccess ea_data, Location l)
8185 public override Expression CreateExpressionTree (ResolveContext ec)
8187 return ea.CreateExpressionTree (ec);
8190 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8192 return DoResolve (ec);
8195 protected override Expression DoResolve (ResolveContext ec)
8197 // dynamic is used per argument in ConvertExpressionToArrayIndex case
8199 ea.Arguments.Resolve (ec, out dynamic);
8201 var ac = ea.Expr.Type as ArrayContainer;
8202 int rank = ea.Arguments.Count;
8203 if (ac.Rank != rank) {
8204 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8205 rank.ToString (), ac.Rank.ToString ());
8210 if (type.IsPointer && !ec.IsUnsafe) {
8211 UnsafeError (ec, ea.Location);
8214 foreach (Argument a in ea.Arguments) {
8215 if (a is NamedArgument)
8216 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
8218 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
8221 eclass = ExprClass.Variable;
8226 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8228 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8232 // Load the array arguments into the stack.
8234 void LoadArrayAndArguments (EmitContext ec)
8237 ea.Arguments.Emit (ec);
8240 public void Emit (EmitContext ec, bool leave_copy)
8242 var ac = ea.Expr.Type as ArrayContainer;
8245 ec.EmitLoadFromPtr (type);
8247 if (prepared_arguments == null) {
8248 LoadArrayAndArguments (ec);
8250 expr_copy.Emit (ec);
8252 foreach (var expr in prepared_arguments) {
8254 lt = expr as LocalTemporary;
8260 ec.EmitArrayLoad (ac);
8264 ec.Emit (OpCodes.Dup);
8265 temp = new LocalTemporary (this.type);
8270 public override void Emit (EmitContext ec)
8275 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8277 var ac = (ArrayContainer) ea.Expr.Type;
8278 TypeSpec t = source.Type;
8281 // When we are dealing with a struct, get the address of it to avoid value copy
8282 // Same cannot be done for reference type because array covariance and the
8283 // check in ldelema requires to specify the type of array element stored at the index
8285 if (t.IsStruct && ((prepare_for_load && !(source is DynamicExpressionStatement)) || !TypeManager.IsPrimitiveType (t))) {
8286 LoadArrayAndArguments (ec);
8287 ec.EmitArrayAddress (ac);
8289 if (prepare_for_load) {
8290 ec.Emit (OpCodes.Dup);
8294 } else if (prepare_for_load) {
8296 ec.Emit (OpCodes.Dup);
8298 expr_copy = new LocalTemporary (ea.Expr.Type);
8299 expr_copy.Store (ec);
8300 prepared_arguments = ea.Arguments.Emit (ec, true);
8302 LoadArrayAndArguments (ec);
8307 if (expr_copy != null) {
8308 expr_copy.Release (ec);
8312 ec.Emit (OpCodes.Dup);
8313 temp = new LocalTemporary (this.type);
8318 ec.EmitStoreFromPtr (t);
8320 ec.EmitArrayStore (ac);
8329 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8331 if (!source.Emit (ec, this)) {
8333 throw new NotImplementedException ();
8338 throw new NotImplementedException ();
8341 public void AddressOf (EmitContext ec, AddressOp mode)
8343 var ac = (ArrayContainer) ea.Expr.Type;
8345 LoadArrayAndArguments (ec);
8346 ec.EmitArrayAddress (ac);
8349 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8352 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8354 throw new NotImplementedException ();
8358 public override SLE.Expression MakeExpression (BuilderContext ctx)
8360 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8363 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
8365 using (ctx.With (BuilderContext.Options.AllCheckStateFlags, true)) {
8366 return Arguments.MakeExpression (ea.Arguments, ctx);
8372 // Indexer access expression
8374 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
8376 LocalTemporary prepared_value;
8377 IList<MemberSpec> indexers;
8378 Arguments arguments;
8379 TypeSpec queried_type;
8381 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
8382 : base (ea.Location)
8384 this.indexers = indexers;
8385 this.queried_type = queriedType;
8386 this.InstanceExpression = ea.Expr;
8387 this.arguments = ea.Arguments;
8391 protected override TypeSpec DeclaringType {
8393 return best_candidate.DeclaringType;
8397 public override bool IsInstance {
8403 public override bool IsStatic {
8409 public override string Name {
8417 public override Expression CreateExpressionTree (ResolveContext ec)
8419 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8420 InstanceExpression.CreateExpressionTree (ec),
8421 new TypeOfMethod (Getter, loc));
8423 return CreateExpressionFactoryCall (ec, "Call", args);
8426 public override void Emit (EmitContext ec, bool leave_copy)
8429 prepared_value.Emit (ec);
8431 Invocation.EmitCall (ec, InstanceExpression, Getter, arguments, loc);
8435 ec.Emit (OpCodes.Dup);
8436 temp = new LocalTemporary (Type);
8441 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8443 prepared = prepare_for_load;
8444 Expression value = source;
8447 Invocation.EmitCall (ec, InstanceExpression, Getter, arguments, loc, true, false);
8449 prepared_value = new LocalTemporary (type);
8450 prepared_value.Store (ec);
8452 prepared_value.Release (ec);
8455 ec.Emit (OpCodes.Dup);
8456 temp = new LocalTemporary (Type);
8459 } else if (leave_copy) {
8460 temp = new LocalTemporary (Type);
8467 arguments.Add (new Argument (value));
8469 Invocation.EmitCall (ec, InstanceExpression, Setter, arguments, loc, false, prepared);
8477 public override string GetSignatureForError ()
8479 return best_candidate.GetSignatureForError ();
8482 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8485 throw new NotSupportedException ();
8487 var value = new[] { source.MakeExpression (ctx) };
8488 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
8490 return SLE.Expression.Block (
8491 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
8494 return args.First ();
8499 public override SLE.Expression MakeExpression (BuilderContext ctx)
8502 return base.MakeExpression (ctx);
8504 var args = Arguments.MakeExpression (arguments, ctx);
8505 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
8509 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
8511 if (best_candidate != null)
8514 eclass = ExprClass.IndexerAccess;
8517 arguments.Resolve (rc, out dynamic);
8519 if (indexers == null && InstanceExpression.Type == InternalType.Dynamic) {
8522 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
8523 res.BaseMembersProvider = this;
8525 // TODO: Do I need 2 argument sets?
8526 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
8527 if (best_candidate != null)
8528 type = res.BestCandidateReturnType;
8529 else if (!res.BestCandidateIsDynamic)
8534 // It has dynamic arguments
8537 Arguments args = new Arguments (arguments.Count + 1);
8539 rc.Report.Error (1972, loc,
8540 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8542 args.Add (new Argument (InstanceExpression));
8544 args.AddRange (arguments);
8546 best_candidate = null;
8547 return new DynamicIndexBinder (args, loc);
8550 ResolveInstanceExpression (rc, right_side);
8551 CheckProtectedMemberAccess (rc, best_candidate);
8555 protected override void CloneTo (CloneContext clonectx, Expression t)
8557 IndexerExpr target = (IndexerExpr) t;
8559 if (arguments != null)
8560 target.arguments = arguments.Clone (clonectx);
8563 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
8565 Error_TypeArgumentsCannotBeUsed (ec.Report, "indexer", GetSignatureForError (), loc);
8568 #region IBaseMembersProvider Members
8570 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
8572 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
8575 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
8577 if (queried_type == member.DeclaringType)
8580 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
8581 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
8584 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
8593 // A base access expression
8595 public class BaseThis : This
8597 public BaseThis (Location loc)
8602 public BaseThis (TypeSpec type, Location loc)
8606 eclass = ExprClass.Variable;
8611 public override string Name {
8619 public override Expression CreateExpressionTree (ResolveContext ec)
8621 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
8622 return base.CreateExpressionTree (ec);
8625 public override void Emit (EmitContext ec)
8629 var context_type = ec.CurrentType;
8630 if (context_type.IsStruct) {
8631 ec.Emit (OpCodes.Ldobj, context_type);
8632 ec.Emit (OpCodes.Box, context_type);
8636 protected override void Error_ThisNotAvailable (ResolveContext ec)
8639 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
8641 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
8645 public override void ResolveBase (ResolveContext ec)
8647 base.ResolveBase (ec);
8648 type = ec.CurrentType.BaseType;
8653 /// This class exists solely to pass the Type around and to be a dummy
8654 /// that can be passed to the conversion functions (this is used by
8655 /// foreach implementation to typecast the object return value from
8656 /// get_Current into the proper type. All code has been generated and
8657 /// we only care about the side effect conversions to be performed
8659 /// This is also now used as a placeholder where a no-action expression
8660 /// is needed (the `New' class).
8662 public class EmptyExpression : Expression {
8663 public static readonly Expression Null = new EmptyExpression ();
8665 public class OutAccess : EmptyExpression
8667 public static readonly OutAccess Instance = new OutAccess ();
8669 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8671 rc.Report.Error (206, right_side.Location,
8672 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
8678 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8679 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8680 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8681 public static readonly EmptyExpression EventAddition = new EmptyExpression ();
8682 public static readonly EmptyExpression EventSubtraction = new EmptyExpression ();
8683 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
8685 static EmptyExpression temp = new EmptyExpression ();
8686 public static EmptyExpression Grab ()
8688 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8693 public static void Release (EmptyExpression e)
8700 // FIXME: Don't set to object
8701 type = TypeManager.object_type;
8702 eclass = ExprClass.Value;
8703 loc = Location.Null;
8706 public EmptyExpression (TypeSpec t)
8709 eclass = ExprClass.Value;
8710 loc = Location.Null;
8713 public override Expression CreateExpressionTree (ResolveContext ec)
8715 throw new NotSupportedException ("ET");
8718 protected override Expression DoResolve (ResolveContext ec)
8723 public override void Emit (EmitContext ec)
8725 // nothing, as we only exist to not do anything.
8728 public override void EmitSideEffect (EmitContext ec)
8733 // This is just because we might want to reuse this bad boy
8734 // instead of creating gazillions of EmptyExpressions.
8735 // (CanImplicitConversion uses it)
8737 public void SetType (TypeSpec t)
8744 // Empty statement expression
8746 public sealed class EmptyExpressionStatement : ExpressionStatement
8748 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8750 private EmptyExpressionStatement ()
8752 loc = Location.Null;
8755 public override Expression CreateExpressionTree (ResolveContext ec)
8760 public override void EmitStatement (EmitContext ec)
8765 protected override Expression DoResolve (ResolveContext ec)
8767 eclass = ExprClass.Value;
8768 type = TypeManager.object_type;
8772 public override void Emit (EmitContext ec)
8778 public class UserCast : Expression {
8782 public UserCast (MethodSpec method, Expression source, Location l)
8784 this.method = method;
8785 this.source = source;
8786 type = method.ReturnType;
8790 public Expression Source {
8796 public override Expression CreateExpressionTree (ResolveContext ec)
8798 Arguments args = new Arguments (3);
8799 args.Add (new Argument (source.CreateExpressionTree (ec)));
8800 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8801 args.Add (new Argument (new TypeOfMethod (method, loc)));
8802 return CreateExpressionFactoryCall (ec, "Convert", args);
8805 protected override Expression DoResolve (ResolveContext ec)
8807 ObsoleteAttribute oa = method.GetAttributeObsolete ();
8809 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
8811 eclass = ExprClass.Value;
8815 public override void Emit (EmitContext ec)
8818 ec.Emit (OpCodes.Call, method);
8821 public override string GetSignatureForError ()
8823 return TypeManager.CSharpSignature (method);
8826 public override SLE.Expression MakeExpression (BuilderContext ctx)
8829 return base.MakeExpression (ctx);
8831 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
8837 // Holds additional type specifiers like ?, *, []
8839 public class ComposedTypeSpecifier
8841 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
8843 public readonly int Dimension;
8844 public readonly Location Location;
8846 public ComposedTypeSpecifier (int specifier, Location loc)
8848 this.Dimension = specifier;
8849 this.Location = loc;
8853 public bool IsNullable {
8855 return Dimension == -1;
8859 public bool IsPointer {
8861 return Dimension == -2;
8865 public ComposedTypeSpecifier Next { get; set; }
8869 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
8871 return new ComposedTypeSpecifier (dimension, loc);
8874 public static ComposedTypeSpecifier CreateNullable (Location loc)
8876 return new ComposedTypeSpecifier (-1, loc);
8879 public static ComposedTypeSpecifier CreatePointer (Location loc)
8881 return new ComposedTypeSpecifier (-2, loc);
8884 public string GetSignatureForError ()
8889 ArrayContainer.GetPostfixSignature (Dimension);
8891 return Next != null ? s + Next.GetSignatureForError () : s;
8896 // This class is used to "construct" the type during a typecast
8897 // operation. Since the Type.GetType class in .NET can parse
8898 // the type specification, we just use this to construct the type
8899 // one bit at a time.
8901 public class ComposedCast : TypeExpr {
8902 FullNamedExpression left;
8903 ComposedTypeSpecifier spec;
8905 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
8908 throw new ArgumentNullException ("spec");
8912 this.loc = spec.Location;
8915 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
8917 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8922 eclass = ExprClass.Type;
8924 var single_spec = spec;
8926 if (single_spec.IsNullable) {
8927 lexpr = new Nullable.NullableType (lexpr, loc);
8928 lexpr = lexpr.ResolveAsTypeTerminal (ec, false);
8932 single_spec = single_spec.Next;
8933 } else if (single_spec.IsPointer) {
8934 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
8938 UnsafeError (ec.Module.Compiler.Report, loc);
8942 type = PointerContainer.MakeType (type);
8943 single_spec = single_spec.Next;
8944 } while (single_spec != null && single_spec.IsPointer);
8947 if (single_spec != null && single_spec.Dimension > 0) {
8948 if (TypeManager.IsSpecialType (type)) {
8949 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
8950 } else if (type.IsStatic) {
8951 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
8952 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8953 type.GetSignatureForError ());
8955 MakeArray (ec.Module, single_spec);
8962 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
8964 if (spec.Next != null)
8965 MakeArray (module, spec.Next);
8967 type = ArrayContainer.MakeType (module, type, spec.Dimension);
8970 public override string GetSignatureForError ()
8972 return left.GetSignatureForError () + spec.GetSignatureForError ();
8976 public class FixedBufferPtr : Expression {
8979 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
8984 type = PointerContainer.MakeType (array_type);
8985 eclass = ExprClass.Value;
8988 public override Expression CreateExpressionTree (ResolveContext ec)
8990 Error_PointerInsideExpressionTree (ec);
8994 public override void Emit(EmitContext ec)
8999 protected override Expression DoResolve (ResolveContext ec)
9002 // We are born fully resolved
9010 // This class is used to represent the address of an array, used
9011 // only by the Fixed statement, this generates "&a [0]" construct
9012 // for fixed (char *pa = a)
9014 public class ArrayPtr : FixedBufferPtr {
9015 TypeSpec array_type;
9017 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
9018 base (array, array_type, l)
9020 this.array_type = array_type;
9023 public override void Emit (EmitContext ec)
9028 ec.Emit (OpCodes.Ldelema, array_type);
9033 // Encapsulates a conversion rules required for array indexes
9035 public class ArrayIndexCast : TypeCast
9037 public ArrayIndexCast (Expression expr)
9038 : base (expr, TypeManager.int32_type)
9040 if (expr.Type == TypeManager.int32_type)
9041 throw new ArgumentException ("unnecessary array index conversion");
9044 public override Expression CreateExpressionTree (ResolveContext ec)
9046 using (ec.Set (ResolveContext.Options.CheckedScope)) {
9047 return base.CreateExpressionTree (ec);
9051 public override void Emit (EmitContext ec)
9055 var expr_type = child.Type;
9057 if (expr_type == TypeManager.uint32_type)
9058 ec.Emit (OpCodes.Conv_U);
9059 else if (expr_type == TypeManager.int64_type)
9060 ec.Emit (OpCodes.Conv_Ovf_I);
9061 else if (expr_type == TypeManager.uint64_type)
9062 ec.Emit (OpCodes.Conv_Ovf_I_Un);
9064 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9069 // Implements the `stackalloc' keyword
9071 public class StackAlloc : Expression {
9076 public StackAlloc (Expression type, Expression count, Location l)
9083 public override Expression CreateExpressionTree (ResolveContext ec)
9085 throw new NotSupportedException ("ET");
9088 protected override Expression DoResolve (ResolveContext ec)
9090 count = count.Resolve (ec);
9094 if (count.Type != TypeManager.uint32_type){
9095 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9100 Constant c = count as Constant;
9101 if (c != null && c.IsNegative) {
9102 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9105 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9106 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9109 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9115 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
9118 type = PointerContainer.MakeType (otype);
9119 eclass = ExprClass.Value;
9124 public override void Emit (EmitContext ec)
9126 int size = GetTypeSize (otype);
9131 ec.Emit (OpCodes.Sizeof, otype);
9135 ec.Emit (OpCodes.Mul_Ovf_Un);
9136 ec.Emit (OpCodes.Localloc);
9139 protected override void CloneTo (CloneContext clonectx, Expression t)
9141 StackAlloc target = (StackAlloc) t;
9142 target.count = count.Clone (clonectx);
9143 target.t = t.Clone (clonectx);
9148 // An object initializer expression
9150 public class ElementInitializer : Assign
9152 public readonly string Name;
9154 public ElementInitializer (string name, Expression initializer, Location loc)
9155 : base (null, initializer, loc)
9160 protected override void CloneTo (CloneContext clonectx, Expression t)
9162 ElementInitializer target = (ElementInitializer) t;
9163 target.source = source.Clone (clonectx);
9166 public override Expression CreateExpressionTree (ResolveContext ec)
9168 Arguments args = new Arguments (2);
9169 FieldExpr fe = target as FieldExpr;
9171 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9173 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9175 args.Add (new Argument (source.CreateExpressionTree (ec)));
9176 return CreateExpressionFactoryCall (ec,
9177 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9181 protected override Expression DoResolve (ResolveContext ec)
9184 return EmptyExpressionStatement.Instance;
9186 var t = ec.CurrentInitializerVariable.Type;
9187 if (t == InternalType.Dynamic) {
9188 Arguments args = new Arguments (1);
9189 args.Add (new Argument (ec.CurrentInitializerVariable));
9190 target = new DynamicMemberBinder (Name, args, loc);
9193 var member = MemberLookup (ec, ec.CurrentType, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9194 if (member == null) {
9195 member = Expression.MemberLookup (null, ec.CurrentType, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9197 if (member != null) {
9198 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
9199 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
9204 if (member == null) {
9205 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
9209 if (!(member is PropertyExpr || member is FieldExpr)) {
9210 ec.Report.Error (1913, loc,
9211 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
9212 member.GetSignatureForError ());
9217 var me = member as MemberExpr;
9219 ec.Report.Error (1914, loc,
9220 "Static field or property `{0}' cannot be assigned in an object initializer",
9221 me.GetSignatureForError ());
9225 me.InstanceExpression = ec.CurrentInitializerVariable;
9228 if (source is CollectionOrObjectInitializers) {
9229 Expression previous = ec.CurrentInitializerVariable;
9230 ec.CurrentInitializerVariable = target;
9231 source = source.Resolve (ec);
9232 ec.CurrentInitializerVariable = previous;
9236 eclass = source.eclass;
9241 return base.DoResolve (ec);
9244 public override void EmitStatement (EmitContext ec)
9246 if (source is CollectionOrObjectInitializers)
9249 base.EmitStatement (ec);
9254 // A collection initializer expression
9256 class CollectionElementInitializer : Invocation
9258 public class ElementInitializerArgument : Argument
9260 public ElementInitializerArgument (Expression e)
9266 sealed class AddMemberAccess : MemberAccess
9268 public AddMemberAccess (Expression expr, Location loc)
9269 : base (expr, "Add", loc)
9273 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9275 if (TypeManager.HasElementType (type))
9278 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9282 public CollectionElementInitializer (Expression argument)
9283 : base (null, new Arguments (1))
9285 base.arguments.Add (new ElementInitializerArgument (argument));
9286 this.loc = argument.Location;
9289 public CollectionElementInitializer (List<Expression> arguments, Location loc)
9290 : base (null, new Arguments (arguments.Count))
9292 foreach (Expression e in arguments)
9293 base.arguments.Add (new ElementInitializerArgument (e));
9298 public override Expression CreateExpressionTree (ResolveContext ec)
9300 Arguments args = new Arguments (2);
9301 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9303 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
9304 foreach (Argument a in arguments)
9305 expr_initializers.Add (a.CreateExpressionTree (ec));
9307 args.Add (new Argument (new ArrayCreation (
9308 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
9309 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9312 protected override void CloneTo (CloneContext clonectx, Expression t)
9314 CollectionElementInitializer target = (CollectionElementInitializer) t;
9315 if (arguments != null)
9316 target.arguments = arguments.Clone (clonectx);
9319 protected override Expression DoResolve (ResolveContext ec)
9321 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9323 return base.DoResolve (ec);
9328 // A block of object or collection initializers
9330 public class CollectionOrObjectInitializers : ExpressionStatement
9332 IList<Expression> initializers;
9333 bool is_collection_initialization;
9335 public static readonly CollectionOrObjectInitializers Empty =
9336 new CollectionOrObjectInitializers (Array.AsReadOnly (new Expression [0]), Location.Null);
9338 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
9340 this.initializers = initializers;
9344 public bool IsEmpty {
9346 return initializers.Count == 0;
9350 public bool IsCollectionInitializer {
9352 return is_collection_initialization;
9356 protected override void CloneTo (CloneContext clonectx, Expression target)
9358 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9360 t.initializers = new List<Expression> (initializers.Count);
9361 foreach (var e in initializers)
9362 t.initializers.Add (e.Clone (clonectx));
9365 public override Expression CreateExpressionTree (ResolveContext ec)
9367 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
9368 foreach (Expression e in initializers) {
9369 Expression expr = e.CreateExpressionTree (ec);
9371 expr_initializers.Add (expr);
9374 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
9377 protected override Expression DoResolve (ResolveContext ec)
9379 List<string> element_names = null;
9380 for (int i = 0; i < initializers.Count; ++i) {
9381 Expression initializer = initializers [i];
9382 ElementInitializer element_initializer = initializer as ElementInitializer;
9385 if (element_initializer != null) {
9386 element_names = new List<string> (initializers.Count);
9387 element_names.Add (element_initializer.Name);
9388 } else if (initializer is CompletingExpression){
9389 initializer.Resolve (ec);
9390 throw new InternalErrorException ("This line should never be reached");
9392 var t = ec.CurrentInitializerVariable.Type;
9393 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
9394 if (!t.ImplementsInterface (TypeManager.ienumerable_type, false) && t != InternalType.Dynamic) {
9395 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9396 "object initializer because type `{1}' does not implement `{2}' interface",
9397 ec.CurrentInitializerVariable.GetSignatureForError (),
9398 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9399 TypeManager.CSharpName (TypeManager.ienumerable_type));
9402 is_collection_initialization = true;
9405 if (is_collection_initialization != (element_initializer == null)) {
9406 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9407 is_collection_initialization ? "collection initializer" : "object initializer");
9411 if (!is_collection_initialization) {
9412 if (element_names.Contains (element_initializer.Name)) {
9413 ec.Report.Error (1912, element_initializer.Location,
9414 "An object initializer includes more than one member `{0}' initialization",
9415 element_initializer.Name);
9417 element_names.Add (element_initializer.Name);
9422 Expression e = initializer.Resolve (ec);
9423 if (e == EmptyExpressionStatement.Instance)
9424 initializers.RemoveAt (i--);
9426 initializers [i] = e;
9429 type = ec.CurrentInitializerVariable.Type;
9430 if (is_collection_initialization) {
9431 if (TypeManager.HasElementType (type)) {
9432 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9433 TypeManager.CSharpName (type));
9437 eclass = ExprClass.Variable;
9441 public override void Emit (EmitContext ec)
9446 public override void EmitStatement (EmitContext ec)
9448 foreach (ExpressionStatement e in initializers)
9449 e.EmitStatement (ec);
9454 // New expression with element/object initializers
9456 public class NewInitialize : New
9459 // This class serves as a proxy for variable initializer target instances.
9460 // A real variable is assigned later when we resolve left side of an
9463 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9465 NewInitialize new_instance;
9467 public InitializerTargetExpression (NewInitialize newInstance)
9469 this.type = newInstance.type;
9470 this.loc = newInstance.loc;
9471 this.eclass = newInstance.eclass;
9472 this.new_instance = newInstance;
9475 public override Expression CreateExpressionTree (ResolveContext ec)
9477 // Should not be reached
9478 throw new NotSupportedException ("ET");
9481 protected override Expression DoResolve (ResolveContext ec)
9486 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9491 public override void Emit (EmitContext ec)
9493 Expression e = (Expression) new_instance.instance;
9497 #region IMemoryLocation Members
9499 public void AddressOf (EmitContext ec, AddressOp mode)
9501 new_instance.instance.AddressOf (ec, mode);
9507 CollectionOrObjectInitializers initializers;
9508 IMemoryLocation instance;
9510 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9511 : base (requested_type, arguments, l)
9513 this.initializers = initializers;
9516 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9518 instance = base.EmitAddressOf (ec, Mode);
9520 if (!initializers.IsEmpty)
9521 initializers.Emit (ec);
9526 protected override void CloneTo (CloneContext clonectx, Expression t)
9528 base.CloneTo (clonectx, t);
9530 NewInitialize target = (NewInitialize) t;
9531 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9534 public override Expression CreateExpressionTree (ResolveContext ec)
9536 Arguments args = new Arguments (2);
9537 args.Add (new Argument (base.CreateExpressionTree (ec)));
9538 if (!initializers.IsEmpty)
9539 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9541 return CreateExpressionFactoryCall (ec,
9542 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9546 protected override Expression DoResolve (ResolveContext ec)
9548 Expression e = base.DoResolve (ec);
9552 Expression previous = ec.CurrentInitializerVariable;
9553 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9554 initializers.Resolve (ec);
9555 ec.CurrentInitializerVariable = previous;
9559 public override bool Emit (EmitContext ec, IMemoryLocation target)
9561 bool left_on_stack = base.Emit (ec, target);
9563 if (initializers.IsEmpty)
9564 return left_on_stack;
9566 LocalTemporary temp = target as LocalTemporary;
9568 if (!left_on_stack) {
9569 VariableReference vr = target as VariableReference;
9571 // FIXME: This still does not work correctly for pre-set variables
9572 if (vr != null && vr.IsRef)
9573 target.AddressOf (ec, AddressOp.Load);
9575 ((Expression) target).Emit (ec);
9576 left_on_stack = true;
9579 temp = new LocalTemporary (type);
9586 initializers.Emit (ec);
9588 if (left_on_stack) {
9593 return left_on_stack;
9597 public class NewAnonymousType : New
9599 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
9601 List<AnonymousTypeParameter> parameters;
9602 readonly TypeContainer parent;
9603 AnonymousTypeClass anonymous_type;
9605 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
9606 : base (null, null, loc)
9608 this.parameters = parameters;
9609 this.parent = parent;
9612 protected override void CloneTo (CloneContext clonectx, Expression target)
9614 if (parameters == null)
9617 NewAnonymousType t = (NewAnonymousType) target;
9618 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
9619 foreach (AnonymousTypeParameter atp in parameters)
9620 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
9623 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
9625 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
9629 type = AnonymousTypeClass.Create (parent, parameters, loc);
9635 type.ResolveTypeParameters ();
9638 if (ec.Report.Errors == 0)
9641 parent.Module.AddAnonymousType (type);
9645 public override Expression CreateExpressionTree (ResolveContext ec)
9647 if (parameters == null)
9648 return base.CreateExpressionTree (ec);
9650 var init = new ArrayInitializer (parameters.Count, loc);
9651 foreach (Property p in anonymous_type.Properties)
9652 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
9654 var ctor_args = new ArrayInitializer (arguments.Count, loc);
9655 foreach (Argument a in arguments)
9656 ctor_args.Add (a.CreateExpressionTree (ec));
9658 Arguments args = new Arguments (3);
9659 args.Add (new Argument (new TypeOfMethod (method, loc)));
9660 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
9661 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
9663 return CreateExpressionFactoryCall (ec, "New", args);
9666 protected override Expression DoResolve (ResolveContext ec)
9668 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
9669 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9673 if (parameters == null) {
9674 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
9675 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
9676 return base.DoResolve (ec);
9680 arguments = new Arguments (parameters.Count);
9681 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9682 for (int i = 0; i < parameters.Count; ++i) {
9683 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9689 arguments.Add (new Argument (e));
9690 t_args [i] = new TypeExpression (e.Type, e.Location);
9696 anonymous_type = CreateAnonymousType (ec, parameters);
9697 if (anonymous_type == null)
9700 RequestedType = new GenericTypeExpr (anonymous_type.Definition, new TypeArguments (t_args), loc);
9701 return base.DoResolve (ec);
9705 public class AnonymousTypeParameter : ShimExpression
9707 public readonly string Name;
9709 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9710 : base (initializer)
9716 public AnonymousTypeParameter (Parameter parameter)
9717 : base (new SimpleName (parameter.Name, parameter.Location))
9719 this.Name = parameter.Name;
9720 this.loc = parameter.Location;
9723 public override bool Equals (object o)
9725 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9726 return other != null && Name == other.Name;
9729 public override int GetHashCode ()
9731 return Name.GetHashCode ();
9734 protected override Expression DoResolve (ResolveContext ec)
9736 Expression e = expr.Resolve (ec);
9740 if (e.eclass == ExprClass.MethodGroup) {
9741 Error_InvalidInitializer (ec, e.ExprClassName);
9746 if (type == TypeManager.void_type || type == InternalType.Null ||
9747 type == InternalType.AnonymousMethod || type.IsPointer) {
9748 Error_InvalidInitializer (ec, e.GetSignatureForError ());
9755 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
9757 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",