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.Compiler, 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 (RootContext.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 (is_false ? false_expr : true_expr, this).Resolve (ec);
4493 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
4498 public override void Emit (EmitContext ec)
4500 Label false_target = ec.DefineLabel ();
4501 Label end_target = ec.DefineLabel ();
4503 expr.EmitBranchable (ec, false_target, false);
4504 true_expr.Emit (ec);
4506 if (type.IsInterface) {
4507 LocalBuilder temp = ec.GetTemporaryLocal (type);
4508 ec.Emit (OpCodes.Stloc, temp);
4509 ec.Emit (OpCodes.Ldloc, temp);
4510 ec.FreeTemporaryLocal (temp, type);
4513 ec.Emit (OpCodes.Br, end_target);
4514 ec.MarkLabel (false_target);
4515 false_expr.Emit (ec);
4516 ec.MarkLabel (end_target);
4519 protected override void CloneTo (CloneContext clonectx, Expression t)
4521 Conditional target = (Conditional) t;
4523 target.expr = expr.Clone (clonectx);
4524 target.true_expr = true_expr.Clone (clonectx);
4525 target.false_expr = false_expr.Clone (clonectx);
4529 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4530 LocalTemporary temp;
4533 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4535 public abstract bool IsLockedByStatement { get; set; }
4537 public abstract bool IsFixed { get; }
4538 public abstract bool IsRef { get; }
4539 public abstract string Name { get; }
4540 public abstract void SetHasAddressTaken ();
4543 // Variable IL data, it has to be protected to encapsulate hoisted variables
4545 protected abstract ILocalVariable Variable { get; }
4548 // Variable flow-analysis data
4550 public abstract VariableInfo VariableInfo { get; }
4553 public virtual void AddressOf (EmitContext ec, AddressOp mode)
4555 HoistedVariable hv = GetHoistedVariable (ec);
4557 hv.AddressOf (ec, mode);
4561 Variable.EmitAddressOf (ec);
4564 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
4566 if (IsLockedByStatement) {
4567 rc.Report.Warning (728, 2, loc,
4568 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
4575 public override void Emit (EmitContext ec)
4580 public override void EmitSideEffect (EmitContext ec)
4586 // This method is used by parameters that are references, that are
4587 // being passed as references: we only want to pass the pointer (that
4588 // is already stored in the parameter, not the address of the pointer,
4589 // and not the value of the variable).
4591 public void EmitLoad (EmitContext ec)
4596 public void Emit (EmitContext ec, bool leave_copy)
4598 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4600 HoistedVariable hv = GetHoistedVariable (ec);
4602 hv.Emit (ec, leave_copy);
4610 // If we are a reference, we loaded on the stack a pointer
4611 // Now lets load the real value
4613 ec.EmitLoadFromPtr (type);
4617 ec.Emit (OpCodes.Dup);
4620 temp = new LocalTemporary (Type);
4626 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4627 bool prepare_for_load)
4629 HoistedVariable hv = GetHoistedVariable (ec);
4631 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4635 New n_source = source as New;
4636 if (n_source != null) {
4637 if (!n_source.Emit (ec, this)) {
4641 ec.EmitLoadFromPtr (type);
4653 ec.Emit (OpCodes.Dup);
4655 temp = new LocalTemporary (Type);
4661 ec.EmitStoreFromPtr (type);
4663 Variable.EmitAssign (ec);
4672 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4674 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4677 public HoistedVariable GetHoistedVariable (EmitContext ec)
4679 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4682 public override string GetSignatureForError ()
4687 public bool IsHoisted {
4688 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4693 // Resolved reference to a local variable
4695 public class LocalVariableReference : VariableReference
4697 public LocalVariable local_info;
4699 public LocalVariableReference (LocalVariable li, Location l)
4701 this.local_info = li;
4705 public override VariableInfo VariableInfo {
4706 get { return local_info.VariableInfo; }
4709 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4711 return local_info.HoistedVariant;
4717 // A local variable is always fixed
4719 public override bool IsFixed {
4725 public override bool IsLockedByStatement {
4727 return local_info.IsLocked;
4730 local_info.IsLocked = value;
4734 public override bool IsRef {
4735 get { return false; }
4738 public override string Name {
4739 get { return local_info.Name; }
4744 public bool VerifyAssigned (ResolveContext ec)
4746 VariableInfo variable_info = local_info.VariableInfo;
4747 return variable_info == null || variable_info.IsAssigned (ec, loc);
4750 public override void SetHasAddressTaken ()
4752 local_info.AddressTaken = true;
4755 public override Expression CreateExpressionTree (ResolveContext ec)
4757 HoistedVariable hv = GetHoistedVariable (ec);
4759 return hv.CreateExpressionTree ();
4761 Arguments arg = new Arguments (1);
4762 arg.Add (new Argument (this));
4763 return CreateExpressionFactoryCall (ec, "Constant", arg);
4766 void DoResolveBase (ResolveContext ec)
4768 VerifyAssigned (ec);
4771 // If we are referencing a variable from the external block
4772 // flag it for capturing
4774 if (ec.MustCaptureVariable (local_info)) {
4775 if (local_info.AddressTaken)
4776 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4778 if (ec.IsVariableCapturingRequired) {
4779 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4780 storey.CaptureLocalVariable (ec, local_info);
4784 eclass = ExprClass.Variable;
4785 type = local_info.Type;
4788 protected override Expression DoResolve (ResolveContext ec)
4790 local_info.SetIsUsed ();
4796 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4799 if (right_side == EmptyExpression.OutAccess.Instance)
4800 local_info.SetIsUsed ();
4802 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
4805 if (right_side == EmptyExpression.OutAccess.Instance) {
4806 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4807 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4808 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4809 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4810 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4811 } else if (right_side == EmptyExpression.UnaryAddress) {
4812 code = 459; msg = "Cannot take the address of {1} `{0}'";
4814 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4816 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4817 } else if (VariableInfo != null) {
4818 VariableInfo.SetAssigned (ec);
4823 return base.DoResolveLValue (ec, right_side);
4826 public override int GetHashCode ()
4828 return local_info.GetHashCode ();
4831 public override bool Equals (object obj)
4833 LocalVariableReference lvr = obj as LocalVariableReference;
4837 return local_info == lvr.local_info;
4840 protected override ILocalVariable Variable {
4841 get { return local_info; }
4844 public override string ToString ()
4846 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4849 protected override void CloneTo (CloneContext clonectx, Expression t)
4856 /// This represents a reference to a parameter in the intermediate
4859 public class ParameterReference : VariableReference
4861 protected ParametersBlock.ParameterInfo pi;
4863 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
4871 public override bool IsLockedByStatement {
4876 pi.IsLocked = value;
4880 public override bool IsRef {
4881 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4884 bool HasOutModifier {
4885 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4888 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4890 return pi.Parameter.HoistedVariant;
4894 // A ref or out parameter is classified as a moveable variable, even
4895 // if the argument given for the parameter is a fixed variable
4897 public override bool IsFixed {
4898 get { return !IsRef; }
4901 public override string Name {
4902 get { return Parameter.Name; }
4905 public Parameter Parameter {
4906 get { return pi.Parameter; }
4909 public override VariableInfo VariableInfo {
4910 get { return pi.VariableInfo; }
4913 protected override ILocalVariable Variable {
4914 get { return Parameter; }
4919 public bool IsAssigned (ResolveContext ec, Location loc)
4921 // HACK: Variables are not captured in probing mode
4922 if (ec.IsInProbingMode)
4925 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4928 ec.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4932 public override void SetHasAddressTaken ()
4934 Parameter.HasAddressTaken = true;
4937 void SetAssigned (ResolveContext ec)
4939 if (HasOutModifier && ec.DoFlowAnalysis)
4940 ec.CurrentBranching.SetAssigned (VariableInfo);
4943 bool DoResolveBase (ResolveContext ec)
4945 type = pi.ParameterType;
4946 eclass = ExprClass.Variable;
4949 // If we are referencing a parameter from the external block
4950 // flag it for capturing
4952 if (ec.MustCaptureVariable (pi)) {
4953 if (Parameter.HasAddressTaken)
4954 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4957 ec.Report.Error (1628, loc,
4958 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4959 Name, ec.CurrentAnonymousMethod.ContainerType);
4962 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
4963 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
4964 storey.CaptureParameter (ec, this);
4971 public override int GetHashCode ()
4973 return Name.GetHashCode ();
4976 public override bool Equals (object obj)
4978 ParameterReference pr = obj as ParameterReference;
4982 return Name == pr.Name;
4985 public override void AddressOf (EmitContext ec, AddressOp mode)
4988 // ParameterReferences might already be a reference
4995 base.AddressOf (ec, mode);
4998 protected override void CloneTo (CloneContext clonectx, Expression target)
5004 public override Expression CreateExpressionTree (ResolveContext ec)
5006 HoistedVariable hv = GetHoistedVariable (ec);
5008 return hv.CreateExpressionTree ();
5010 return Parameter.ExpressionTreeVariableReference ();
5014 // Notice that for ref/out parameters, the type exposed is not the
5015 // same type exposed externally.
5018 // externally we expose "int&"
5019 // here we expose "int".
5021 // We record this in "is_ref". This means that the type system can treat
5022 // the type as it is expected, but when we generate the code, we generate
5023 // the alternate kind of code.
5025 protected override Expression DoResolve (ResolveContext ec)
5027 if (!DoResolveBase (ec))
5030 // HACK: Variables are not captured in probing mode
5031 if (ec.IsInProbingMode)
5034 if (HasOutModifier && ec.DoFlowAnalysis &&
5035 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
5041 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5043 if (!DoResolveBase (ec))
5047 return base.DoResolveLValue (ec, right_side);
5050 static public void EmitLdArg (EmitContext ec, int x)
5053 case 0: ec.Emit (OpCodes.Ldarg_0); break;
5054 case 1: ec.Emit (OpCodes.Ldarg_1); break;
5055 case 2: ec.Emit (OpCodes.Ldarg_2); break;
5056 case 3: ec.Emit (OpCodes.Ldarg_3); break;
5058 if (x > byte.MaxValue)
5059 ec.Emit (OpCodes.Ldarg, x);
5061 ec.Emit (OpCodes.Ldarg_S, (byte) x);
5068 /// Invocation of methods or delegates.
5070 public class Invocation : ExpressionStatement
5072 protected Arguments arguments;
5073 protected Expression expr;
5074 protected MethodGroupExpr mg;
5076 public Invocation (Expression expr, Arguments arguments)
5079 this.arguments = arguments;
5081 loc = expr.Location;
5085 public Arguments Arguments {
5091 public Expression Expression {
5098 protected override void CloneTo (CloneContext clonectx, Expression t)
5100 Invocation target = (Invocation) t;
5102 if (arguments != null)
5103 target.arguments = arguments.Clone (clonectx);
5105 target.expr = expr.Clone (clonectx);
5109 public override Expression CreateExpressionTree (ResolveContext ec)
5111 Expression instance = mg.IsInstance ?
5112 mg.InstanceExpression.CreateExpressionTree (ec) :
5113 new NullLiteral (loc);
5115 var args = Arguments.CreateForExpressionTree (ec, arguments,
5117 mg.CreateExpressionTree (ec));
5119 return CreateExpressionFactoryCall (ec, "Call", args);
5122 protected override Expression DoResolve (ResolveContext ec)
5124 Expression member_expr;
5125 var atn = expr as ATypeNameExpression;
5127 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
5128 if (member_expr != null)
5129 member_expr = member_expr.Resolve (ec);
5131 member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5134 if (member_expr == null)
5138 // Next, evaluate all the expressions in the argument list
5140 bool dynamic_arg = false;
5141 if (arguments != null)
5142 arguments.Resolve (ec, out dynamic_arg);
5144 TypeSpec expr_type = member_expr.Type;
5145 if (expr_type == InternalType.Dynamic)
5146 return DoResolveDynamic (ec, member_expr);
5148 mg = member_expr as MethodGroupExpr;
5149 Expression invoke = null;
5152 if (expr_type != null && TypeManager.IsDelegateType (expr_type)) {
5153 invoke = new DelegateInvocation (member_expr, arguments, loc);
5154 invoke = invoke.Resolve (ec);
5155 if (invoke == null || !dynamic_arg)
5158 if (member_expr is RuntimeValueExpression) {
5159 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
5160 member_expr.Type.GetSignatureForError ()); ;
5164 MemberExpr me = member_expr as MemberExpr;
5166 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5170 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
5171 member_expr.GetSignatureForError ());
5176 if (invoke == null) {
5177 mg = DoResolveOverload (ec);
5183 return DoResolveDynamic (ec, member_expr);
5185 var method = mg.BestCandidate;
5186 type = mg.BestCandidateReturnType;
5188 if (arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
5190 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5192 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5196 IsSpecialMethodInvocation (ec, method, loc);
5198 eclass = ExprClass.Value;
5202 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
5205 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
5207 args = dmb.Arguments;
5208 if (arguments != null)
5209 args.AddRange (arguments);
5210 } else if (mg == null) {
5211 if (arguments == null)
5212 args = new Arguments (1);
5216 args.Insert (0, new Argument (memberExpr));
5220 ec.Report.Error (1971, loc,
5221 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
5226 if (arguments == null)
5227 args = new Arguments (1);
5231 MemberAccess ma = expr as MemberAccess;
5233 var left_type = ma.LeftExpression as TypeExpr;
5234 if (left_type != null) {
5235 args.Insert (0, new Argument (new TypeOf (left_type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5238 // Any value type has to be pass as by-ref to get back the same
5239 // instance on which the member was called
5241 var mod = TypeManager.IsValueType (ma.LeftExpression.Type) ? Argument.AType.Ref : Argument.AType.None;
5242 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
5244 } else { // is SimpleName
5246 args.Insert (0, new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc).Resolve (ec), Argument.AType.DynamicTypeName));
5248 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5253 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5256 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5258 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
5261 static MetaType[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
5263 AParametersCollection pd = mb.Parameters;
5265 Argument a = arguments[pd.Count - 1];
5266 Arglist list = (Arglist) a.Expr;
5268 return list.ArgumentTypes;
5272 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
5273 // or the type dynamic, then the member is invocable
5275 public static bool IsMemberInvocable (MemberSpec member)
5277 switch (member.Kind) {
5278 case MemberKind.Event:
5280 case MemberKind.Field:
5281 case MemberKind.Property:
5282 var m = member as IInterfaceMemberSpec;
5283 return m.MemberType.IsDelegate || m.MemberType == InternalType.Dynamic;
5289 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
5291 if (!method.IsReservedMethod)
5294 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
5297 ec.Report.SymbolRelatedToPreviousError (method);
5298 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5299 method.GetSignatureForError ());
5305 // Used to decide whether call or callvirt is needed
5307 static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
5310 // There are 2 scenarious where we emit callvirt
5312 // Case 1: A method is virtual and it's not used to call base
5313 // Case 2: A method instance expression can be null. In this casen callvirt ensures
5314 // correct NRE exception when the method is called
5316 var decl_type = method.DeclaringType;
5317 if (decl_type.IsStruct || decl_type.IsEnum)
5320 if (instance is BaseThis)
5324 // It's non-virtual and will never be null
5326 if (!method.IsVirtual && (instance is This || instance is New || instance is ArrayCreation || instance is DelegateCreation || instance is TypeOf))
5333 /// is_base tells whether we want to force the use of the `call'
5334 /// opcode instead of using callvirt. Call is required to call
5335 /// a specific method, while callvirt will always use the most
5336 /// recent method in the vtable.
5338 /// is_static tells whether this is an invocation on a static method
5340 /// instance_expr is an expression that represents the instance
5341 /// it must be non-null if is_static is false.
5343 /// method is the method to invoke.
5345 /// Arguments is the list of arguments to pass to the method or constructor.
5347 public static void EmitCall (EmitContext ec, Expression instance_expr,
5348 MethodSpec method, Arguments Arguments, Location loc)
5350 EmitCall (ec, instance_expr, method, Arguments, loc, false, false);
5353 // `dup_args' leaves an extra copy of the arguments on the stack
5354 // `omit_args' does not leave any arguments at all.
5355 // So, basically, you could make one call with `dup_args' set to true,
5356 // and then another with `omit_args' set to true, and the two calls
5357 // would have the same set of arguments. However, each argument would
5358 // only have been evaluated once.
5359 public static void EmitCall (EmitContext ec, Expression instance_expr,
5360 MethodSpec method, Arguments Arguments, Location loc,
5361 bool dup_args, bool omit_args)
5363 LocalTemporary this_arg = null;
5365 // Speed up the check by not doing it on not allowed targets
5366 if (method.ReturnType == TypeManager.void_type && method.IsConditionallyExcluded (loc))
5370 TypeSpec iexpr_type;
5372 if (method.IsStatic) {
5374 call_op = OpCodes.Call;
5376 iexpr_type = instance_expr.Type;
5378 if (IsVirtualCallRequired (instance_expr, method)) {
5379 call_op = OpCodes.Callvirt;
5381 call_op = OpCodes.Call;
5385 // If this is ourselves, push "this"
5388 TypeSpec t = iexpr_type;
5391 // Push the instance expression
5393 if ((iexpr_type.IsStruct && (call_op == OpCodes.Callvirt || (call_op == OpCodes.Call && method.DeclaringType == iexpr_type))) ||
5394 iexpr_type.IsGenericParameter || TypeManager.IsNullableType (method.DeclaringType)) {
5396 // If the expression implements IMemoryLocation, then
5397 // we can optimize and use AddressOf on the
5400 // If not we have to use some temporary storage for
5402 var iml = instance_expr as IMemoryLocation;
5404 iml.AddressOf (ec, AddressOp.LoadStore);
5406 LocalTemporary temp = new LocalTemporary (iexpr_type);
5407 instance_expr.Emit (ec);
5409 temp.AddressOf (ec, AddressOp.Load);
5412 // avoid the overhead of doing this all the time.
5414 t = ReferenceContainer.MakeType (iexpr_type);
5415 } else if (iexpr_type.IsEnum || iexpr_type.IsStruct) {
5416 instance_expr.Emit (ec);
5417 ec.Emit (OpCodes.Box, iexpr_type);
5418 t = iexpr_type = TypeManager.object_type;
5420 instance_expr.Emit (ec);
5424 ec.Emit (OpCodes.Dup);
5425 if (Arguments != null && Arguments.Count != 0) {
5426 this_arg = new LocalTemporary (t);
5427 this_arg.Store (ec);
5433 if (!omit_args && Arguments != null) {
5434 var dup_arg_exprs = Arguments.Emit (ec, dup_args);
5438 foreach (var dup in dup_arg_exprs) {
5440 lt = dup as LocalTemporary;
5447 if (call_op == OpCodes.Callvirt && (iexpr_type.IsGenericParameter || iexpr_type.IsStruct)) {
5448 ec.Emit (OpCodes.Constrained, iexpr_type);
5451 if (method.Parameters.HasArglist) {
5452 var varargs_types = GetVarargsTypes (method, Arguments);
5453 ec.Emit (call_op, method, varargs_types);
5460 // and DoFoo is not virtual, you can omit the callvirt,
5461 // because you don't need the null checking behavior.
5463 ec.Emit (call_op, method);
5466 public override void Emit (EmitContext ec)
5468 mg.EmitCall (ec, arguments);
5471 public override void EmitStatement (EmitContext ec)
5476 // Pop the return value if there is one
5478 if (type != TypeManager.void_type)
5479 ec.Emit (OpCodes.Pop);
5482 public override SLE.Expression MakeExpression (BuilderContext ctx)
5484 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
5487 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
5490 throw new NotSupportedException ();
5492 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5493 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
5499 // Implements simple new expression
5501 public class New : ExpressionStatement, IMemoryLocation
5503 protected Arguments arguments;
5506 // During bootstrap, it contains the RequestedType,
5507 // but if `type' is not null, it *might* contain a NewDelegate
5508 // (because of field multi-initialization)
5510 protected Expression RequestedType;
5512 protected MethodSpec method;
5514 public New (Expression requested_type, Arguments arguments, Location l)
5516 RequestedType = requested_type;
5517 this.arguments = arguments;
5522 public Arguments Arguments {
5529 // Returns true for resolved `new S()'
5531 public bool IsDefaultStruct {
5533 return arguments == null && type.IsStruct && GetType () == typeof (New);
5540 /// Converts complex core type syntax like 'new int ()' to simple constant
5542 public static Constant Constantify (TypeSpec t, Location loc)
5544 if (t == TypeManager.int32_type)
5545 return new IntConstant (0, loc);
5546 if (t == TypeManager.uint32_type)
5547 return new UIntConstant (0, loc);
5548 if (t == TypeManager.int64_type)
5549 return new LongConstant (0, loc);
5550 if (t == TypeManager.uint64_type)
5551 return new ULongConstant (0, loc);
5552 if (t == TypeManager.float_type)
5553 return new FloatConstant (0, loc);
5554 if (t == TypeManager.double_type)
5555 return new DoubleConstant (0, loc);
5556 if (t == TypeManager.short_type)
5557 return new ShortConstant (0, loc);
5558 if (t == TypeManager.ushort_type)
5559 return new UShortConstant (0, loc);
5560 if (t == TypeManager.sbyte_type)
5561 return new SByteConstant (0, loc);
5562 if (t == TypeManager.byte_type)
5563 return new ByteConstant (0, loc);
5564 if (t == TypeManager.char_type)
5565 return new CharConstant ('\0', loc);
5566 if (t == TypeManager.bool_type)
5567 return new BoolConstant (false, loc);
5568 if (t == TypeManager.decimal_type)
5569 return new DecimalConstant (0, loc);
5570 if (TypeManager.IsEnumType (t))
5571 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
5572 if (TypeManager.IsNullableType (t))
5573 return Nullable.LiftedNull.Create (t, loc);
5579 // Checks whether the type is an interface that has the
5580 // [ComImport, CoClass] attributes and must be treated
5583 public Expression CheckComImport (ResolveContext ec)
5585 if (!type.IsInterface)
5589 // Turn the call into:
5590 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5592 var real_class = type.MemberDefinition.GetAttributeCoClass ();
5593 if (real_class == null)
5596 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
5597 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5598 return cast.Resolve (ec);
5601 public override Expression CreateExpressionTree (ResolveContext ec)
5604 if (method == null) {
5605 args = new Arguments (1);
5606 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5608 args = Arguments.CreateForExpressionTree (ec,
5609 arguments, new TypeOfMethod (method, loc));
5612 return CreateExpressionFactoryCall (ec, "New", args);
5615 protected override Expression DoResolve (ResolveContext ec)
5617 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5622 eclass = ExprClass.Value;
5624 if (type.IsPointer) {
5625 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5626 TypeManager.CSharpName (type));
5630 if (arguments == null) {
5631 Constant c = Constantify (type, RequestedType.Location);
5633 return ReducedExpression.Create (c.Resolve (ec), this);
5636 if (TypeManager.IsDelegateType (type)) {
5637 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
5640 var tparam = type as TypeParameterSpec;
5641 if (tparam != null) {
5643 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
5644 // where type parameter constraint is inflated to struct
5646 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !tparam.BaseType.IsStruct) {
5647 ec.Report.Error (304, loc,
5648 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
5649 TypeManager.CSharpName (type));
5652 if ((arguments != null) && (arguments.Count != 0)) {
5653 ec.Report.Error (417, loc,
5654 "`{0}': cannot provide arguments when creating an instance of a variable type",
5655 TypeManager.CSharpName (type));
5661 if (type.IsStatic) {
5662 ec.Report.SymbolRelatedToPreviousError (type);
5663 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5667 if (type.IsInterface || type.IsAbstract){
5668 if (!TypeManager.IsGenericType (type)) {
5669 RequestedType = CheckComImport (ec);
5670 if (RequestedType != null)
5671 return RequestedType;
5674 ec.Report.SymbolRelatedToPreviousError (type);
5675 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5680 // Any struct always defines parameterless constructor
5682 if (type.IsStruct && arguments == null)
5686 if (arguments != null) {
5687 arguments.Resolve (ec, out dynamic);
5692 method = ConstructorLookup (ec, type, ref arguments, loc);
5695 arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5696 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
5702 bool DoEmitTypeParameter (EmitContext ec)
5704 var activator = ec.MemberContext.Module.PredefinedTypes.Activator;
5705 var t = activator.Resolve (loc);
5709 if (TypeManager.activator_create_instance == null) {
5710 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5711 t, MemberFilter.Method ("CreateInstance", 1, ParametersCompiled.EmptyReadOnlyParameters, null), loc);
5714 var ctor_factory = TypeManager.activator_create_instance.MakeGenericMethod (type);
5715 var tparam = (TypeParameterSpec) type;
5717 if (tparam.IsReferenceType) {
5718 ec.Emit (OpCodes.Call, ctor_factory);
5722 // Allow DoEmit() to be called multiple times.
5723 // We need to create a new LocalTemporary each time since
5724 // you can't share LocalBuilders among ILGeneators.
5725 LocalTemporary temp = new LocalTemporary (type);
5727 Label label_activator = ec.DefineLabel ();
5728 Label label_end = ec.DefineLabel ();
5730 temp.AddressOf (ec, AddressOp.Store);
5731 ec.Emit (OpCodes.Initobj, type);
5734 ec.Emit (OpCodes.Box, type);
5735 ec.Emit (OpCodes.Brfalse, label_activator);
5737 temp.AddressOf (ec, AddressOp.Store);
5738 ec.Emit (OpCodes.Initobj, type);
5740 ec.Emit (OpCodes.Br_S, label_end);
5742 ec.MarkLabel (label_activator);
5744 ec.Emit (OpCodes.Call, ctor_factory);
5745 ec.MarkLabel (label_end);
5750 // This Emit can be invoked in two contexts:
5751 // * As a mechanism that will leave a value on the stack (new object)
5752 // * As one that wont (init struct)
5754 // If we are dealing with a ValueType, we have a few
5755 // situations to deal with:
5757 // * The target is a ValueType, and we have been provided
5758 // the instance (this is easy, we are being assigned).
5760 // * The target of New is being passed as an argument,
5761 // to a boxing operation or a function that takes a
5764 // In this case, we need to create a temporary variable
5765 // that is the argument of New.
5767 // Returns whether a value is left on the stack
5769 // *** Implementation note ***
5771 // To benefit from this optimization, each assignable expression
5772 // has to manually cast to New and call this Emit.
5774 // TODO: It's worth to implement it for arrays and fields
5776 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5778 bool is_value_type = TypeManager.IsValueType (type);
5779 VariableReference vr = target as VariableReference;
5781 if (target != null && is_value_type && (vr != null || method == null)) {
5782 target.AddressOf (ec, AddressOp.Store);
5783 } else if (vr != null && vr.IsRef) {
5787 if (arguments != null)
5788 arguments.Emit (ec);
5790 if (is_value_type) {
5791 if (method == null) {
5792 ec.Emit (OpCodes.Initobj, type);
5797 ec.Emit (OpCodes.Call, method);
5802 if (type is TypeParameterSpec)
5803 return DoEmitTypeParameter (ec);
5805 ec.Emit (OpCodes.Newobj, method);
5809 public override void Emit (EmitContext ec)
5811 LocalTemporary v = null;
5812 if (method == null && TypeManager.IsValueType (type)) {
5813 // TODO: Use temporary variable from pool
5814 v = new LocalTemporary (type);
5821 public override void EmitStatement (EmitContext ec)
5823 LocalTemporary v = null;
5824 if (method == null && TypeManager.IsValueType (type)) {
5825 // TODO: Use temporary variable from pool
5826 v = new LocalTemporary (type);
5830 ec.Emit (OpCodes.Pop);
5833 public void AddressOf (EmitContext ec, AddressOp mode)
5835 EmitAddressOf (ec, mode);
5838 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5840 LocalTemporary value_target = new LocalTemporary (type);
5842 if (type is TypeParameterSpec) {
5843 DoEmitTypeParameter (ec);
5844 value_target.Store (ec);
5845 value_target.AddressOf (ec, mode);
5846 return value_target;
5849 if (!TypeManager.IsStruct (type)){
5851 // We throw an exception. So far, I believe we only need to support
5853 // foreach (int j in new StructType ())
5856 throw new Exception ("AddressOf should not be used for classes");
5859 value_target.AddressOf (ec, AddressOp.Store);
5861 if (method == null) {
5862 ec.Emit (OpCodes.Initobj, type);
5864 if (arguments != null)
5865 arguments.Emit (ec);
5867 ec.Emit (OpCodes.Call, method);
5870 value_target.AddressOf (ec, mode);
5871 return value_target;
5874 protected override void CloneTo (CloneContext clonectx, Expression t)
5876 New target = (New) t;
5878 target.RequestedType = RequestedType.Clone (clonectx);
5879 if (arguments != null){
5880 target.arguments = arguments.Clone (clonectx);
5884 public override SLE.Expression MakeExpression (BuilderContext ctx)
5887 return base.MakeExpression (ctx);
5889 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
5895 // Array initializer expression, the expression is allowed in
5896 // variable or field initialization only which makes it tricky as
5897 // the type has to be infered based on the context either from field
5898 // type or variable type (think of multiple declarators)
5900 public class ArrayInitializer : Expression
5902 List<Expression> elements;
5903 BlockVariableDeclaration variable;
5905 public ArrayInitializer (List<Expression> init, Location loc)
5911 public ArrayInitializer (int count, Location loc)
5912 : this (new List<Expression> (count), loc)
5916 public ArrayInitializer (Location loc)
5924 get { return elements.Count; }
5927 public Expression this [int index] {
5929 return elements [index];
5933 public BlockVariableDeclaration VariableDeclaration {
5944 public void Add (Expression expr)
5946 elements.Add (expr);
5949 public override Expression CreateExpressionTree (ResolveContext ec)
5951 throw new NotSupportedException ("ET");
5954 protected override void CloneTo (CloneContext clonectx, Expression t)
5956 var target = (ArrayInitializer) t;
5958 target.elements = new List<Expression> (elements.Count);
5959 foreach (var element in elements)
5960 target.elements.Add (element.Clone (clonectx));
5963 protected override Expression DoResolve (ResolveContext rc)
5965 var current_field = rc.CurrentMemberDefinition as FieldBase;
5966 TypeExpression type;
5967 if (current_field != null) {
5968 type = new TypeExpression (current_field.MemberType, current_field.Location);
5969 } else if (variable != null) {
5970 if (variable.TypeExpression is VarExpr) {
5971 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5972 return EmptyExpression.Null;
5975 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
5977 throw new NotImplementedException ("Unexpected array initializer context");
5980 return new ArrayCreation (type, this).Resolve (rc);
5983 public override void Emit (EmitContext ec)
5985 throw new InternalErrorException ("Missing Resolve call");
5990 /// 14.5.10.2: Represents an array creation expression.
5994 /// There are two possible scenarios here: one is an array creation
5995 /// expression that specifies the dimensions and optionally the
5996 /// initialization data and the other which does not need dimensions
5997 /// specified but where initialization data is mandatory.
5999 public class ArrayCreation : Expression
6001 FullNamedExpression requested_base_type;
6002 ArrayInitializer initializers;
6005 // The list of Argument types.
6006 // This is used to construct the `newarray' or constructor signature
6008 protected List<Expression> arguments;
6010 protected TypeSpec array_element_type;
6011 int num_arguments = 0;
6012 protected int dimensions;
6013 protected readonly ComposedTypeSpecifier rank;
6014 Expression first_emit;
6015 LocalTemporary first_emit_temp;
6017 protected List<Expression> array_data;
6019 Dictionary<int, int> bounds;
6021 // The number of constants in array initializers
6022 int const_initializers_count;
6023 bool only_constant_initializers;
6025 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6026 : this (requested_base_type, rank, initializers, l)
6028 arguments = new List<Expression> (exprs);
6029 num_arguments = arguments.Count;
6033 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6035 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6037 this.requested_base_type = requested_base_type;
6039 this.initializers = initializers;
6043 num_arguments = rank.Dimension;
6047 // For compiler generated single dimensional arrays only
6049 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6050 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6055 // For expressions like int[] foo = { 1, 2, 3 };
6057 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6058 : this (requested_base_type, null, initializers, initializers.Location)
6062 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
6064 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
6067 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6069 if (initializers != null && bounds == null) {
6071 // We use this to store all the date values in the order in which we
6072 // will need to store them in the byte blob later
6074 array_data = new List<Expression> ();
6075 bounds = new Dictionary<int, int> ();
6078 if (specified_dims) {
6079 Expression a = arguments [idx];
6084 a = ConvertExpressionToArrayIndex (ec, a);
6090 if (initializers != null) {
6091 Constant c = a as Constant;
6092 if (c == null && a is ArrayIndexCast)
6093 c = ((ArrayIndexCast) a).Child as Constant;
6096 ec.Report.Error (150, a.Location, "A constant value is expected");
6102 value = System.Convert.ToInt32 (c.GetValue ());
6104 ec.Report.Error (150, a.Location, "A constant value is expected");
6108 // TODO: probe.Count does not fit ulong in
6109 if (value != probe.Count) {
6110 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6114 bounds[idx] = value;
6118 if (initializers == null)
6121 for (int i = 0; i < probe.Count; ++i) {
6123 if (o is ArrayInitializer) {
6124 var sub_probe = o as ArrayInitializer;
6125 if (idx + 1 >= dimensions){
6126 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6130 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6133 } else if (child_bounds > 1) {
6134 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6136 Expression element = ResolveArrayElement (ec, o);
6137 if (element == null)
6140 // Initializers with the default values can be ignored
6141 Constant c = element as Constant;
6143 if (!c.IsDefaultInitializer (array_element_type)) {
6144 ++const_initializers_count;
6147 only_constant_initializers = false;
6150 array_data.Add (element);
6157 public override Expression CreateExpressionTree (ResolveContext ec)
6161 if (array_data == null) {
6162 args = new Arguments (arguments.Count + 1);
6163 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
6164 foreach (Expression a in arguments)
6165 args.Add (new Argument (a.CreateExpressionTree (ec)));
6167 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6170 if (dimensions > 1) {
6171 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6175 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6176 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
6177 if (array_data != null) {
6178 for (int i = 0; i < array_data.Count; ++i) {
6179 Expression e = array_data [i];
6180 args.Add (new Argument (e.CreateExpressionTree (ec)));
6184 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6187 public void UpdateIndices ()
6190 for (var probe = initializers; probe != null;) {
6191 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
6192 Expression e = new IntConstant (probe.Count, Location.Null);
6195 bounds [i++] = probe.Count;
6197 probe = (ArrayInitializer) probe[0];
6200 Expression e = new IntConstant (probe.Count, Location.Null);
6203 bounds [i++] = probe.Count;
6209 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
6211 element = element.Resolve (ec);
6212 if (element == null)
6215 if (element is CompoundAssign.TargetExpression) {
6216 if (first_emit != null)
6217 throw new InternalErrorException ("Can only handle one mutator at a time");
6218 first_emit = element;
6219 element = first_emit_temp = new LocalTemporary (element.Type);
6222 return Convert.ImplicitConversionRequired (
6223 ec, element, array_element_type, loc);
6226 protected bool ResolveInitializers (ResolveContext ec)
6228 only_constant_initializers = true;
6230 if (arguments != null) {
6232 for (int i = 0; i < arguments.Count; ++i) {
6233 res &= CheckIndices (ec, initializers, i, true, dimensions);
6234 if (initializers != null)
6241 arguments = new List<Expression> ();
6243 if (!CheckIndices (ec, initializers, 0, false, dimensions))
6252 // Resolved the type of the array
6254 bool ResolveArrayType (ResolveContext ec)
6259 FullNamedExpression array_type_expr;
6260 if (num_arguments > 0) {
6261 array_type_expr = new ComposedCast (requested_base_type, rank);
6263 array_type_expr = requested_base_type;
6266 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6267 if (array_type_expr == null)
6270 type = array_type_expr.Type;
6271 var ac = type as ArrayContainer;
6273 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6277 array_element_type = ac.Element;
6278 dimensions = ac.Rank;
6283 protected override Expression DoResolve (ResolveContext ec)
6288 if (!ResolveArrayType (ec))
6292 // validate the initializers and fill in any missing bits
6294 if (!ResolveInitializers (ec))
6297 eclass = ExprClass.Value;
6301 byte [] MakeByteBlob ()
6306 int count = array_data.Count;
6308 TypeSpec element_type = array_element_type;
6309 if (TypeManager.IsEnumType (element_type))
6310 element_type = EnumSpec.GetUnderlyingType (element_type);
6312 factor = GetTypeSize (element_type);
6314 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6316 data = new byte [(count * factor + 3) & ~3];
6319 for (int i = 0; i < count; ++i) {
6320 object v = array_data [i];
6322 if (v is EnumConstant)
6323 v = ((EnumConstant) v).Child;
6325 if (v is Constant && !(v is StringConstant))
6326 v = ((Constant) v).GetValue ();
6332 if (element_type == TypeManager.int64_type){
6333 if (!(v is Expression)){
6334 long val = (long) v;
6336 for (int j = 0; j < factor; ++j) {
6337 data [idx + j] = (byte) (val & 0xFF);
6341 } else if (element_type == TypeManager.uint64_type){
6342 if (!(v is Expression)){
6343 ulong val = (ulong) v;
6345 for (int j = 0; j < factor; ++j) {
6346 data [idx + j] = (byte) (val & 0xFF);
6350 } else if (element_type == TypeManager.float_type) {
6351 if (!(v is Expression)){
6352 element = BitConverter.GetBytes ((float) v);
6354 for (int j = 0; j < factor; ++j)
6355 data [idx + j] = element [j];
6356 if (!BitConverter.IsLittleEndian)
6357 System.Array.Reverse (data, idx, 4);
6359 } else if (element_type == TypeManager.double_type) {
6360 if (!(v is Expression)){
6361 element = BitConverter.GetBytes ((double) v);
6363 for (int j = 0; j < factor; ++j)
6364 data [idx + j] = element [j];
6366 // FIXME: Handle the ARM float format.
6367 if (!BitConverter.IsLittleEndian)
6368 System.Array.Reverse (data, idx, 8);
6370 } else if (element_type == TypeManager.char_type){
6371 if (!(v is Expression)){
6372 int val = (int) ((char) v);
6374 data [idx] = (byte) (val & 0xff);
6375 data [idx+1] = (byte) (val >> 8);
6377 } else if (element_type == TypeManager.short_type){
6378 if (!(v is Expression)){
6379 int val = (int) ((short) v);
6381 data [idx] = (byte) (val & 0xff);
6382 data [idx+1] = (byte) (val >> 8);
6384 } else if (element_type == TypeManager.ushort_type){
6385 if (!(v is Expression)){
6386 int val = (int) ((ushort) v);
6388 data [idx] = (byte) (val & 0xff);
6389 data [idx+1] = (byte) (val >> 8);
6391 } else if (element_type == TypeManager.int32_type) {
6392 if (!(v is Expression)){
6395 data [idx] = (byte) (val & 0xff);
6396 data [idx+1] = (byte) ((val >> 8) & 0xff);
6397 data [idx+2] = (byte) ((val >> 16) & 0xff);
6398 data [idx+3] = (byte) (val >> 24);
6400 } else if (element_type == TypeManager.uint32_type) {
6401 if (!(v is Expression)){
6402 uint val = (uint) v;
6404 data [idx] = (byte) (val & 0xff);
6405 data [idx+1] = (byte) ((val >> 8) & 0xff);
6406 data [idx+2] = (byte) ((val >> 16) & 0xff);
6407 data [idx+3] = (byte) (val >> 24);
6409 } else if (element_type == TypeManager.sbyte_type) {
6410 if (!(v is Expression)){
6411 sbyte val = (sbyte) v;
6412 data [idx] = (byte) val;
6414 } else if (element_type == TypeManager.byte_type) {
6415 if (!(v is Expression)){
6416 byte val = (byte) v;
6417 data [idx] = (byte) val;
6419 } else if (element_type == TypeManager.bool_type) {
6420 if (!(v is Expression)){
6421 bool val = (bool) v;
6422 data [idx] = (byte) (val ? 1 : 0);
6424 } else if (element_type == TypeManager.decimal_type){
6425 if (!(v is Expression)){
6426 int [] bits = Decimal.GetBits ((decimal) v);
6429 // FIXME: For some reason, this doesn't work on the MS runtime.
6430 int [] nbits = new int [4];
6431 nbits [0] = bits [3];
6432 nbits [1] = bits [2];
6433 nbits [2] = bits [0];
6434 nbits [3] = bits [1];
6436 for (int j = 0; j < 4; j++){
6437 data [p++] = (byte) (nbits [j] & 0xff);
6438 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6439 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6440 data [p++] = (byte) (nbits [j] >> 24);
6444 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6454 public override SLE.Expression MakeExpression (BuilderContext ctx)
6457 return base.MakeExpression (ctx);
6459 var initializers = new SLE.Expression [array_data.Count];
6460 for (var i = 0; i < initializers.Length; i++) {
6461 if (array_data [i] == null)
6462 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
6464 initializers [i] = array_data [i].MakeExpression (ctx);
6467 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
6472 // Emits the initializers for the array
6474 void EmitStaticInitializers (EmitContext ec)
6476 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6477 var helper = ec.CurrentTypeDefinition.Module.PredefinedTypes.RuntimeHelpers.Resolve (loc);
6481 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6482 helper, "InitializeArray", loc,
6483 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6484 if (TypeManager.void_initializearray_array_fieldhandle == null)
6489 // First, the static data
6491 byte [] data = MakeByteBlob ();
6492 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
6494 ec.Emit (OpCodes.Dup);
6495 ec.Emit (OpCodes.Ldtoken, fb);
6496 ec.Emit (OpCodes.Call, TypeManager.void_initializearray_array_fieldhandle);
6500 // Emits pieces of the array that can not be computed at compile
6501 // time (variables and string locations).
6503 // This always expect the top value on the stack to be the array
6505 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6507 int dims = bounds.Count;
6508 var current_pos = new int [dims];
6510 for (int i = 0; i < array_data.Count; i++){
6512 Expression e = array_data [i];
6513 var c = e as Constant;
6515 // Constant can be initialized via StaticInitializer
6516 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
6517 TypeSpec etype = e.Type;
6519 ec.Emit (OpCodes.Dup);
6521 for (int idx = 0; idx < dims; idx++)
6522 ec.EmitInt (current_pos [idx]);
6525 // If we are dealing with a struct, get the
6526 // address of it, so we can store it.
6528 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6529 (!TypeManager.IsBuiltinOrEnum (etype) ||
6530 etype == TypeManager.decimal_type)) {
6532 ec.Emit (OpCodes.Ldelema, etype);
6537 ec.EmitArrayStore ((ArrayContainer) type);
6543 for (int j = dims - 1; j >= 0; j--){
6545 if (current_pos [j] < bounds [j])
6547 current_pos [j] = 0;
6552 public override void Emit (EmitContext ec)
6554 if (first_emit != null) {
6555 first_emit.Emit (ec);
6556 first_emit_temp.Store (ec);
6559 foreach (Expression e in arguments)
6562 ec.EmitArrayNew ((ArrayContainer) type);
6564 if (initializers == null)
6567 // Emit static initializer for arrays which have contain more than 2 items and
6568 // the static initializer will initialize at least 25% of array values or there
6569 // is more than 10 items to be initialized
6570 // NOTE: const_initializers_count does not contain default constant values.
6571 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
6572 (TypeManager.IsPrimitiveType (array_element_type) || TypeManager.IsEnumType (array_element_type))) {
6573 EmitStaticInitializers (ec);
6575 if (!only_constant_initializers)
6576 EmitDynamicInitializers (ec, false);
6578 EmitDynamicInitializers (ec, true);
6581 if (first_emit_temp != null)
6582 first_emit_temp.Release (ec);
6585 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
6587 // no multi dimensional or jagged arrays
6588 if (arguments.Count != 1 || array_element_type.IsArray) {
6589 base.EncodeAttributeValue (rc, enc, targetType);
6593 // No array covariance, except for array -> object
6594 if (type != targetType) {
6595 if (targetType != TypeManager.object_type) {
6596 base.EncodeAttributeValue (rc, enc, targetType);
6600 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
6601 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
6606 // Single dimensional array of 0 size
6607 if (array_data == null) {
6608 IntConstant ic = arguments[0] as IntConstant;
6609 if (ic == null || !ic.IsDefaultValue) {
6610 base.EncodeAttributeValue (rc, enc, targetType);
6612 enc.Stream.Write (0);
6618 enc.Stream.Write ((int) array_data.Count);
6619 foreach (var element in array_data) {
6620 element.EncodeAttributeValue (rc, enc, array_element_type);
6624 protected override void CloneTo (CloneContext clonectx, Expression t)
6626 ArrayCreation target = (ArrayCreation) t;
6628 if (requested_base_type != null)
6629 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6631 if (arguments != null){
6632 target.arguments = new List<Expression> (arguments.Count);
6633 foreach (Expression e in arguments)
6634 target.arguments.Add (e.Clone (clonectx));
6637 if (initializers != null)
6638 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
6643 // Represents an implicitly typed array epxression
6645 class ImplicitlyTypedArrayCreation : ArrayCreation
6647 sealed class InferenceContext : TypeInferenceContext
6649 class ExpressionBoundInfo : BoundInfo
6651 readonly Expression expr;
6653 public ExpressionBoundInfo (Expression expr)
6654 : base (expr.Type, BoundKind.Lower)
6659 public override bool Equals (BoundInfo other)
6661 // We are using expression not type for conversion check
6662 // no optimization based on types is possible
6666 public override Expression GetTypeExpression ()
6672 public void AddExpression (Expression expr)
6674 AddToBounds (new ExpressionBoundInfo (expr), 0);
6678 InferenceContext best_type_inference;
6680 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6681 : base (null, rank, initializers, loc)
6685 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
6686 : base (null, initializers, loc)
6690 protected override Expression DoResolve (ResolveContext ec)
6695 dimensions = rank.Dimension;
6697 best_type_inference = new InferenceContext ();
6699 if (!ResolveInitializers (ec))
6702 best_type_inference.FixAllTypes (ec);
6703 array_element_type = best_type_inference.InferredTypeArguments[0];
6704 best_type_inference = null;
6706 if (array_element_type == null || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
6707 arguments.Count != rank.Dimension) {
6708 ec.Report.Error (826, loc,
6709 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6714 // At this point we found common base type for all initializer elements
6715 // but we have to be sure that all static initializer elements are of
6718 UnifyInitializerElement (ec);
6720 type = ArrayContainer.MakeType (array_element_type, dimensions);
6721 eclass = ExprClass.Value;
6726 // Converts static initializer only
6728 void UnifyInitializerElement (ResolveContext ec)
6730 for (int i = 0; i < array_data.Count; ++i) {
6731 Expression e = array_data[i];
6733 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6737 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6739 element = element.Resolve (ec);
6740 if (element != null)
6741 best_type_inference.AddExpression (element);
6747 sealed class CompilerGeneratedThis : This
6749 public static This Instance = new CompilerGeneratedThis ();
6751 private CompilerGeneratedThis ()
6752 : base (Location.Null)
6756 public CompilerGeneratedThis (TypeSpec type, Location loc)
6762 protected override Expression DoResolve (ResolveContext ec)
6764 eclass = ExprClass.Variable;
6766 type = ec.CurrentType;
6771 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6778 /// Represents the `this' construct
6781 public class This : VariableReference
6783 sealed class ThisVariable : ILocalVariable
6785 public static readonly ILocalVariable Instance = new ThisVariable ();
6787 public void Emit (EmitContext ec)
6789 ec.Emit (OpCodes.Ldarg_0);
6792 public void EmitAssign (EmitContext ec)
6794 throw new InvalidOperationException ();
6797 public void EmitAddressOf (EmitContext ec)
6799 ec.Emit (OpCodes.Ldarg_0);
6803 VariableInfo variable_info;
6805 public This (Location loc)
6812 public override string Name {
6813 get { return "this"; }
6816 public override bool IsLockedByStatement {
6824 public override bool IsRef {
6825 get { return type.IsStruct; }
6828 protected override ILocalVariable Variable {
6829 get { return ThisVariable.Instance; }
6832 public override VariableInfo VariableInfo {
6833 get { return variable_info; }
6836 public override bool IsFixed {
6837 get { return false; }
6842 public void CheckStructThisDefiniteAssignment (ResolveContext rc)
6844 if (variable_info != null && !variable_info.IsAssigned (rc)) {
6845 rc.Report.Error (188, loc,
6846 "The `this' object cannot be used before all of its fields are assigned to");
6850 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
6852 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6853 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6854 } else if (ec.CurrentAnonymousMethod != null) {
6855 ec.Report.Error (1673, loc,
6856 "Anonymous methods inside structs cannot access instance members of `this'. " +
6857 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6859 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6863 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6868 AnonymousMethodStorey storey = ae.Storey;
6869 while (storey != null) {
6870 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6872 return storey.HoistedThis;
6880 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
6882 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
6885 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
6888 if (TypeManager.IsStruct (ec.CurrentType) && ec.CurrentIterator == null)
6894 public virtual void ResolveBase (ResolveContext ec)
6896 eclass = ExprClass.Variable;
6897 type = ec.CurrentType;
6899 if (!IsThisAvailable (ec, false)) {
6900 Error_ThisNotAvailable (ec);
6904 var block = ec.CurrentBlock;
6905 if (block != null) {
6906 if (block.ParametersBlock.TopBlock.ThisVariable != null)
6907 variable_info = block.ParametersBlock.TopBlock.ThisVariable.VariableInfo;
6909 AnonymousExpression am = ec.CurrentAnonymousMethod;
6910 if (am != null && ec.IsVariableCapturingRequired) {
6911 am.SetHasThisAccess ();
6916 public override Expression CreateExpressionTree (ResolveContext ec)
6918 Arguments args = new Arguments (1);
6919 args.Add (new Argument (this));
6921 // Use typeless constant for ldarg.0 to save some
6922 // space and avoid problems with anonymous stories
6923 return CreateExpressionFactoryCall (ec, "Constant", args);
6926 protected override Expression DoResolve (ResolveContext ec)
6930 if (variable_info != null && type.IsStruct) {
6931 CheckStructThisDefiniteAssignment (ec);
6937 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6941 if (variable_info != null)
6942 variable_info.SetAssigned (ec);
6945 if (right_side == EmptyExpression.UnaryAddress)
6946 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6947 else if (right_side == EmptyExpression.OutAccess.Instance)
6948 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6950 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6956 public override int GetHashCode()
6958 throw new NotImplementedException ();
6961 public override bool Equals (object obj)
6963 This t = obj as This;
6970 protected override void CloneTo (CloneContext clonectx, Expression t)
6975 public override void SetHasAddressTaken ()
6982 /// Represents the `__arglist' construct
6984 public class ArglistAccess : Expression
6986 public ArglistAccess (Location loc)
6991 public override Expression CreateExpressionTree (ResolveContext ec)
6993 throw new NotSupportedException ("ET");
6996 protected override Expression DoResolve (ResolveContext ec)
6998 eclass = ExprClass.Variable;
6999 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve (loc);
7001 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7002 ec.Report.Error (190, loc,
7003 "The __arglist construct is valid only within a variable argument method");
7009 public override void Emit (EmitContext ec)
7011 ec.Emit (OpCodes.Arglist);
7014 protected override void CloneTo (CloneContext clonectx, Expression target)
7021 /// Represents the `__arglist (....)' construct
7023 public class Arglist : Expression
7025 Arguments Arguments;
7027 public Arglist (Location loc)
7032 public Arglist (Arguments args, Location l)
7038 public MetaType[] ArgumentTypes {
7040 if (Arguments == null)
7041 return MetaType.EmptyTypes;
7043 var retval = new MetaType[Arguments.Count];
7044 for (int i = 0; i < retval.Length; i++)
7045 retval[i] = Arguments[i].Expr.Type.GetMetaInfo ();
7051 public override Expression CreateExpressionTree (ResolveContext ec)
7053 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7057 protected override Expression DoResolve (ResolveContext ec)
7059 eclass = ExprClass.Variable;
7060 type = InternalType.Arglist;
7061 if (Arguments != null) {
7062 bool dynamic; // Can be ignored as there is always only 1 overload
7063 Arguments.Resolve (ec, out dynamic);
7069 public override void Emit (EmitContext ec)
7071 if (Arguments != null)
7072 Arguments.Emit (ec);
7075 protected override void CloneTo (CloneContext clonectx, Expression t)
7077 Arglist target = (Arglist) t;
7079 if (Arguments != null)
7080 target.Arguments = Arguments.Clone (clonectx);
7085 /// Implements the typeof operator
7087 public class TypeOf : Expression {
7088 FullNamedExpression QueriedType;
7091 public TypeOf (FullNamedExpression queried_type, Location l)
7093 QueriedType = queried_type;
7098 public TypeSpec TypeArgument {
7104 public FullNamedExpression TypeExpression {
7112 public override Expression CreateExpressionTree (ResolveContext ec)
7114 Arguments args = new Arguments (2);
7115 args.Add (new Argument (this));
7116 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7117 return CreateExpressionFactoryCall (ec, "Constant", args);
7120 protected override Expression DoResolve (ResolveContext ec)
7125 // Pointer types are allowed without explicit unsafe, they are just tokens
7127 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
7128 texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7134 typearg = texpr.Type;
7136 if (typearg == TypeManager.void_type && !(QueriedType is TypeExpression)) {
7137 ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
7138 } else if (texpr is DynamicTypeExpr) {
7139 ec.Report.Error (1962, QueriedType.Location,
7140 "The typeof operator cannot be used on the dynamic type");
7143 type = TypeManager.type_type;
7144 QueriedType = texpr;
7146 return DoResolveBase ();
7149 protected Expression DoResolveBase ()
7151 if (TypeManager.system_type_get_type_from_handle == null) {
7152 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
7153 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
7156 // Even though what is returned is a type object, it's treated as a value by the compiler.
7157 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7158 eclass = ExprClass.Value;
7162 static bool ContainsDynamicType (TypeSpec type)
7164 if (type == InternalType.Dynamic)
7167 var element_container = type as ElementTypeSpec;
7168 if (element_container != null)
7169 return ContainsDynamicType (element_container.Element);
7171 foreach (var t in type.TypeArguments) {
7172 if (ContainsDynamicType (t)) {
7180 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7182 // Target type is not System.Type therefore must be object
7183 // and we need to use different encoding sequence
7184 if (targetType != type)
7187 if (!(QueriedType is GenericOpenTypeExpr)) {
7189 while (gt != null) {
7190 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
7191 rc.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7192 typearg.GetSignatureForError ());
7196 gt = gt.DeclaringType;
7199 if (ContainsDynamicType (typearg)) {
7200 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7205 enc.EncodeTypeName (typearg);
7208 public override void Emit (EmitContext ec)
7210 ec.Emit (OpCodes.Ldtoken, typearg);
7211 ec.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
7214 protected override void CloneTo (CloneContext clonectx, Expression t)
7216 TypeOf target = (TypeOf) t;
7217 if (QueriedType != null)
7218 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
7222 class TypeOfMethod : TypeOfMember<MethodSpec>
7224 public TypeOfMethod (MethodSpec method, Location loc)
7225 : base (method, loc)
7229 protected override Expression DoResolve (ResolveContext ec)
7231 if (member.IsConstructor) {
7232 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve (loc);
7234 type = ec.Module.PredefinedTypes.MethodInfo.Resolve (loc);
7240 return base.DoResolve (ec);
7243 public override void Emit (EmitContext ec)
7245 ec.Emit (OpCodes.Ldtoken, member);
7248 ec.Emit (OpCodes.Castclass, type);
7251 protected override string GetMethodName {
7252 get { return "GetMethodFromHandle"; }
7255 protected override PredefinedType GetDeclaringType (PredefinedTypes types)
7257 return types.MethodBase;
7260 protected override PredefinedType GetRuntimeHandle (PredefinedTypes types)
7262 return types.RuntimeMethodHandle;
7265 protected override MethodSpec TypeFromHandle {
7267 return TypeManager.methodbase_get_type_from_handle;
7270 TypeManager.methodbase_get_type_from_handle = value;
7274 protected override MethodSpec TypeFromHandleGeneric {
7276 return TypeManager.methodbase_get_type_from_handle_generic;
7279 TypeManager.methodbase_get_type_from_handle_generic = value;
7284 abstract class TypeOfMember<T> : Expression where T : MemberSpec
7286 protected readonly T member;
7288 protected TypeOfMember (T member, Location loc)
7290 this.member = member;
7294 public override Expression CreateExpressionTree (ResolveContext ec)
7296 Arguments args = new Arguments (2);
7297 args.Add (new Argument (this));
7298 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7299 return CreateExpressionFactoryCall (ec, "Constant", args);
7302 protected override Expression DoResolve (ResolveContext ec)
7304 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
7305 var mi = is_generic ? TypeFromHandleGeneric : TypeFromHandle;
7308 TypeSpec declaring_type = GetDeclaringType (ec.Module.PredefinedTypes).Resolve (loc);
7309 TypeSpec handle_type = GetRuntimeHandle (ec.Module.PredefinedTypes).Resolve (loc);
7311 if (handle_type == null || declaring_type == null)
7314 mi = TypeManager.GetPredefinedMethod (declaring_type, GetMethodName, loc,
7316 new TypeSpec[] { handle_type, TypeManager.runtime_handle_type } :
7317 new TypeSpec[] { handle_type } );
7320 TypeFromHandleGeneric = mi;
7322 TypeFromHandle = mi;
7325 eclass = ExprClass.Value;
7329 public override void Emit (EmitContext ec)
7331 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
7334 mi = TypeFromHandleGeneric;
7335 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
7337 mi = TypeFromHandle;
7340 ec.Emit (OpCodes.Call, mi);
7343 protected abstract PredefinedType GetDeclaringType (PredefinedTypes types);
7344 protected abstract string GetMethodName { get; }
7345 protected abstract PredefinedType GetRuntimeHandle (PredefinedTypes types);
7346 protected abstract MethodSpec TypeFromHandle { get; set; }
7347 protected abstract MethodSpec TypeFromHandleGeneric { get; set; }
7350 class TypeOfField : TypeOfMember<FieldSpec>
7352 public TypeOfField (FieldSpec field, Location loc)
7357 protected override Expression DoResolve (ResolveContext ec)
7359 type = ec.Module.PredefinedTypes.FieldInfo.Resolve (loc);
7363 return base.DoResolve (ec);
7366 public override void Emit (EmitContext ec)
7368 ec.Emit (OpCodes.Ldtoken, member);
7372 protected override PredefinedType GetDeclaringType (PredefinedTypes types)
7374 return types.FieldInfo;
7377 protected override string GetMethodName {
7378 get { return "GetFieldFromHandle"; }
7381 protected override PredefinedType GetRuntimeHandle (PredefinedTypes types)
7383 return types.RuntimeFieldHandle;
7386 protected override MethodSpec TypeFromHandle {
7388 return TypeManager.fieldinfo_get_field_from_handle;
7391 TypeManager.fieldinfo_get_field_from_handle = value;
7395 protected override MethodSpec TypeFromHandleGeneric {
7397 return TypeManager.fieldinfo_get_field_from_handle_generic;
7400 TypeManager.fieldinfo_get_field_from_handle_generic = value;
7406 /// Implements the sizeof expression
7408 public class SizeOf : Expression {
7409 readonly Expression QueriedType;
7410 TypeSpec type_queried;
7412 public SizeOf (Expression queried_type, Location l)
7414 this.QueriedType = queried_type;
7418 public override Expression CreateExpressionTree (ResolveContext ec)
7420 Error_PointerInsideExpressionTree (ec);
7424 protected override Expression DoResolve (ResolveContext ec)
7426 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7430 type_queried = texpr.Type;
7431 if (TypeManager.IsEnumType (type_queried))
7432 type_queried = EnumSpec.GetUnderlyingType (type_queried);
7434 int size_of = GetTypeSize (type_queried);
7436 return new IntConstant (size_of, loc).Resolve (ec);
7439 if (!TypeManager.VerifyUnmanaged (ec.Compiler, type_queried, loc)){
7444 ec.Report.Error (233, loc,
7445 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7446 TypeManager.CSharpName (type_queried));
7449 type = TypeManager.int32_type;
7450 eclass = ExprClass.Value;
7454 public override void Emit (EmitContext ec)
7456 ec.Emit (OpCodes.Sizeof, type_queried);
7459 protected override void CloneTo (CloneContext clonectx, Expression t)
7465 /// Implements the qualified-alias-member (::) expression.
7467 public class QualifiedAliasMember : MemberAccess
7469 readonly string alias;
7470 public static readonly string GlobalAlias = "global";
7472 public QualifiedAliasMember (string alias, string identifier, Location l)
7473 : base (null, identifier, l)
7478 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7479 : base (null, identifier, targs, l)
7484 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
7485 : base (null, identifier, arity, l)
7490 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7492 if (alias == GlobalAlias) {
7493 expr = ec.Module.GlobalRootNamespace;
7494 return base.ResolveAsTypeStep (ec, silent);
7497 int errors = ec.Compiler.Report.Errors;
7498 expr = ec.LookupNamespaceAlias (alias);
7500 if (errors == ec.Compiler.Report.Errors)
7501 ec.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7505 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7509 if (expr.eclass == ExprClass.Type) {
7511 ec.Compiler.Report.Error (431, loc,
7512 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7520 protected override Expression DoResolve (ResolveContext ec)
7522 return ResolveAsTypeStep (ec, false);
7525 protected override void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7527 rc.Compiler.Report.Error (687, loc,
7528 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7529 GetSignatureForError ());
7532 public override string GetSignatureForError ()
7535 if (targs != null) {
7536 name = Name + "<" + targs.GetSignatureForError () + ">";
7539 return alias + "::" + name;
7542 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7544 return DoResolve (rc);
7547 protected override void CloneTo (CloneContext clonectx, Expression t)
7554 /// Implements the member access expression
7556 public class MemberAccess : ATypeNameExpression
7558 protected Expression expr;
7560 public MemberAccess (Expression expr, string id)
7561 : base (id, expr.Location)
7566 public MemberAccess (Expression expr, string identifier, Location loc)
7567 : base (identifier, loc)
7572 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7573 : base (identifier, args, loc)
7578 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
7579 : base (identifier, arity, loc)
7584 public Expression LeftExpression {
7590 protected override Expression DoResolve (ResolveContext ec)
7592 return DoResolveName (ec, null);
7595 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7597 return DoResolveName (ec, right_side);
7600 Expression DoResolveName (ResolveContext rc, Expression right_side)
7602 Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
7606 if (right_side != null) {
7607 if (e is TypeExpr) {
7608 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
7612 e = e.ResolveLValue (rc, right_side);
7614 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
7620 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7622 var sn = expr as SimpleName;
7623 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
7626 // Resolve the expression with flow analysis turned off, we'll do the definite
7627 // assignment checks later. This is because we don't know yet what the expression
7628 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7629 // definite assignment check on the actual field and not on the whole struct.
7631 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
7633 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
7635 // Call resolve on expression which does have type set as we need expression type
7636 // TODO: I should probably ensure that the type is always set and leave resolve for the final
7637 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
7638 using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
7639 expr = expr.Resolve (rc);
7641 } else if (expr is TypeParameterExpr) {
7642 expr.Error_UnexpectedKind (rc, flags, sn.Location);
7646 expr = expr.Resolve (rc, flags);
7653 Namespace ns = expr as Namespace;
7655 FullNamedExpression retval = ns.Lookup (rc.Compiler, Name, Arity, loc);
7657 if (retval == null) {
7658 ns.Error_NamespaceDoesNotExist (loc, Name, Arity, rc);
7662 if (HasTypeArguments)
7663 return new GenericTypeExpr (retval.Type, targs, loc);
7669 TypeSpec expr_type = expr.Type;
7670 if (expr_type == InternalType.Dynamic) {
7671 me = expr as MemberExpr;
7673 me.ResolveInstanceExpression (rc, null);
7675 Arguments args = new Arguments (1);
7676 args.Add (new Argument (expr));
7677 return new DynamicMemberBinder (Name, args, loc);
7680 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
7681 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
7683 if ((expr_type.Kind & dot_kinds) == 0 || expr_type == TypeManager.void_type) {
7684 if (expr_type == InternalType.Null && rc.Compiler.IsRuntimeBinder)
7685 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
7687 Unary.Error_OperatorCannotBeApplied (rc, loc, ".", expr_type);
7691 var current_type = rc.CurrentType;
7692 var lookup_arity = Arity;
7693 bool errorMode = false;
7694 Expression member_lookup;
7696 member_lookup = MemberLookup (errorMode ? null : rc, current_type, expr_type, Name, lookup_arity, restrictions, loc);
7697 if (member_lookup == null) {
7699 // Try to look for extension method when member lookup failed
7701 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
7702 NamespaceEntry scope = null;
7703 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity, ref scope);
7704 if (methods != null) {
7705 var emg = new ExtensionMethodGroupExpr (methods, scope, expr, loc);
7706 if (HasTypeArguments) {
7707 if (!targs.Resolve (rc))
7710 emg.SetTypeArguments (rc, targs);
7713 // TODO: it should really skip the checks bellow
7714 return emg.Resolve (rc);
7720 if (member_lookup == null) {
7721 if (expr is TypeExpr)
7722 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
7724 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
7729 if (member_lookup is MethodGroupExpr) {
7730 // Leave it to overload resolution to report correct error
7732 // TODO: rc.SymbolRelatedToPreviousError
7733 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
7738 if (member_lookup != null)
7741 current_type = null;
7743 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
7747 TypeExpr texpr = member_lookup as TypeExpr;
7748 if (texpr != null) {
7749 if (!(expr is TypeExpr)) {
7750 me = expr as MemberExpr;
7751 if (me == null || me.ProbeIdenticalTypeName (rc, expr, sn) == expr) {
7752 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7753 Name, member_lookup.GetSignatureForError ());
7758 if (!texpr.Type.IsAccessible (rc.CurrentType)) {
7759 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
7760 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
7764 if (HasTypeArguments) {
7765 return new GenericTypeExpr (member_lookup.Type, targs, loc);
7768 return member_lookup;
7771 me = member_lookup as MemberExpr;
7773 if (sn != null && me.IsStatic)
7774 expr = me.ProbeIdenticalTypeName (rc, expr, sn);
7776 me = me.ResolveMemberAccess (rc, expr, sn);
7779 if (!targs.Resolve (rc))
7782 me.SetTypeArguments (rc, targs);
7785 if (sn != null && (!TypeManager.IsValueType (expr_type) || me is PropertyExpr)) {
7786 if (me.IsInstance) {
7787 LocalVariableReference var = expr as LocalVariableReference;
7788 if (var != null && !var.VerifyAssigned (rc))
7796 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7798 return ResolveNamespaceOrType (ec, silent);
7801 public FullNamedExpression ResolveNamespaceOrType (IMemberContext rc, bool silent)
7803 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7805 if (expr_resolved == null)
7808 Namespace ns = expr_resolved as Namespace;
7810 FullNamedExpression retval = ns.Lookup (rc.Compiler, Name, Arity, loc);
7812 if (retval == null) {
7814 ns.Error_NamespaceDoesNotExist (loc, Name, Arity, rc);
7815 } else if (HasTypeArguments) {
7816 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7822 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7823 if (tnew_expr == null)
7826 TypeSpec expr_type = tnew_expr.Type;
7827 if (TypeManager.IsGenericParameter (expr_type)) {
7828 rc.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7829 tnew_expr.GetSignatureForError ());
7833 TypeSpec nested = null;
7834 while (expr_type != null) {
7835 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7836 if (nested == null) {
7840 if (expr_type == tnew_expr.Type) {
7841 Error_IdentifierNotFound (rc, expr_type, Name);
7845 expr_type = tnew_expr.Type;
7846 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7847 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
7851 if (nested.IsAccessible (rc.CurrentType))
7854 // Keep looking after inaccessible candidate
7855 expr_type = nested.DeclaringType.BaseType;
7860 if (HasTypeArguments) {
7861 texpr = new GenericTypeExpr (nested, targs, loc);
7863 texpr = new GenericOpenTypeExpr (nested, loc);
7866 texpr = new TypeExpression (nested, loc);
7869 return texpr.ResolveAsTypeStep (rc, false);
7872 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7874 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
7876 if (nested != null) {
7877 Error_TypeArgumentsCannotBeUsed (rc.Compiler.Report, expr.Location, nested, Arity);
7881 var any_other_member = MemberLookup (null, rc.CurrentType, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
7882 if (any_other_member != null) {
7883 any_other_member.Error_UnexpectedKind (rc.Compiler.Report, null, "type", loc);
7887 rc.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7888 Name, expr_type.GetSignatureForError ());
7891 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
7893 if (RootContext.Version > LanguageVersion.ISO_2 && !ec.Compiler.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
7894 ec.Report.SymbolRelatedToPreviousError (type);
7895 ec.Report.Error (1061, loc,
7896 "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?)",
7897 type.GetSignatureForError (), name);
7901 base.Error_TypeDoesNotContainDefinition (ec, type, name);
7904 public override string GetSignatureForError ()
7906 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7909 protected override void CloneTo (CloneContext clonectx, Expression t)
7911 MemberAccess target = (MemberAccess) t;
7913 target.expr = expr.Clone (clonectx);
7918 /// Implements checked expressions
7920 public class CheckedExpr : Expression {
7922 public Expression Expr;
7924 public CheckedExpr (Expression e, Location l)
7930 public override Expression CreateExpressionTree (ResolveContext ec)
7932 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7933 return Expr.CreateExpressionTree (ec);
7936 protected override Expression DoResolve (ResolveContext ec)
7938 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7939 Expr = Expr.Resolve (ec);
7944 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7947 eclass = Expr.eclass;
7952 public override void Emit (EmitContext ec)
7954 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7958 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7960 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7961 Expr.EmitBranchable (ec, target, on_true);
7964 public override SLE.Expression MakeExpression (BuilderContext ctx)
7966 using (ctx.With (BuilderContext.Options.AllCheckStateFlags, true)) {
7967 return Expr.MakeExpression (ctx);
7971 protected override void CloneTo (CloneContext clonectx, Expression t)
7973 CheckedExpr target = (CheckedExpr) t;
7975 target.Expr = Expr.Clone (clonectx);
7980 /// Implements the unchecked expression
7982 public class UnCheckedExpr : Expression {
7984 public Expression Expr;
7986 public UnCheckedExpr (Expression e, Location l)
7992 public override Expression CreateExpressionTree (ResolveContext ec)
7994 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7995 return Expr.CreateExpressionTree (ec);
7998 protected override Expression DoResolve (ResolveContext ec)
8000 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8001 Expr = Expr.Resolve (ec);
8006 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8009 eclass = Expr.eclass;
8014 public override void Emit (EmitContext ec)
8016 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
8020 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8022 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
8023 Expr.EmitBranchable (ec, target, on_true);
8026 protected override void CloneTo (CloneContext clonectx, Expression t)
8028 UnCheckedExpr target = (UnCheckedExpr) t;
8030 target.Expr = Expr.Clone (clonectx);
8035 /// An Element Access expression.
8037 /// During semantic analysis these are transformed into
8038 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
8040 public class ElementAccess : Expression {
8041 public Arguments Arguments;
8042 public Expression Expr;
8044 public ElementAccess (Expression e, Arguments args, Location loc)
8048 this.Arguments = args;
8052 // We perform some simple tests, and then to "split" the emit and store
8053 // code we create an instance of a different class, and return that.
8055 Expression CreateAccessExpression (ResolveContext ec)
8058 return (new ArrayAccess (this, loc));
8061 return MakePointerAccess (ec, type);
8063 FieldExpr fe = Expr as FieldExpr;
8065 var ff = fe.Spec as FixedFieldSpec;
8067 return MakePointerAccess (ec, ff.ElementType);
8071 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
8072 if (indexers != null || type == InternalType.Dynamic) {
8073 return new IndexerExpr (indexers, type, this);
8076 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8077 type.GetSignatureForError ());
8081 public override Expression CreateExpressionTree (ResolveContext ec)
8083 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
8084 Expr.CreateExpressionTree (ec));
8086 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
8089 Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
8091 if (Arguments.Count != 1){
8092 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
8096 if (Arguments [0] is NamedArgument)
8097 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
8099 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
8100 return new Indirection (p, loc);
8103 protected override Expression DoResolve (ResolveContext ec)
8105 Expr = Expr.Resolve (ec);
8111 // TODO: Create 1 result for Resolve and ResolveLValue ?
8112 var res = CreateAccessExpression (ec);
8116 return res.Resolve (ec);
8119 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8121 Expr = Expr.Resolve (ec);
8127 var res = CreateAccessExpression (ec);
8131 return res.ResolveLValue (ec, right_side);
8134 public override void Emit (EmitContext ec)
8136 throw new Exception ("Should never be reached");
8139 public static void Error_NamedArgument (NamedArgument na, Report Report)
8141 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
8144 public override string GetSignatureForError ()
8146 return Expr.GetSignatureForError ();
8149 protected override void CloneTo (CloneContext clonectx, Expression t)
8151 ElementAccess target = (ElementAccess) t;
8153 target.Expr = Expr.Clone (clonectx);
8154 if (Arguments != null)
8155 target.Arguments = Arguments.Clone (clonectx);
8160 /// Implements array access
8162 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
8164 // Points to our "data" repository
8168 LocalTemporary temp, expr_copy;
8169 Expression[] prepared_arguments;
8172 public ArrayAccess (ElementAccess ea_data, Location l)
8178 public override Expression CreateExpressionTree (ResolveContext ec)
8180 return ea.CreateExpressionTree (ec);
8183 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8185 return DoResolve (ec);
8188 protected override Expression DoResolve (ResolveContext ec)
8190 // dynamic is used per argument in ConvertExpressionToArrayIndex case
8192 ea.Arguments.Resolve (ec, out dynamic);
8194 var ac = ea.Expr.Type as ArrayContainer;
8195 int rank = ea.Arguments.Count;
8196 if (ac.Rank != rank) {
8197 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8198 rank.ToString (), ac.Rank.ToString ());
8203 if (type.IsPointer && !ec.IsUnsafe) {
8204 UnsafeError (ec, ea.Location);
8207 foreach (Argument a in ea.Arguments) {
8208 if (a is NamedArgument)
8209 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
8211 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
8214 eclass = ExprClass.Variable;
8219 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8221 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8225 // Load the array arguments into the stack.
8227 void LoadArrayAndArguments (EmitContext ec)
8230 ea.Arguments.Emit (ec);
8233 public void Emit (EmitContext ec, bool leave_copy)
8235 var ac = ea.Expr.Type as ArrayContainer;
8238 ec.EmitLoadFromPtr (type);
8240 if (prepared_arguments == null) {
8241 LoadArrayAndArguments (ec);
8243 expr_copy.Emit (ec);
8245 foreach (var expr in prepared_arguments) {
8247 lt = expr as LocalTemporary;
8253 ec.EmitArrayLoad (ac);
8257 ec.Emit (OpCodes.Dup);
8258 temp = new LocalTemporary (this.type);
8263 public override void Emit (EmitContext ec)
8268 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8270 var ac = (ArrayContainer) ea.Expr.Type;
8271 TypeSpec t = source.Type;
8274 // When we are dealing with a struct, get the address of it to avoid value copy
8275 // Same cannot be done for reference type because array covariance and the
8276 // check in ldelema requires to specify the type of array element stored at the index
8278 if (t.IsStruct && ((prepare_for_load && !(source is DynamicExpressionStatement)) || !TypeManager.IsPrimitiveType (t))) {
8279 LoadArrayAndArguments (ec);
8280 ec.EmitArrayAddress (ac);
8282 if (prepare_for_load) {
8283 ec.Emit (OpCodes.Dup);
8287 } else if (prepare_for_load) {
8289 ec.Emit (OpCodes.Dup);
8291 expr_copy = new LocalTemporary (ea.Expr.Type);
8292 expr_copy.Store (ec);
8293 prepared_arguments = ea.Arguments.Emit (ec, true);
8295 LoadArrayAndArguments (ec);
8300 if (expr_copy != null) {
8301 expr_copy.Release (ec);
8305 ec.Emit (OpCodes.Dup);
8306 temp = new LocalTemporary (this.type);
8311 ec.EmitStoreFromPtr (t);
8313 ec.EmitArrayStore (ac);
8322 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8324 if (!source.Emit (ec, this)) {
8326 throw new NotImplementedException ();
8331 throw new NotImplementedException ();
8334 public void AddressOf (EmitContext ec, AddressOp mode)
8336 var ac = (ArrayContainer) ea.Expr.Type;
8338 LoadArrayAndArguments (ec);
8339 ec.EmitArrayAddress (ac);
8342 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8345 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8347 throw new NotImplementedException ();
8351 public override SLE.Expression MakeExpression (BuilderContext ctx)
8353 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8356 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
8358 using (ctx.With (BuilderContext.Options.AllCheckStateFlags, true)) {
8359 return Arguments.MakeExpression (ea.Arguments, ctx);
8365 // Indexer access expression
8367 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
8369 LocalTemporary prepared_value;
8370 IList<MemberSpec> indexers;
8371 Arguments arguments;
8372 TypeSpec queried_type;
8374 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
8375 : base (ea.Location)
8377 this.indexers = indexers;
8378 this.queried_type = queriedType;
8379 this.InstanceExpression = ea.Expr;
8380 this.arguments = ea.Arguments;
8384 protected override TypeSpec DeclaringType {
8386 return best_candidate.DeclaringType;
8390 public override bool IsInstance {
8396 public override bool IsStatic {
8402 public override string Name {
8410 public override Expression CreateExpressionTree (ResolveContext ec)
8412 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8413 InstanceExpression.CreateExpressionTree (ec),
8414 new TypeOfMethod (Getter, loc));
8416 return CreateExpressionFactoryCall (ec, "Call", args);
8419 public override void Emit (EmitContext ec, bool leave_copy)
8422 prepared_value.Emit (ec);
8424 Invocation.EmitCall (ec, InstanceExpression, Getter, arguments, loc);
8428 ec.Emit (OpCodes.Dup);
8429 temp = new LocalTemporary (Type);
8434 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8436 prepared = prepare_for_load;
8437 Expression value = source;
8440 Invocation.EmitCall (ec, InstanceExpression, Getter, arguments, loc, true, false);
8442 prepared_value = new LocalTemporary (type);
8443 prepared_value.Store (ec);
8445 prepared_value.Release (ec);
8448 ec.Emit (OpCodes.Dup);
8449 temp = new LocalTemporary (Type);
8452 } else if (leave_copy) {
8453 temp = new LocalTemporary (Type);
8460 arguments.Add (new Argument (value));
8462 Invocation.EmitCall (ec, InstanceExpression, Setter, arguments, loc, false, prepared);
8470 public override string GetSignatureForError ()
8472 return best_candidate.GetSignatureForError ();
8475 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8478 throw new NotSupportedException ();
8480 var value = new[] { source.MakeExpression (ctx) };
8481 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
8483 return SLE.Expression.Block (
8484 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
8487 return args.First ();
8492 public override SLE.Expression MakeExpression (BuilderContext ctx)
8495 return base.MakeExpression (ctx);
8497 var args = Arguments.MakeExpression (arguments, ctx);
8498 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
8502 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
8504 if (best_candidate != null)
8507 eclass = ExprClass.IndexerAccess;
8510 arguments.Resolve (rc, out dynamic);
8512 if (indexers == null && InstanceExpression.Type == InternalType.Dynamic) {
8515 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
8516 res.BaseMembersProvider = this;
8518 // TODO: Do I need 2 argument sets?
8519 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
8520 if (best_candidate != null)
8521 type = res.BestCandidateReturnType;
8522 else if (!res.BestCandidateIsDynamic)
8527 // It has dynamic arguments
8530 Arguments args = new Arguments (arguments.Count + 1);
8532 rc.Report.Error (1972, loc,
8533 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8535 args.Add (new Argument (InstanceExpression));
8537 args.AddRange (arguments);
8539 best_candidate = null;
8540 return new DynamicIndexBinder (args, loc);
8543 ResolveInstanceExpression (rc, right_side);
8544 CheckProtectedMemberAccess (rc, best_candidate);
8548 protected override void CloneTo (CloneContext clonectx, Expression t)
8550 IndexerExpr target = (IndexerExpr) t;
8552 if (arguments != null)
8553 target.arguments = arguments.Clone (clonectx);
8556 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
8558 Error_TypeArgumentsCannotBeUsed (ec.Report, "indexer", GetSignatureForError (), loc);
8561 #region IBaseMembersProvider Members
8563 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
8565 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
8568 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
8570 if (queried_type == member.DeclaringType)
8573 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
8574 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
8577 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
8586 // A base access expression
8588 public class BaseThis : This
8590 public BaseThis (Location loc)
8595 public BaseThis (TypeSpec type, Location loc)
8599 eclass = ExprClass.Variable;
8604 public override string Name {
8612 public override Expression CreateExpressionTree (ResolveContext ec)
8614 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
8615 return base.CreateExpressionTree (ec);
8618 public override void Emit (EmitContext ec)
8622 if (ec.CurrentType.IsStruct) {
8623 ec.Emit (OpCodes.Ldobj, ec.CurrentType);
8624 ec.Emit (OpCodes.Box, ec.CurrentType);
8628 protected override void Error_ThisNotAvailable (ResolveContext ec)
8631 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
8633 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
8637 public override void ResolveBase (ResolveContext ec)
8639 base.ResolveBase (ec);
8640 type = ec.CurrentType.BaseType;
8645 /// This class exists solely to pass the Type around and to be a dummy
8646 /// that can be passed to the conversion functions (this is used by
8647 /// foreach implementation to typecast the object return value from
8648 /// get_Current into the proper type. All code has been generated and
8649 /// we only care about the side effect conversions to be performed
8651 /// This is also now used as a placeholder where a no-action expression
8652 /// is needed (the `New' class).
8654 public class EmptyExpression : Expression {
8655 public static readonly Expression Null = new EmptyExpression ();
8657 public class OutAccess : EmptyExpression
8659 public static readonly OutAccess Instance = new OutAccess ();
8661 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8663 rc.Report.Error (206, right_side.Location,
8664 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
8670 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8671 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8672 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8673 public static readonly EmptyExpression EventAddition = new EmptyExpression ();
8674 public static readonly EmptyExpression EventSubtraction = new EmptyExpression ();
8675 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
8677 static EmptyExpression temp = new EmptyExpression ();
8678 public static EmptyExpression Grab ()
8680 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8685 public static void Release (EmptyExpression e)
8692 // FIXME: Don't set to object
8693 type = TypeManager.object_type;
8694 eclass = ExprClass.Value;
8695 loc = Location.Null;
8698 public EmptyExpression (TypeSpec t)
8701 eclass = ExprClass.Value;
8702 loc = Location.Null;
8705 public override Expression CreateExpressionTree (ResolveContext ec)
8707 throw new NotSupportedException ("ET");
8710 protected override Expression DoResolve (ResolveContext ec)
8715 public override void Emit (EmitContext ec)
8717 // nothing, as we only exist to not do anything.
8720 public override void EmitSideEffect (EmitContext ec)
8725 // This is just because we might want to reuse this bad boy
8726 // instead of creating gazillions of EmptyExpressions.
8727 // (CanImplicitConversion uses it)
8729 public void SetType (TypeSpec t)
8736 // Empty statement expression
8738 public sealed class EmptyExpressionStatement : ExpressionStatement
8740 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8742 private EmptyExpressionStatement ()
8744 loc = Location.Null;
8747 public override Expression CreateExpressionTree (ResolveContext ec)
8752 public override void EmitStatement (EmitContext ec)
8757 protected override Expression DoResolve (ResolveContext ec)
8759 eclass = ExprClass.Value;
8760 type = TypeManager.object_type;
8764 public override void Emit (EmitContext ec)
8770 public class UserCast : Expression {
8774 public UserCast (MethodSpec method, Expression source, Location l)
8776 this.method = method;
8777 this.source = source;
8778 type = method.ReturnType;
8782 public Expression Source {
8788 public override Expression CreateExpressionTree (ResolveContext ec)
8790 Arguments args = new Arguments (3);
8791 args.Add (new Argument (source.CreateExpressionTree (ec)));
8792 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8793 args.Add (new Argument (new TypeOfMethod (method, loc)));
8794 return CreateExpressionFactoryCall (ec, "Convert", args);
8797 protected override Expression DoResolve (ResolveContext ec)
8799 ObsoleteAttribute oa = method.GetAttributeObsolete ();
8801 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
8803 eclass = ExprClass.Value;
8807 public override void Emit (EmitContext ec)
8810 ec.Emit (OpCodes.Call, method);
8813 public override string GetSignatureForError ()
8815 return TypeManager.CSharpSignature (method);
8818 public override SLE.Expression MakeExpression (BuilderContext ctx)
8821 return base.MakeExpression (ctx);
8823 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
8829 // Holds additional type specifiers like ?, *, []
8831 public class ComposedTypeSpecifier
8833 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
8835 public readonly int Dimension;
8836 public readonly Location Location;
8838 public ComposedTypeSpecifier (int specifier, Location loc)
8840 this.Dimension = specifier;
8841 this.Location = loc;
8845 public bool IsNullable {
8847 return Dimension == -1;
8851 public bool IsPointer {
8853 return Dimension == -2;
8857 public ComposedTypeSpecifier Next { get; set; }
8861 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
8863 return new ComposedTypeSpecifier (dimension, loc);
8866 public static ComposedTypeSpecifier CreateNullable (Location loc)
8868 return new ComposedTypeSpecifier (-1, loc);
8871 public static ComposedTypeSpecifier CreatePointer (Location loc)
8873 return new ComposedTypeSpecifier (-2, loc);
8876 public string GetSignatureForError ()
8881 ArrayContainer.GetPostfixSignature (Dimension);
8883 return Next != null ? s + Next.GetSignatureForError () : s;
8888 // This class is used to "construct" the type during a typecast
8889 // operation. Since the Type.GetType class in .NET can parse
8890 // the type specification, we just use this to construct the type
8891 // one bit at a time.
8893 public class ComposedCast : TypeExpr {
8894 FullNamedExpression left;
8895 ComposedTypeSpecifier spec;
8897 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
8900 throw new ArgumentNullException ("spec");
8904 this.loc = spec.Location;
8907 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
8909 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8914 eclass = ExprClass.Type;
8916 var single_spec = spec;
8918 if (single_spec.IsNullable) {
8919 lexpr = new Nullable.NullableType (lexpr, loc);
8920 lexpr = lexpr.ResolveAsTypeTerminal (ec, false);
8924 single_spec = single_spec.Next;
8925 } else if (single_spec.IsPointer) {
8926 if (!TypeManager.VerifyUnmanaged (ec.Compiler, type, loc))
8930 UnsafeError (ec.Compiler.Report, loc);
8934 type = PointerContainer.MakeType (type);
8935 single_spec = single_spec.Next;
8936 } while (single_spec != null && single_spec.IsPointer);
8939 if (single_spec != null && single_spec.Dimension > 0) {
8940 if (TypeManager.IsSpecialType (type)) {
8941 ec.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
8942 } else if (type.IsStatic) {
8943 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
8944 ec.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8945 type.GetSignatureForError ());
8947 MakeArray (single_spec);
8954 void MakeArray (ComposedTypeSpecifier spec)
8956 if (spec.Next != null)
8957 MakeArray (spec.Next);
8959 type = ArrayContainer.MakeType (type, spec.Dimension);
8962 public override string GetSignatureForError ()
8964 return left.GetSignatureForError () + spec.GetSignatureForError ();
8968 public class FixedBufferPtr : Expression {
8971 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
8976 type = PointerContainer.MakeType (array_type);
8977 eclass = ExprClass.Value;
8980 public override Expression CreateExpressionTree (ResolveContext ec)
8982 Error_PointerInsideExpressionTree (ec);
8986 public override void Emit(EmitContext ec)
8991 protected override Expression DoResolve (ResolveContext ec)
8994 // We are born fully resolved
9002 // This class is used to represent the address of an array, used
9003 // only by the Fixed statement, this generates "&a [0]" construct
9004 // for fixed (char *pa = a)
9006 public class ArrayPtr : FixedBufferPtr {
9007 TypeSpec array_type;
9009 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
9010 base (array, array_type, l)
9012 this.array_type = array_type;
9015 public override void Emit (EmitContext ec)
9020 ec.Emit (OpCodes.Ldelema, array_type);
9025 // Encapsulates a conversion rules required for array indexes
9027 public class ArrayIndexCast : TypeCast
9029 public ArrayIndexCast (Expression expr)
9030 : base (expr, TypeManager.int32_type)
9032 if (expr.Type == TypeManager.int32_type)
9033 throw new ArgumentException ("unnecessary array index conversion");
9036 public override Expression CreateExpressionTree (ResolveContext ec)
9038 using (ec.Set (ResolveContext.Options.CheckedScope)) {
9039 return base.CreateExpressionTree (ec);
9043 public override void Emit (EmitContext ec)
9047 var expr_type = child.Type;
9049 if (expr_type == TypeManager.uint32_type)
9050 ec.Emit (OpCodes.Conv_U);
9051 else if (expr_type == TypeManager.int64_type)
9052 ec.Emit (OpCodes.Conv_Ovf_I);
9053 else if (expr_type == TypeManager.uint64_type)
9054 ec.Emit (OpCodes.Conv_Ovf_I_Un);
9056 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9061 // Implements the `stackalloc' keyword
9063 public class StackAlloc : Expression {
9068 public StackAlloc (Expression type, Expression count, Location l)
9075 public override Expression CreateExpressionTree (ResolveContext ec)
9077 throw new NotSupportedException ("ET");
9080 protected override Expression DoResolve (ResolveContext ec)
9082 count = count.Resolve (ec);
9086 if (count.Type != TypeManager.uint32_type){
9087 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9092 Constant c = count as Constant;
9093 if (c != null && c.IsNegative) {
9094 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9097 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9098 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9101 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9107 if (!TypeManager.VerifyUnmanaged (ec.Compiler, otype, loc))
9110 type = PointerContainer.MakeType (otype);
9111 eclass = ExprClass.Value;
9116 public override void Emit (EmitContext ec)
9118 int size = GetTypeSize (otype);
9123 ec.Emit (OpCodes.Sizeof, otype);
9127 ec.Emit (OpCodes.Mul_Ovf_Un);
9128 ec.Emit (OpCodes.Localloc);
9131 protected override void CloneTo (CloneContext clonectx, Expression t)
9133 StackAlloc target = (StackAlloc) t;
9134 target.count = count.Clone (clonectx);
9135 target.t = t.Clone (clonectx);
9140 // An object initializer expression
9142 public class ElementInitializer : Assign
9144 public readonly string Name;
9146 public ElementInitializer (string name, Expression initializer, Location loc)
9147 : base (null, initializer, loc)
9152 protected override void CloneTo (CloneContext clonectx, Expression t)
9154 ElementInitializer target = (ElementInitializer) t;
9155 target.source = source.Clone (clonectx);
9158 public override Expression CreateExpressionTree (ResolveContext ec)
9160 Arguments args = new Arguments (2);
9161 FieldExpr fe = target as FieldExpr;
9163 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9165 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9167 args.Add (new Argument (source.CreateExpressionTree (ec)));
9168 return CreateExpressionFactoryCall (ec,
9169 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9173 protected override Expression DoResolve (ResolveContext ec)
9176 return EmptyExpressionStatement.Instance;
9178 var t = ec.CurrentInitializerVariable.Type;
9179 if (t == InternalType.Dynamic) {
9180 Arguments args = new Arguments (1);
9181 args.Add (new Argument (ec.CurrentInitializerVariable));
9182 target = new DynamicMemberBinder (Name, args, loc);
9185 var member = MemberLookup (ec, ec.CurrentType, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9186 if (member == null) {
9187 member = Expression.MemberLookup (null, ec.CurrentType, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9189 if (member != null) {
9190 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
9191 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
9196 if (member == null) {
9197 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
9201 if (!(member is PropertyExpr || member is FieldExpr)) {
9202 ec.Report.Error (1913, loc,
9203 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
9204 member.GetSignatureForError ());
9209 var me = member as MemberExpr;
9211 ec.Report.Error (1914, loc,
9212 "Static field or property `{0}' cannot be assigned in an object initializer",
9213 me.GetSignatureForError ());
9217 me.InstanceExpression = ec.CurrentInitializerVariable;
9220 if (source is CollectionOrObjectInitializers) {
9221 Expression previous = ec.CurrentInitializerVariable;
9222 ec.CurrentInitializerVariable = target;
9223 source = source.Resolve (ec);
9224 ec.CurrentInitializerVariable = previous;
9228 eclass = source.eclass;
9233 return base.DoResolve (ec);
9236 public override void EmitStatement (EmitContext ec)
9238 if (source is CollectionOrObjectInitializers)
9241 base.EmitStatement (ec);
9246 // A collection initializer expression
9248 class CollectionElementInitializer : Invocation
9250 public class ElementInitializerArgument : Argument
9252 public ElementInitializerArgument (Expression e)
9258 sealed class AddMemberAccess : MemberAccess
9260 public AddMemberAccess (Expression expr, Location loc)
9261 : base (expr, "Add", loc)
9265 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9267 if (TypeManager.HasElementType (type))
9270 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9274 public CollectionElementInitializer (Expression argument)
9275 : base (null, new Arguments (1))
9277 base.arguments.Add (new ElementInitializerArgument (argument));
9278 this.loc = argument.Location;
9281 public CollectionElementInitializer (List<Expression> arguments, Location loc)
9282 : base (null, new Arguments (arguments.Count))
9284 foreach (Expression e in arguments)
9285 base.arguments.Add (new ElementInitializerArgument (e));
9290 public override Expression CreateExpressionTree (ResolveContext ec)
9292 Arguments args = new Arguments (2);
9293 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9295 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
9296 foreach (Argument a in arguments)
9297 expr_initializers.Add (a.CreateExpressionTree (ec));
9299 args.Add (new Argument (new ArrayCreation (
9300 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
9301 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9304 protected override void CloneTo (CloneContext clonectx, Expression t)
9306 CollectionElementInitializer target = (CollectionElementInitializer) t;
9307 if (arguments != null)
9308 target.arguments = arguments.Clone (clonectx);
9311 protected override Expression DoResolve (ResolveContext ec)
9313 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9315 return base.DoResolve (ec);
9320 // A block of object or collection initializers
9322 public class CollectionOrObjectInitializers : ExpressionStatement
9324 IList<Expression> initializers;
9325 bool is_collection_initialization;
9327 public static readonly CollectionOrObjectInitializers Empty =
9328 new CollectionOrObjectInitializers (Array.AsReadOnly (new Expression [0]), Location.Null);
9330 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
9332 this.initializers = initializers;
9336 public bool IsEmpty {
9338 return initializers.Count == 0;
9342 public bool IsCollectionInitializer {
9344 return is_collection_initialization;
9348 protected override void CloneTo (CloneContext clonectx, Expression target)
9350 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9352 t.initializers = new List<Expression> (initializers.Count);
9353 foreach (var e in initializers)
9354 t.initializers.Add (e.Clone (clonectx));
9357 public override Expression CreateExpressionTree (ResolveContext ec)
9359 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
9360 foreach (Expression e in initializers) {
9361 Expression expr = e.CreateExpressionTree (ec);
9363 expr_initializers.Add (expr);
9366 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
9369 protected override Expression DoResolve (ResolveContext ec)
9371 List<string> element_names = null;
9372 for (int i = 0; i < initializers.Count; ++i) {
9373 Expression initializer = initializers [i];
9374 ElementInitializer element_initializer = initializer as ElementInitializer;
9377 if (element_initializer != null) {
9378 element_names = new List<string> (initializers.Count);
9379 element_names.Add (element_initializer.Name);
9380 } else if (initializer is CompletingExpression){
9381 initializer.Resolve (ec);
9382 throw new InternalErrorException ("This line should never be reached");
9384 var t = ec.CurrentInitializerVariable.Type;
9385 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
9386 if (!t.ImplementsInterface (TypeManager.ienumerable_type, false) && t != InternalType.Dynamic) {
9387 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9388 "object initializer because type `{1}' does not implement `{2}' interface",
9389 ec.CurrentInitializerVariable.GetSignatureForError (),
9390 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9391 TypeManager.CSharpName (TypeManager.ienumerable_type));
9394 is_collection_initialization = true;
9397 if (is_collection_initialization != (element_initializer == null)) {
9398 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9399 is_collection_initialization ? "collection initializer" : "object initializer");
9403 if (!is_collection_initialization) {
9404 if (element_names.Contains (element_initializer.Name)) {
9405 ec.Report.Error (1912, element_initializer.Location,
9406 "An object initializer includes more than one member `{0}' initialization",
9407 element_initializer.Name);
9409 element_names.Add (element_initializer.Name);
9414 Expression e = initializer.Resolve (ec);
9415 if (e == EmptyExpressionStatement.Instance)
9416 initializers.RemoveAt (i--);
9418 initializers [i] = e;
9421 type = ec.CurrentInitializerVariable.Type;
9422 if (is_collection_initialization) {
9423 if (TypeManager.HasElementType (type)) {
9424 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9425 TypeManager.CSharpName (type));
9429 eclass = ExprClass.Variable;
9433 public override void Emit (EmitContext ec)
9438 public override void EmitStatement (EmitContext ec)
9440 foreach (ExpressionStatement e in initializers)
9441 e.EmitStatement (ec);
9446 // New expression with element/object initializers
9448 public class NewInitialize : New
9451 // This class serves as a proxy for variable initializer target instances.
9452 // A real variable is assigned later when we resolve left side of an
9455 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9457 NewInitialize new_instance;
9459 public InitializerTargetExpression (NewInitialize newInstance)
9461 this.type = newInstance.type;
9462 this.loc = newInstance.loc;
9463 this.eclass = newInstance.eclass;
9464 this.new_instance = newInstance;
9467 public override Expression CreateExpressionTree (ResolveContext ec)
9469 // Should not be reached
9470 throw new NotSupportedException ("ET");
9473 protected override Expression DoResolve (ResolveContext ec)
9478 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9483 public override void Emit (EmitContext ec)
9485 Expression e = (Expression) new_instance.instance;
9489 #region IMemoryLocation Members
9491 public void AddressOf (EmitContext ec, AddressOp mode)
9493 new_instance.instance.AddressOf (ec, mode);
9499 CollectionOrObjectInitializers initializers;
9500 IMemoryLocation instance;
9502 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9503 : base (requested_type, arguments, l)
9505 this.initializers = initializers;
9508 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9510 instance = base.EmitAddressOf (ec, Mode);
9512 if (!initializers.IsEmpty)
9513 initializers.Emit (ec);
9518 protected override void CloneTo (CloneContext clonectx, Expression t)
9520 base.CloneTo (clonectx, t);
9522 NewInitialize target = (NewInitialize) t;
9523 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9526 public override Expression CreateExpressionTree (ResolveContext ec)
9528 Arguments args = new Arguments (2);
9529 args.Add (new Argument (base.CreateExpressionTree (ec)));
9530 if (!initializers.IsEmpty)
9531 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9533 return CreateExpressionFactoryCall (ec,
9534 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9538 protected override Expression DoResolve (ResolveContext ec)
9540 Expression e = base.DoResolve (ec);
9544 Expression previous = ec.CurrentInitializerVariable;
9545 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9546 initializers.Resolve (ec);
9547 ec.CurrentInitializerVariable = previous;
9551 public override bool Emit (EmitContext ec, IMemoryLocation target)
9553 bool left_on_stack = base.Emit (ec, target);
9555 if (initializers.IsEmpty)
9556 return left_on_stack;
9558 LocalTemporary temp = target as LocalTemporary;
9560 if (!left_on_stack) {
9561 VariableReference vr = target as VariableReference;
9563 // FIXME: This still does not work correctly for pre-set variables
9564 if (vr != null && vr.IsRef)
9565 target.AddressOf (ec, AddressOp.Load);
9567 ((Expression) target).Emit (ec);
9568 left_on_stack = true;
9571 temp = new LocalTemporary (type);
9578 initializers.Emit (ec);
9580 if (left_on_stack) {
9585 return left_on_stack;
9589 public class NewAnonymousType : New
9591 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
9593 List<AnonymousTypeParameter> parameters;
9594 readonly TypeContainer parent;
9595 AnonymousTypeClass anonymous_type;
9597 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
9598 : base (null, null, loc)
9600 this.parameters = parameters;
9601 this.parent = parent;
9604 protected override void CloneTo (CloneContext clonectx, Expression target)
9606 if (parameters == null)
9609 NewAnonymousType t = (NewAnonymousType) target;
9610 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
9611 foreach (AnonymousTypeParameter atp in parameters)
9612 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
9615 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
9617 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
9621 type = AnonymousTypeClass.Create (ec.Compiler, parent, parameters, loc);
9627 type.ResolveTypeParameters ();
9630 if (ec.Report.Errors == 0)
9633 parent.Module.AddAnonymousType (type);
9637 public override Expression CreateExpressionTree (ResolveContext ec)
9639 if (parameters == null)
9640 return base.CreateExpressionTree (ec);
9642 var init = new ArrayInitializer (parameters.Count, loc);
9643 foreach (Property p in anonymous_type.Properties)
9644 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
9646 var ctor_args = new ArrayInitializer (arguments.Count, loc);
9647 foreach (Argument a in arguments)
9648 ctor_args.Add (a.CreateExpressionTree (ec));
9650 Arguments args = new Arguments (3);
9651 args.Add (new Argument (new TypeOfMethod (method, loc)));
9652 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
9653 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
9655 return CreateExpressionFactoryCall (ec, "New", args);
9658 protected override Expression DoResolve (ResolveContext ec)
9660 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
9661 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9665 if (parameters == null) {
9666 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
9667 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
9668 return base.DoResolve (ec);
9672 arguments = new Arguments (parameters.Count);
9673 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9674 for (int i = 0; i < parameters.Count; ++i) {
9675 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9681 arguments.Add (new Argument (e));
9682 t_args [i] = new TypeExpression (e.Type, e.Location);
9688 anonymous_type = CreateAnonymousType (ec, parameters);
9689 if (anonymous_type == null)
9692 RequestedType = new GenericTypeExpr (anonymous_type.Definition, new TypeArguments (t_args), loc);
9693 return base.DoResolve (ec);
9697 public class AnonymousTypeParameter : ShimExpression
9699 public readonly string Name;
9701 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9702 : base (initializer)
9708 public AnonymousTypeParameter (Parameter parameter)
9709 : base (new SimpleName (parameter.Name, parameter.Location))
9711 this.Name = parameter.Name;
9712 this.loc = parameter.Location;
9715 public override bool Equals (object o)
9717 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9718 return other != null && Name == other.Name;
9721 public override int GetHashCode ()
9723 return Name.GetHashCode ();
9726 protected override Expression DoResolve (ResolveContext ec)
9728 Expression e = expr.Resolve (ec);
9732 if (e.eclass == ExprClass.MethodGroup) {
9733 Error_InvalidInitializer (ec, e.ExprClassName);
9738 if (type == TypeManager.void_type || type == InternalType.Null ||
9739 type == InternalType.AnonymousMethod || type.IsPointer) {
9740 Error_InvalidInitializer (ec, e.GetSignatureForError ());
9747 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
9749 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",