2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
9 // (C) 2003, 2004 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// This is just a helper class, it is generated by Unary, UnaryMutator
22 /// when an overloaded method has been found. It just emits the code for a
25 public class StaticCallExpr : ExpressionStatement {
29 public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
35 eclass = ExprClass.Value;
39 public override Expression DoResolve (EmitContext ec)
42 // We are born fully resolved
47 public override void Emit (EmitContext ec)
50 Invocation.EmitArguments (ec, mi, args, false, null);
52 ec.ig.Emit (OpCodes.Call, mi);
56 static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
57 Expression e, Location loc)
61 args = new ArrayList (1);
62 Argument a = new Argument (e, Argument.AType.Expression);
64 // We need to resolve the arguments before sending them in !
65 if (!a.Resolve (ec, loc))
69 mg = mg.OverloadResolve (ec, args, false, loc);
74 return new StaticCallExpr ((MethodInfo) mg, args, loc);
77 public override void EmitStatement (EmitContext ec)
80 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
81 ec.ig.Emit (OpCodes.Pop);
84 public MethodInfo Method {
89 public class ParenthesizedExpression : Expression
91 public Expression Expr;
93 public ParenthesizedExpression (Expression expr)
98 public override Expression DoResolve (EmitContext ec)
100 Expr = Expr.Resolve (ec);
104 public override void Emit (EmitContext ec)
106 throw new Exception ("Should not happen");
109 public override Location Location
112 return Expr.Location;
116 protected override void CloneTo (CloneContext clonectx, Expression t)
118 ParenthesizedExpression target = (ParenthesizedExpression) t;
120 target.Expr = Expr.Clone (clonectx);
125 /// Unary expressions.
129 /// Unary implements unary expressions. It derives from
130 /// ExpressionStatement becuase the pre/post increment/decrement
131 /// operators can be used in a statement context.
133 public class Unary : Expression {
134 public enum Operator : byte {
135 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
136 Indirection, AddressOf, TOP
139 public Operator Oper;
140 public Expression Expr;
142 public Unary (Operator op, Expression expr, Location loc)
150 /// Returns a stringified representation of the Operator
152 static public string OperName (Operator oper)
155 case Operator.UnaryPlus:
157 case Operator.UnaryNegation:
159 case Operator.LogicalNot:
161 case Operator.OnesComplement:
163 case Operator.AddressOf:
165 case Operator.Indirection:
169 return oper.ToString ();
172 public static readonly string [] oper_names;
176 oper_names = new string [(int)Operator.TOP];
178 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
179 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
180 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
181 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
182 oper_names [(int) Operator.Indirection] = "op_Indirection";
183 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
186 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
188 Error_OperatorCannotBeApplied (loc, oper, TypeManager.CSharpName (t));
191 public static void Error_OperatorCannotBeApplied (Location loc, string oper, string type)
193 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
197 void Error23 (Type t)
199 Error_OperatorCannotBeApplied (loc, OperName (Oper), t);
203 // This routine will attempt to simplify the unary expression when the
204 // argument is a constant.
206 Constant TryReduceConstant (EmitContext ec, Constant e)
208 Type expr_type = e.Type;
211 case Operator.UnaryPlus:
212 // Unary numeric promotions
213 if (expr_type == TypeManager.byte_type)
214 return new IntConstant (((ByteConstant)e).Value, e.Location);
215 if (expr_type == TypeManager.sbyte_type)
216 return new IntConstant (((SByteConstant)e).Value, e.Location);
217 if (expr_type == TypeManager.short_type)
218 return new IntConstant (((ShortConstant)e).Value, e.Location);
219 if (expr_type == TypeManager.ushort_type)
220 return new IntConstant (((UShortConstant)e).Value, e.Location);
221 if (expr_type == TypeManager.char_type)
222 return new IntConstant (((CharConstant)e).Value, e.Location);
224 // Predefined operators
225 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
226 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
227 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
228 expr_type == TypeManager.decimal_type)
235 case Operator.UnaryNegation:
236 // Unary numeric promotions
237 if (expr_type == TypeManager.byte_type)
238 return new IntConstant (-((ByteConstant)e).Value, e.Location);
239 if (expr_type == TypeManager.sbyte_type)
240 return new IntConstant (-((SByteConstant)e).Value, e.Location);
241 if (expr_type == TypeManager.short_type)
242 return new IntConstant (-((ShortConstant)e).Value, e.Location);
243 if (expr_type == TypeManager.ushort_type)
244 return new IntConstant (-((UShortConstant)e).Value, e.Location);
245 if (expr_type == TypeManager.char_type)
246 return new IntConstant (-((CharConstant)e).Value, e.Location);
248 // Predefined operators
249 if (expr_type == TypeManager.int32_type) {
250 int value = ((IntConstant)e).Value;
251 if (value == int.MinValue) {
252 if (ec.ConstantCheckState) {
253 ConstantFold.Error_CompileTimeOverflow (loc);
258 return new IntConstant (-value, e.Location);
260 if (expr_type == TypeManager.int64_type) {
261 long value = ((LongConstant)e).Value;
262 if (value == long.MinValue) {
263 if (ec.ConstantCheckState) {
264 ConstantFold.Error_CompileTimeOverflow (loc);
269 return new LongConstant (-value, e.Location);
272 if (expr_type == TypeManager.uint32_type) {
273 UIntLiteral uil = e as UIntLiteral;
275 if (uil.Value == 2147483648)
276 return new IntLiteral (int.MinValue, e.Location);
277 return new LongLiteral (-uil.Value, e.Location);
279 return new LongConstant (-((UIntConstant)e).Value, e.Location);
282 if (expr_type == TypeManager.uint64_type) {
283 ULongLiteral ull = e as ULongLiteral;
284 if (ull != null && ull.Value == 9223372036854775808)
285 return new LongLiteral (long.MinValue, e.Location);
289 if (expr_type == TypeManager.float_type) {
290 FloatLiteral fl = e as FloatLiteral;
291 // For better error reporting
293 fl.Value = -fl.Value;
296 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
298 if (expr_type == TypeManager.double_type) {
299 DoubleLiteral dl = e as DoubleLiteral;
300 // For better error reporting
302 dl.Value = -dl.Value;
306 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
308 if (expr_type == TypeManager.decimal_type)
309 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
313 case Operator.LogicalNot:
314 if (expr_type != TypeManager.bool_type)
317 BoolConstant b = (BoolConstant) e;
318 return new BoolConstant (!(b.Value), b.Location);
320 case Operator.OnesComplement:
321 // Unary numeric promotions
322 if (expr_type == TypeManager.byte_type)
323 return new IntConstant (~((ByteConstant)e).Value, e.Location);
324 if (expr_type == TypeManager.sbyte_type)
325 return new IntConstant (~((SByteConstant)e).Value, e.Location);
326 if (expr_type == TypeManager.short_type)
327 return new IntConstant (~((ShortConstant)e).Value, e.Location);
328 if (expr_type == TypeManager.ushort_type)
329 return new IntConstant (~((UShortConstant)e).Value, e.Location);
330 if (expr_type == TypeManager.char_type)
331 return new IntConstant (~((CharConstant)e).Value, e.Location);
333 // Predefined operators
334 if (expr_type == TypeManager.int32_type)
335 return new IntConstant (~((IntConstant)e).Value, e.Location);
336 if (expr_type == TypeManager.uint32_type)
337 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
338 if (expr_type == TypeManager.int64_type)
339 return new LongConstant (~((LongConstant)e).Value, e.Location);
340 if (expr_type == TypeManager.uint64_type){
341 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
343 if (e is EnumConstant) {
344 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
346 e = new EnumConstant (e, expr_type);
351 case Operator.AddressOf:
354 case Operator.Indirection:
357 throw new Exception ("Can not constant fold: " + Oper.ToString());
360 Expression ResolveOperator (EmitContext ec)
363 // Step 1: Default operations on CLI native types.
366 // Attempt to use a constant folding operation.
367 Constant cexpr = Expr as Constant;
369 cexpr = TryReduceConstant (ec, cexpr);
376 // Step 2: Perform Operator Overload location
378 Type expr_type = Expr.Type;
379 string op_name = oper_names [(int) Oper];
381 Expression mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
383 Expression e = StaticCallExpr.MakeSimpleCall (
384 ec, (MethodGroupExpr) mg, Expr, loc);
395 case Operator.LogicalNot:
396 if (expr_type != TypeManager.bool_type) {
397 Expr = ResolveBoolean (ec, Expr, loc);
404 type = TypeManager.bool_type;
407 case Operator.OnesComplement:
408 // Unary numeric promotions
409 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
410 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
411 expr_type == TypeManager.char_type)
413 type = TypeManager.int32_type;
414 return new EmptyCast (this, type);
417 // Predefined operators
418 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
419 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
420 TypeManager.IsEnumType (expr_type))
426 type = TypeManager.int32_type;
427 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
434 case Operator.AddressOf:
440 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
444 IVariable variable = Expr as IVariable;
445 bool is_fixed = variable != null && variable.VerifyFixed ();
447 if (!ec.InFixedInitializer && !is_fixed) {
448 Error (212, "You can only take the address of unfixed expression inside " +
449 "of a fixed statement initializer");
453 if (ec.InFixedInitializer && is_fixed) {
454 Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
458 LocalVariableReference lr = Expr as LocalVariableReference;
460 if (lr.local_info.IsCaptured){
461 AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
464 lr.local_info.AddressTaken = true;
465 lr.local_info.Used = true;
468 ParameterReference pr = Expr as ParameterReference;
469 if ((pr != null) && pr.Parameter.IsCaptured) {
470 AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
474 // According to the specs, a variable is considered definitely assigned if you take
476 if ((variable != null) && (variable.VariableInfo != null)){
477 variable.VariableInfo.SetAssigned (ec);
480 type = TypeManager.GetPointerType (Expr.Type);
483 case Operator.Indirection:
489 if (!expr_type.IsPointer){
490 Error (193, "The * or -> operator must be applied to a pointer");
495 // We create an Indirection expression, because
496 // it can implement the IMemoryLocation.
498 return new Indirection (Expr, loc);
500 case Operator.UnaryPlus:
501 // Unary numeric promotions
502 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
503 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
504 expr_type == TypeManager.char_type)
506 return new EmptyCast (Expr, TypeManager.int32_type);
509 // Predefined operators
510 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
511 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
512 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
513 expr_type == TypeManager.decimal_type)
518 Expr = Convert.ImplicitUserConversion(ec, Expr, TypeManager.int32_type, loc);
520 // Because we can completely ignore unary +
527 case Operator.UnaryNegation:
529 // transform - - expr into expr
531 Unary u = Expr as Unary;
532 if (u != null && u.Oper == Operator.UnaryNegation) {
536 // Unary numeric promotions
537 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
538 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
539 expr_type == TypeManager.char_type)
541 type = TypeManager.int32_type;
542 return new EmptyCast (this, type);
546 // Predefined operators
548 if (expr_type == TypeManager.uint32_type) {
549 type = TypeManager.int64_type;
550 Expr = Convert.ImplicitNumericConversion (Expr, type);
554 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.int64_type ||
555 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
556 expr_type == TypeManager.decimal_type)
565 type = TypeManager.int32_type;
566 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
574 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
575 TypeManager.CSharpName (expr_type) + "'");
579 public override Expression DoResolve (EmitContext ec)
581 if (Oper == Operator.AddressOf) {
582 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
584 if (Expr == null || Expr.eclass != ExprClass.Variable){
585 Error (211, "Cannot take the address of the given expression");
590 Expr = Expr.Resolve (ec);
596 if (TypeManager.IsNullableValueType (Expr.Type))
597 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
600 eclass = ExprClass.Value;
601 return ResolveOperator (ec);
604 public override Expression DoResolveLValue (EmitContext ec, Expression right)
606 if (Oper == Operator.Indirection)
607 return DoResolve (ec);
612 public override void Emit (EmitContext ec)
614 ILGenerator ig = ec.ig;
617 case Operator.UnaryPlus:
618 throw new Exception ("This should be caught by Resolve");
620 case Operator.UnaryNegation:
621 if (ec.CheckState && type != TypeManager.float_type && type != TypeManager.double_type) {
622 ig.Emit (OpCodes.Ldc_I4_0);
623 if (type == TypeManager.int64_type)
624 ig.Emit (OpCodes.Conv_U8);
626 ig.Emit (OpCodes.Sub_Ovf);
629 ig.Emit (OpCodes.Neg);
634 case Operator.LogicalNot:
636 ig.Emit (OpCodes.Ldc_I4_0);
637 ig.Emit (OpCodes.Ceq);
640 case Operator.OnesComplement:
642 ig.Emit (OpCodes.Not);
645 case Operator.AddressOf:
646 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
650 throw new Exception ("This should not happen: Operator = "
655 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
657 if (Oper == Operator.LogicalNot)
658 Expr.EmitBranchable (ec, target, !onTrue);
660 base.EmitBranchable (ec, target, onTrue);
663 public override string ToString ()
665 return "Unary (" + Oper + ", " + Expr + ")";
668 protected override void CloneTo (CloneContext clonectx, Expression t)
670 Unary target = (Unary) t;
672 target.Expr = Expr.Clone (clonectx);
677 // Unary operators are turned into Indirection expressions
678 // after semantic analysis (this is so we can take the address
679 // of an indirection).
681 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
683 LocalTemporary temporary;
686 public Indirection (Expression expr, Location l)
689 type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
690 eclass = ExprClass.Variable;
694 public override void Emit (EmitContext ec)
699 LoadFromPtr (ec.ig, Type);
702 public void Emit (EmitContext ec, bool leave_copy)
706 ec.ig.Emit (OpCodes.Dup);
707 temporary = new LocalTemporary (expr.Type);
708 temporary.Store (ec);
712 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
714 prepared = prepare_for_load;
718 if (prepare_for_load)
719 ec.ig.Emit (OpCodes.Dup);
723 ec.ig.Emit (OpCodes.Dup);
724 temporary = new LocalTemporary (expr.Type);
725 temporary.Store (ec);
728 StoreFromPtr (ec.ig, type);
730 if (temporary != null) {
732 temporary.Release (ec);
736 public void AddressOf (EmitContext ec, AddressOp Mode)
741 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
743 return DoResolve (ec);
746 public override Expression DoResolve (EmitContext ec)
749 // Born fully resolved
754 public override string ToString ()
756 return "*(" + expr + ")";
759 #region IVariable Members
761 public VariableInfo VariableInfo {
765 public bool VerifyFixed ()
767 // A pointer-indirection is always fixed.
775 /// Unary Mutator expressions (pre and post ++ and --)
779 /// UnaryMutator implements ++ and -- expressions. It derives from
780 /// ExpressionStatement becuase the pre/post increment/decrement
781 /// operators can be used in a statement context.
783 /// FIXME: Idea, we could split this up in two classes, one simpler
784 /// for the common case, and one with the extra fields for more complex
785 /// classes (indexers require temporary access; overloaded require method)
788 public class UnaryMutator : ExpressionStatement {
790 public enum Mode : byte {
797 PreDecrement = IsDecrement,
798 PostIncrement = IsPost,
799 PostDecrement = IsPost | IsDecrement
803 bool is_expr = false;
804 bool recurse = false;
809 // This is expensive for the simplest case.
811 StaticCallExpr method;
813 public UnaryMutator (Mode m, Expression e, Location l)
820 static string OperName (Mode mode)
822 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
827 /// Returns whether an object of type `t' can be incremented
828 /// or decremented with add/sub (ie, basically whether we can
829 /// use pre-post incr-decr operations on it, but it is not a
830 /// System.Decimal, which we require operator overloading to catch)
832 static bool IsIncrementableNumber (Type t)
834 return (t == TypeManager.sbyte_type) ||
835 (t == TypeManager.byte_type) ||
836 (t == TypeManager.short_type) ||
837 (t == TypeManager.ushort_type) ||
838 (t == TypeManager.int32_type) ||
839 (t == TypeManager.uint32_type) ||
840 (t == TypeManager.int64_type) ||
841 (t == TypeManager.uint64_type) ||
842 (t == TypeManager.char_type) ||
843 (t.IsSubclassOf (TypeManager.enum_type)) ||
844 (t == TypeManager.float_type) ||
845 (t == TypeManager.double_type) ||
846 (t.IsPointer && t != TypeManager.void_ptr_type);
849 Expression ResolveOperator (EmitContext ec)
851 Type expr_type = expr.Type;
854 // Step 1: Perform Operator Overload location
859 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
860 op_name = "op_Increment";
862 op_name = "op_Decrement";
864 mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
867 method = StaticCallExpr.MakeSimpleCall (
868 ec, (MethodGroupExpr) mg, expr, loc);
871 } else if (!IsIncrementableNumber (expr_type)) {
872 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
873 TypeManager.CSharpName (expr_type) + "'");
878 // The operand of the prefix/postfix increment decrement operators
879 // should be an expression that is classified as a variable,
880 // a property access or an indexer access
883 if (expr.eclass == ExprClass.Variable){
884 LocalVariableReference var = expr as LocalVariableReference;
885 if ((var != null) && var.IsReadOnly) {
886 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
889 } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
890 expr = expr.ResolveLValue (ec, this, Location);
894 if (expr.eclass == ExprClass.Value) {
895 Error_ValueAssignment (loc);
897 expr.Error_UnexpectedKind (ec.DeclContainer, "variable, indexer or property access", loc);
905 public override Expression DoResolve (EmitContext ec)
907 expr = expr.Resolve (ec);
912 eclass = ExprClass.Value;
915 if (TypeManager.IsNullableValueType (expr.Type))
916 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
919 return ResolveOperator (ec);
922 static int PtrTypeSize (Type t)
924 return GetTypeSize (TypeManager.GetElementType (t));
928 // Loads the proper "1" into the stack based on the type, then it emits the
929 // opcode for the operation requested
931 void LoadOneAndEmitOp (EmitContext ec, Type t)
934 // Measure if getting the typecode and using that is more/less efficient
935 // that comparing types. t.GetTypeCode() is an internal call.
937 ILGenerator ig = ec.ig;
939 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
940 LongConstant.EmitLong (ig, 1);
941 else if (t == TypeManager.double_type)
942 ig.Emit (OpCodes.Ldc_R8, 1.0);
943 else if (t == TypeManager.float_type)
944 ig.Emit (OpCodes.Ldc_R4, 1.0F);
945 else if (t.IsPointer){
946 int n = PtrTypeSize (t);
949 ig.Emit (OpCodes.Sizeof, t);
951 IntConstant.EmitInt (ig, n);
953 ig.Emit (OpCodes.Ldc_I4_1);
956 // Now emit the operation
959 if (t == TypeManager.int32_type ||
960 t == TypeManager.int64_type){
961 if ((mode & Mode.IsDecrement) != 0)
962 ig.Emit (OpCodes.Sub_Ovf);
964 ig.Emit (OpCodes.Add_Ovf);
965 } else if (t == TypeManager.uint32_type ||
966 t == TypeManager.uint64_type){
967 if ((mode & Mode.IsDecrement) != 0)
968 ig.Emit (OpCodes.Sub_Ovf_Un);
970 ig.Emit (OpCodes.Add_Ovf_Un);
972 if ((mode & Mode.IsDecrement) != 0)
973 ig.Emit (OpCodes.Sub_Ovf);
975 ig.Emit (OpCodes.Add_Ovf);
978 if ((mode & Mode.IsDecrement) != 0)
979 ig.Emit (OpCodes.Sub);
981 ig.Emit (OpCodes.Add);
984 if (t == TypeManager.sbyte_type){
986 ig.Emit (OpCodes.Conv_Ovf_I1);
988 ig.Emit (OpCodes.Conv_I1);
989 } else if (t == TypeManager.byte_type){
991 ig.Emit (OpCodes.Conv_Ovf_U1);
993 ig.Emit (OpCodes.Conv_U1);
994 } else if (t == TypeManager.short_type){
996 ig.Emit (OpCodes.Conv_Ovf_I2);
998 ig.Emit (OpCodes.Conv_I2);
999 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1001 ig.Emit (OpCodes.Conv_Ovf_U2);
1003 ig.Emit (OpCodes.Conv_U2);
1008 void EmitCode (EmitContext ec, bool is_expr)
1011 this.is_expr = is_expr;
1012 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1015 public override void Emit (EmitContext ec)
1018 // We use recurse to allow ourselfs to be the source
1019 // of an assignment. This little hack prevents us from
1020 // having to allocate another expression
1023 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1025 LoadOneAndEmitOp (ec, expr.Type);
1027 ec.ig.Emit (OpCodes.Call, method.Method);
1032 EmitCode (ec, true);
1035 public override void EmitStatement (EmitContext ec)
1037 EmitCode (ec, false);
1040 protected override void CloneTo (CloneContext clonectx, Expression t)
1042 UnaryMutator target = (UnaryMutator) t;
1044 target.expr = expr.Clone (clonectx);
1049 /// Base class for the `Is' and `As' classes.
1053 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1056 public abstract class Probe : Expression {
1057 public Expression ProbeType;
1058 protected Expression expr;
1059 protected TypeExpr probe_type_expr;
1061 public Probe (Expression expr, Expression probe_type, Location l)
1063 ProbeType = probe_type;
1068 public Expression Expr {
1074 public override Expression DoResolve (EmitContext ec)
1076 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1077 if (probe_type_expr == null)
1080 expr = expr.Resolve (ec);
1084 if (expr.Type.IsPointer) {
1085 Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types");
1091 protected override void CloneTo (CloneContext clonectx, Expression t)
1093 Probe target = (Probe) t;
1095 target.expr = expr.Clone (clonectx);
1096 target.ProbeType = ProbeType.Clone (clonectx);
1102 /// Implementation of the `is' operator.
1104 public class Is : Probe {
1105 public Is (Expression expr, Expression probe_type, Location l)
1106 : base (expr, probe_type, l)
1111 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1116 public override void Emit (EmitContext ec)
1118 ILGenerator ig = ec.ig;
1123 case Action.AlwaysFalse:
1124 ig.Emit (OpCodes.Pop);
1125 IntConstant.EmitInt (ig, 0);
1127 case Action.AlwaysTrue:
1128 ig.Emit (OpCodes.Pop);
1129 IntConstant.EmitInt (ig, 1);
1131 case Action.LeaveOnStack:
1132 // the `e != null' rule.
1133 ig.Emit (OpCodes.Ldnull);
1134 ig.Emit (OpCodes.Ceq);
1135 ig.Emit (OpCodes.Ldc_I4_0);
1136 ig.Emit (OpCodes.Ceq);
1139 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1140 ig.Emit (OpCodes.Ldnull);
1141 ig.Emit (OpCodes.Cgt_Un);
1144 throw new Exception ("never reached");
1147 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
1149 ILGenerator ig = ec.ig;
1152 case Action.AlwaysFalse:
1154 ig.Emit (OpCodes.Br, target);
1157 case Action.AlwaysTrue:
1159 ig.Emit (OpCodes.Br, target);
1162 case Action.LeaveOnStack:
1163 // the `e != null' rule.
1165 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1169 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1170 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1173 throw new Exception ("never reached");
1176 public override Expression DoResolve (EmitContext ec)
1178 Expression e = base.DoResolve (ec);
1180 if ((e == null) || (expr == null))
1183 Type etype = expr.Type;
1184 type = TypeManager.bool_type;
1185 eclass = ExprClass.Value;
1188 // First case, if at compile time, there is an implicit conversion
1189 // then e != null (objects) or true (value types)
1191 Type probe_type = probe_type_expr.Type;
1192 e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
1195 if (etype.IsValueType)
1196 action = Action.AlwaysTrue;
1198 action = Action.LeaveOnStack;
1200 Constant c = e as Constant;
1201 if (c != null && c.GetValue () == null) {
1202 action = Action.AlwaysFalse;
1203 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1204 TypeManager.CSharpName (probe_type));
1205 } else if (etype.IsValueType) {
1206 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1207 TypeManager.CSharpName (probe_type));
1212 if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1213 if (TypeManager.IsGenericParameter (etype))
1214 expr = new BoxedCast (expr, etype);
1217 // Second case: explicit reference convresion
1219 if (expr is NullLiteral)
1220 action = Action.AlwaysFalse;
1222 action = Action.Probe;
1223 } else if (TypeManager.ContainsGenericParameters (etype) ||
1224 TypeManager.ContainsGenericParameters (probe_type)) {
1225 expr = new BoxedCast (expr, etype);
1226 action = Action.Probe;
1228 action = Action.AlwaysFalse;
1229 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1230 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type", TypeManager.CSharpName (probe_type));
1238 /// Implementation of the `as' operator.
1240 public class As : Probe {
1241 public As (Expression expr, Expression probe_type, Location l)
1242 : base (expr, probe_type, l)
1246 bool do_isinst = false;
1247 Expression resolved_type;
1249 public override void Emit (EmitContext ec)
1251 ILGenerator ig = ec.ig;
1256 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1259 if (TypeManager.IsNullableType (type))
1260 ig.Emit (OpCodes.Unbox_Any, type);
1264 static void Error_CannotConvertType (Type source, Type target, Location loc)
1266 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1267 TypeManager.CSharpName (source),
1268 TypeManager.CSharpName (target));
1271 public override Expression DoResolve (EmitContext ec)
1273 if (resolved_type == null) {
1274 resolved_type = base.DoResolve (ec);
1276 if (resolved_type == null)
1280 type = probe_type_expr.Type;
1281 eclass = ExprClass.Value;
1282 Type etype = expr.Type;
1284 if (type.IsValueType && !TypeManager.IsNullableType (type)) {
1285 Report.Error (77, loc, "The as operator must be used with a reference type (`" +
1286 TypeManager.CSharpName (type) + "' is a value type)");
1293 // If the type is a type parameter, ensure
1294 // that it is constrained by a class
1296 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1298 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1301 if (constraints == null)
1304 if (!constraints.HasClassConstraint)
1305 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1309 Report.Error (413, loc,
1310 "The as operator requires that the `{0}' type parameter be constrained by a class",
1311 probe_type_expr.GetSignatureForError ());
1317 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1324 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1325 if (TypeManager.IsGenericParameter (etype))
1326 expr = new BoxedCast (expr, etype);
1332 if (TypeManager.ContainsGenericParameters (etype) ||
1333 TypeManager.ContainsGenericParameters (type)) {
1334 expr = new BoxedCast (expr, etype);
1339 Error_CannotConvertType (etype, type, loc);
1343 public override bool GetAttributableValue (Type valueType, out object value)
1345 return expr.GetAttributableValue (valueType, out value);
1350 /// This represents a typecast in the source language.
1352 /// FIXME: Cast expressions have an unusual set of parsing
1353 /// rules, we need to figure those out.
1355 public class Cast : Expression {
1356 Expression target_type;
1359 public Cast (Expression cast_type, Expression expr)
1360 : this (cast_type, expr, cast_type.Location)
1364 public Cast (Expression cast_type, Expression expr, Location loc)
1366 this.target_type = cast_type;
1370 if (target_type == TypeManager.system_void_expr)
1371 Error_VoidInvalidInTheContext (loc);
1374 public Expression TargetType {
1375 get { return target_type; }
1378 public Expression Expr {
1379 get { return expr; }
1380 set { expr = value; }
1383 public override Expression DoResolve (EmitContext ec)
1385 expr = expr.Resolve (ec);
1389 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1395 if (type.IsAbstract && type.IsSealed) {
1396 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1400 eclass = ExprClass.Value;
1402 Constant c = expr as Constant;
1404 c = c.TryReduce (ec, type, loc);
1409 if (type.IsPointer && !ec.InUnsafe) {
1413 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1417 public override void Emit (EmitContext ec)
1419 throw new Exception ("Should not happen");
1422 protected override void CloneTo (CloneContext clonectx, Expression t)
1424 Cast target = (Cast) t;
1426 target.target_type = target_type.Clone (clonectx);
1427 target.expr = expr.Clone (clonectx);
1432 /// Binary operators
1434 public class Binary : Expression {
1435 public enum Operator : byte {
1436 Multiply, Division, Modulus,
1437 Addition, Subtraction,
1438 LeftShift, RightShift,
1439 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1440 Equality, Inequality,
1450 Expression left, right;
1452 // This must be kept in sync with Operator!!!
1453 public static readonly string [] oper_names;
1457 oper_names = new string [(int) Operator.TOP];
1459 oper_names [(int) Operator.Multiply] = "op_Multiply";
1460 oper_names [(int) Operator.Division] = "op_Division";
1461 oper_names [(int) Operator.Modulus] = "op_Modulus";
1462 oper_names [(int) Operator.Addition] = "op_Addition";
1463 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1464 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1465 oper_names [(int) Operator.RightShift] = "op_RightShift";
1466 oper_names [(int) Operator.LessThan] = "op_LessThan";
1467 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1468 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1469 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1470 oper_names [(int) Operator.Equality] = "op_Equality";
1471 oper_names [(int) Operator.Inequality] = "op_Inequality";
1472 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1473 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1474 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1475 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1476 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1479 public Binary (Operator oper, Expression left, Expression right)
1484 this.loc = left.Location;
1487 public Operator Oper {
1496 public Expression Left {
1505 public Expression Right {
1516 /// Returns a stringified representation of the Operator
1518 public static string OperName (Operator oper)
1521 case Operator.Multiply:
1523 case Operator.Division:
1525 case Operator.Modulus:
1527 case Operator.Addition:
1529 case Operator.Subtraction:
1531 case Operator.LeftShift:
1533 case Operator.RightShift:
1535 case Operator.LessThan:
1537 case Operator.GreaterThan:
1539 case Operator.LessThanOrEqual:
1541 case Operator.GreaterThanOrEqual:
1543 case Operator.Equality:
1545 case Operator.Inequality:
1547 case Operator.BitwiseAnd:
1549 case Operator.BitwiseOr:
1551 case Operator.ExclusiveOr:
1553 case Operator.LogicalOr:
1555 case Operator.LogicalAnd:
1559 return oper.ToString ();
1562 public override string ToString ()
1564 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1565 right.ToString () + ")";
1568 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1570 if (expr.Type == target_type)
1573 return Convert.ImplicitConversion (ec, expr, target_type, loc);
1576 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1579 34, loc, "Operator `" + OperName (oper)
1580 + "' is ambiguous on operands of type `"
1581 + TypeManager.CSharpName (l) + "' "
1582 + "and `" + TypeManager.CSharpName (r)
1586 bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
1588 return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
1591 bool VerifyApplicable_Predefined (EmitContext ec, Type t)
1593 if (!IsConvertible (ec, left, right, t))
1595 left = ForceConversion (ec, left, t);
1596 right = ForceConversion (ec, right, t);
1601 bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
1603 bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
1604 bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
1606 if (oper == Operator.Equality || oper == Operator.Inequality)
1608 if (oper == Operator.Addition)
1613 bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
1615 if (!IsApplicable_String (ec, left, right, oper))
1617 Type t = TypeManager.string_type;
1618 if (Convert.ImplicitConversionExists (ec, left, t))
1619 left = ForceConversion (ec, left, t);
1620 if (Convert.ImplicitConversionExists (ec, right, t))
1621 right = ForceConversion (ec, right, t);
1626 bool OverloadResolve_PredefinedIntegral (EmitContext ec)
1628 return VerifyApplicable_Predefined (ec, TypeManager.int32_type) ||
1629 VerifyApplicable_Predefined (ec, TypeManager.uint32_type) ||
1630 VerifyApplicable_Predefined (ec, TypeManager.int64_type) ||
1631 VerifyApplicable_Predefined (ec, TypeManager.uint64_type) ||
1635 bool OverloadResolve_PredefinedFloating (EmitContext ec)
1637 return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
1638 VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
1642 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1644 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1647 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1649 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1653 void Error_OperatorCannotBeApplied ()
1655 Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
1656 TypeManager.CSharpName(right.Type));
1659 static bool is_unsigned (Type t)
1661 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1662 t == TypeManager.short_type || t == TypeManager.byte_type);
1665 Expression Make32or64 (EmitContext ec, Expression e)
1669 if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1670 t == TypeManager.int64_type || t == TypeManager.uint64_type)
1672 Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
1675 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
1678 ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
1681 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
1687 Expression CheckShiftArguments (EmitContext ec)
1689 Expression new_left = Make32or64 (ec, left);
1690 Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
1691 if (new_left == null || new_right == null) {
1692 Error_OperatorCannotBeApplied ();
1695 type = new_left.Type;
1696 int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
1698 right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
1703 // This is used to check if a test 'x == null' can be optimized to a reference equals,
1704 // i.e., not invoke op_Equality.
1706 static bool EqualsNullIsReferenceEquals (Type t)
1708 return t == TypeManager.object_type || t == TypeManager.string_type ||
1709 t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
1712 static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
1714 Report.Warning ((side == "left" ? 252 : 253), 2, loc,
1715 "Possible unintended reference comparison; to get a value comparison, " +
1716 "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
1719 Expression ResolveOperator (EmitContext ec)
1722 Type r = right.Type;
1724 if (oper == Operator.Equality || oper == Operator.Inequality){
1725 if (TypeManager.IsGenericParameter (l) && (right is NullLiteral)) {
1726 if (l.BaseType == TypeManager.value_type) {
1727 Error_OperatorCannotBeApplied ();
1731 left = new BoxedCast (left, TypeManager.object_type);
1732 Type = TypeManager.bool_type;
1736 if (TypeManager.IsGenericParameter (r) && (left is NullLiteral)) {
1737 if (r.BaseType == TypeManager.value_type) {
1738 Error_OperatorCannotBeApplied ();
1742 right = new BoxedCast (right, TypeManager.object_type);
1743 Type = TypeManager.bool_type;
1748 // Optimize out call to op_Equality in a few cases.
1750 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
1751 (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
1752 Type = TypeManager.bool_type;
1757 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
1758 Type = TypeManager.bool_type;
1764 // Delegate equality
1766 MethodGroupExpr mg = null;
1767 Type delegate_type = null;
1768 if (left.eclass == ExprClass.MethodGroup) {
1769 if (!TypeManager.IsDelegateType(r)) {
1770 Error_OperatorCannotBeApplied(Location, OperName(oper),
1771 left.ExprClassName, right.ExprClassName);
1774 mg = (MethodGroupExpr)left;
1776 } else if (right.eclass == ExprClass.MethodGroup) {
1777 if (!TypeManager.IsDelegateType(l)) {
1778 Error_OperatorCannotBeApplied(Location, OperName(oper),
1779 left.ExprClassName, right.ExprClassName);
1782 mg = (MethodGroupExpr)right;
1787 Expression e = ImplicitDelegateCreation.Create (ec, mg, delegate_type, loc);
1791 // Find operator method
1792 string op = oper_names[(int)oper];
1793 MemberInfo[] mi = TypeManager.MemberLookup(ec.ContainerType, null,
1794 TypeManager.delegate_type, MemberTypes.Method, AllBindingFlags, op, null);
1796 ArrayList args = new ArrayList(2);
1797 args.Add(new Argument(e, Argument.AType.Expression));
1798 if (delegate_type == l)
1799 args.Insert(0, new Argument(left, Argument.AType.Expression));
1801 args.Add(new Argument(right, Argument.AType.Expression));
1803 return new BinaryMethod (TypeManager.bool_type, (MethodInfo)mi [0], args);
1806 if (l == TypeManager.anonymous_method_type || r == TypeManager.anonymous_method_type) {
1807 Error_OperatorCannotBeApplied(Location, OperName(oper),
1808 left.ExprClassName, right.ExprClassName);
1815 // Do not perform operator overload resolution when both sides are
1818 MethodGroupExpr left_operators = null, right_operators = null;
1819 if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
1821 // Step 1: Perform Operator Overload location
1823 string op = oper_names [(int) oper];
1825 MethodGroupExpr union;
1826 left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1828 right_operators = MemberLookup (
1829 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1830 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
1832 union = left_operators;
1834 if (union != null) {
1835 ArrayList args = new ArrayList (2);
1836 args.Add (new Argument (left, Argument.AType.Expression));
1837 args.Add (new Argument (right, Argument.AType.Expression));
1839 union = union.OverloadResolve (ec, args, true, Location.Null);
1841 if (union != null) {
1842 MethodInfo mi = (MethodInfo) union;
1843 return new BinaryMethod (mi.ReturnType, mi, args);
1849 // Step 0: String concatenation (because overloading will get this wrong)
1851 if (oper == Operator.Addition){
1853 // If any of the arguments is a string, cast to string
1856 // Simple constant folding
1857 if (left is StringConstant && right is StringConstant)
1858 return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location);
1860 if (l == TypeManager.string_type || r == TypeManager.string_type) {
1862 if (r == TypeManager.void_type || l == TypeManager.void_type) {
1863 Error_OperatorCannotBeApplied ();
1867 // try to fold it in on the left
1868 if (left is StringConcat) {
1871 // We have to test here for not-null, since we can be doubly-resolved
1872 // take care of not appending twice
1875 type = TypeManager.string_type;
1876 ((StringConcat) left).Append (ec, right);
1877 return left.Resolve (ec);
1883 // Otherwise, start a new concat expression
1884 return new StringConcat (ec, loc, left, right).Resolve (ec);
1888 // Transform a + ( - b) into a - b
1890 if (right is Unary){
1891 Unary right_unary = (Unary) right;
1893 if (right_unary.Oper == Unary.Operator.UnaryNegation){
1894 oper = Operator.Subtraction;
1895 right = right_unary.Expr;
1901 if (oper == Operator.Equality || oper == Operator.Inequality){
1902 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1903 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1904 Error_OperatorCannotBeApplied ();
1908 type = TypeManager.bool_type;
1912 if (l.IsPointer || r.IsPointer) {
1913 if (l.IsPointer && r.IsPointer) {
1914 type = TypeManager.bool_type;
1918 if (l.IsPointer && r == TypeManager.null_type) {
1919 right = new EmptyCast (NullPointer.Null, l);
1920 type = TypeManager.bool_type;
1924 if (r.IsPointer && l == TypeManager.null_type) {
1925 left = new EmptyCast (NullPointer.Null, r);
1926 type = TypeManager.bool_type;
1932 if (l.IsGenericParameter && r.IsGenericParameter) {
1933 GenericConstraints l_gc, r_gc;
1935 l_gc = TypeManager.GetTypeParameterConstraints (l);
1936 r_gc = TypeManager.GetTypeParameterConstraints (r);
1938 if ((l_gc == null) || (r_gc == null) ||
1939 !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
1940 !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
1941 Error_OperatorCannotBeApplied ();
1949 // operator != (object a, object b)
1950 // operator == (object a, object b)
1952 // For this to be used, both arguments have to be reference-types.
1953 // Read the rationale on the spec (14.9.6)
1955 if (!(l.IsValueType || r.IsValueType)){
1956 type = TypeManager.bool_type;
1962 // Also, a standard conversion must exist from either one
1964 bool left_to_right =
1965 Convert.ImplicitStandardConversionExists (left, r);
1966 bool right_to_left = !left_to_right &&
1967 Convert.ImplicitStandardConversionExists (right, l);
1969 if (!left_to_right && !right_to_left) {
1970 Error_OperatorCannotBeApplied ();
1974 if (left_to_right && left_operators != null &&
1975 RootContext.WarningLevel >= 2) {
1976 ArrayList args = new ArrayList (2);
1977 args.Add (new Argument (left, Argument.AType.Expression));
1978 args.Add (new Argument (left, Argument.AType.Expression));
1979 if (left_operators.OverloadResolve (ec, args, true, Location.Null) != null)
1980 Warning_UnintendedReferenceComparison (loc, "right", l);
1983 if (right_to_left && right_operators != null &&
1984 RootContext.WarningLevel >= 2) {
1985 ArrayList args = new ArrayList (2);
1986 args.Add (new Argument (right, Argument.AType.Expression));
1987 args.Add (new Argument (right, Argument.AType.Expression));
1988 if (right_operators.OverloadResolve (ec, args, true, Location.Null) != null)
1989 Warning_UnintendedReferenceComparison (loc, "left", r);
1993 // We are going to have to convert to an object to compare
1995 if (l != TypeManager.object_type)
1996 left = new EmptyCast (left, TypeManager.object_type);
1997 if (r != TypeManager.object_type)
1998 right = new EmptyCast (right, TypeManager.object_type);
2004 // Only perform numeric promotions on:
2005 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2007 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2008 if (TypeManager.IsDelegateType (l)){
2009 if (((right.eclass == ExprClass.MethodGroup) ||
2010 (r == TypeManager.anonymous_method_type))){
2011 if ((RootContext.Version != LanguageVersion.ISO_1)){
2012 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2020 if (TypeManager.IsDelegateType (r) || right is NullLiteral){
2022 ArrayList args = new ArrayList (2);
2024 args = new ArrayList (2);
2025 args.Add (new Argument (left, Argument.AType.Expression));
2026 args.Add (new Argument (right, Argument.AType.Expression));
2028 if (oper == Operator.Addition)
2029 method = TypeManager.delegate_combine_delegate_delegate;
2031 method = TypeManager.delegate_remove_delegate_delegate;
2033 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
2034 Error_OperatorCannotBeApplied ();
2038 return new BinaryDelegate (l, method, args);
2043 // Pointer arithmetic:
2045 // T* operator + (T* x, int y);
2046 // T* operator + (T* x, uint y);
2047 // T* operator + (T* x, long y);
2048 // T* operator + (T* x, ulong y);
2050 // T* operator + (int y, T* x);
2051 // T* operator + (uint y, T *x);
2052 // T* operator + (long y, T *x);
2053 // T* operator + (ulong y, T *x);
2055 // T* operator - (T* x, int y);
2056 // T* operator - (T* x, uint y);
2057 // T* operator - (T* x, long y);
2058 // T* operator - (T* x, ulong y);
2060 // long operator - (T* x, T *y)
2063 if (r.IsPointer && oper == Operator.Subtraction){
2065 return new PointerArithmetic (
2066 false, left, right, TypeManager.int64_type,
2069 Expression t = Make32or64 (ec, right);
2071 return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2073 } else if (r.IsPointer && oper == Operator.Addition){
2074 Expression t = Make32or64 (ec, left);
2076 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2081 // Enumeration operators
2083 bool lie = TypeManager.IsEnumType (l);
2084 bool rie = TypeManager.IsEnumType (r);
2088 // U operator - (E e, E f)
2090 if (oper == Operator.Subtraction){
2092 type = TypeManager.EnumToUnderlying (l);
2095 Error_OperatorCannotBeApplied ();
2101 // operator + (E e, U x)
2102 // operator - (E e, U x)
2104 if (oper == Operator.Addition || oper == Operator.Subtraction){
2105 Type enum_type = lie ? l : r;
2106 Type other_type = lie ? r : l;
2107 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2109 if (underlying_type != other_type){
2110 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2120 Error_OperatorCannotBeApplied ();
2129 temp = Convert.ImplicitConversion (ec, right, l, loc);
2133 Error_OperatorCannotBeApplied ();
2137 temp = Convert.ImplicitConversion (ec, left, r, loc);
2142 Error_OperatorCannotBeApplied ();
2147 if (oper == Operator.Equality || oper == Operator.Inequality ||
2148 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2149 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2150 if (left.Type != right.Type){
2151 Error_OperatorCannotBeApplied ();
2154 type = TypeManager.bool_type;
2158 if (oper == Operator.BitwiseAnd ||
2159 oper == Operator.BitwiseOr ||
2160 oper == Operator.ExclusiveOr){
2161 if (left.Type != right.Type){
2162 Error_OperatorCannotBeApplied ();
2168 Error_OperatorCannotBeApplied ();
2172 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2173 return CheckShiftArguments (ec);
2175 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2176 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2177 type = TypeManager.bool_type;
2181 Expression left_operators_e = l == TypeManager.bool_type ?
2182 left : Convert.ImplicitUserConversion (ec, left, TypeManager.bool_type, loc);
2183 Expression right_operators_e = r == TypeManager.bool_type ?
2184 right : Convert.ImplicitUserConversion (ec, right, TypeManager.bool_type, loc);
2186 if (left_operators_e != null && right_operators_e != null) {
2187 left = left_operators_e;
2188 right = right_operators_e;
2189 type = TypeManager.bool_type;
2193 Expression e = new ConditionalLogicalOperator (
2194 oper == Operator.LogicalAnd, left, right, l, loc);
2195 return e.Resolve (ec);
2198 Expression orig_left = left;
2199 Expression orig_right = right;
2202 // operator & (bool x, bool y)
2203 // operator | (bool x, bool y)
2204 // operator ^ (bool x, bool y)
2206 if (oper == Operator.BitwiseAnd ||
2207 oper == Operator.BitwiseOr ||
2208 oper == Operator.ExclusiveOr) {
2209 if (OverloadResolve_PredefinedIntegral (ec)) {
2210 if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
2211 Error_OperatorAmbiguous (loc, oper, l, r);
2215 if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
2216 (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
2217 r == TypeManager.int32_type || r == TypeManager.int64_type)) {
2218 Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2219 TypeManager.CSharpName (r));
2222 } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
2223 Error_OperatorCannotBeApplied ();
2230 // Pointer comparison
2232 if (l.IsPointer && r.IsPointer){
2233 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2234 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2235 type = TypeManager.bool_type;
2240 if (OverloadResolve_PredefinedIntegral (ec)) {
2241 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2242 Error_OperatorAmbiguous (loc, oper, l, r);
2245 } else if (OverloadResolve_PredefinedFloating (ec)) {
2246 if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
2247 IsApplicable_String (ec, orig_left, orig_right, oper)) {
2248 Error_OperatorAmbiguous (loc, oper, l, r);
2251 } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
2252 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2253 Error_OperatorAmbiguous (loc, oper, l, r);
2256 } else if (!OverloadResolve_PredefinedString (ec, oper)) {
2257 Error_OperatorCannotBeApplied ();
2261 if (oper == Operator.Equality ||
2262 oper == Operator.Inequality ||
2263 oper == Operator.LessThanOrEqual ||
2264 oper == Operator.LessThan ||
2265 oper == Operator.GreaterThanOrEqual ||
2266 oper == Operator.GreaterThan)
2267 type = TypeManager.bool_type;
2272 if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
2274 if (r == TypeManager.string_type)
2276 MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
2277 ec.ContainerType, lookup, oper_names [(int) oper],
2278 MemberTypes.Method, AllBindingFlags, loc);
2279 ArrayList args = new ArrayList (2);
2280 args.Add (new Argument (left, Argument.AType.Expression));
2281 args.Add (new Argument (right, Argument.AType.Expression));
2282 ops = ops.OverloadResolve (ec, args, true, Location.Null);
2283 return new BinaryMethod (type, (MethodInfo)ops, args);
2289 Constant EnumLiftUp (Constant left, Constant right)
2292 case Operator.BitwiseOr:
2293 case Operator.BitwiseAnd:
2294 case Operator.ExclusiveOr:
2295 case Operator.Equality:
2296 case Operator.Inequality:
2297 case Operator.LessThan:
2298 case Operator.LessThanOrEqual:
2299 case Operator.GreaterThan:
2300 case Operator.GreaterThanOrEqual:
2301 if (left is EnumConstant)
2304 if (left.IsZeroInteger)
2305 return new EnumConstant (left, right.Type);
2309 case Operator.Addition:
2310 case Operator.Subtraction:
2313 case Operator.Multiply:
2314 case Operator.Division:
2315 case Operator.Modulus:
2316 case Operator.LeftShift:
2317 case Operator.RightShift:
2318 if (right is EnumConstant || left is EnumConstant)
2322 Error_OperatorCannotBeApplied (loc, Binary.OperName (oper), left.Type, right.Type);
2326 public override Expression DoResolve (EmitContext ec)
2331 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2332 left = ((ParenthesizedExpression) left).Expr;
2333 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2337 if (left.eclass == ExprClass.Type) {
2338 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2342 left = left.Resolve (ec);
2347 Constant lc = left as Constant;
2348 if (lc != null && lc.Type == TypeManager.bool_type &&
2349 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2350 (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2352 // TODO: make a sense to resolve unreachable expression as we do for statement
2353 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2357 right = right.Resolve (ec);
2361 eclass = ExprClass.Value;
2362 Constant rc = right as Constant;
2364 // The conversion rules are ignored in enum context but why
2365 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2366 left = lc = EnumLiftUp (lc, rc);
2370 right = rc = EnumLiftUp (rc, lc);
2375 if (oper == Operator.BitwiseAnd) {
2376 if (rc != null && rc.IsZeroInteger) {
2377 return lc is EnumConstant ?
2378 new EnumConstant (rc, lc.Type):
2382 if (lc != null && lc.IsZeroInteger) {
2383 return rc is EnumConstant ?
2384 new EnumConstant (lc, rc.Type):
2388 else if (oper == Operator.BitwiseOr) {
2389 if (lc is EnumConstant &&
2390 rc != null && rc.IsZeroInteger)
2392 if (rc is EnumConstant &&
2393 lc != null && lc.IsZeroInteger)
2395 } else if (oper == Operator.LogicalAnd) {
2396 if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
2398 if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
2402 if (rc != null && lc != null){
2403 int prev_e = Report.Errors;
2404 Expression e = ConstantFold.BinaryFold (
2405 ec, oper, lc, rc, loc);
2406 if (e != null || Report.Errors != prev_e)
2411 if ((left is NullLiteral || left.Type.IsValueType) &&
2412 (right is NullLiteral || right.Type.IsValueType) &&
2413 !(left is NullLiteral && right is NullLiteral) &&
2414 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
2415 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2418 // Comparison warnings
2419 if (oper == Operator.Equality || oper == Operator.Inequality ||
2420 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2421 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2422 if (left.Equals (right)) {
2423 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2425 CheckUselessComparison (lc, right.Type);
2426 CheckUselessComparison (rc, left.Type);
2429 return ResolveOperator (ec);
2432 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2437 private void CheckUselessComparison (Constant c, Type type)
2439 if (c == null || !IsTypeIntegral (type)
2440 || c is StringConstant
2441 || c is BoolConstant
2442 || c is FloatConstant
2443 || c is DoubleConstant
2444 || c is DecimalConstant
2450 if (c is ULongConstant) {
2451 ulong uvalue = ((ULongConstant) c).Value;
2452 if (uvalue > long.MaxValue) {
2453 if (type == TypeManager.byte_type ||
2454 type == TypeManager.sbyte_type ||
2455 type == TypeManager.short_type ||
2456 type == TypeManager.ushort_type ||
2457 type == TypeManager.int32_type ||
2458 type == TypeManager.uint32_type ||
2459 type == TypeManager.int64_type ||
2460 type == TypeManager.char_type)
2461 WarnUselessComparison (type);
2464 value = (long) uvalue;
2466 else if (c is ByteConstant)
2467 value = ((ByteConstant) c).Value;
2468 else if (c is SByteConstant)
2469 value = ((SByteConstant) c).Value;
2470 else if (c is ShortConstant)
2471 value = ((ShortConstant) c).Value;
2472 else if (c is UShortConstant)
2473 value = ((UShortConstant) c).Value;
2474 else if (c is IntConstant)
2475 value = ((IntConstant) c).Value;
2476 else if (c is UIntConstant)
2477 value = ((UIntConstant) c).Value;
2478 else if (c is LongConstant)
2479 value = ((LongConstant) c).Value;
2480 else if (c is CharConstant)
2481 value = ((CharConstant)c).Value;
2486 if (IsValueOutOfRange (value, type))
2487 WarnUselessComparison (type);
2490 private bool IsValueOutOfRange (long value, Type type)
2492 if (IsTypeUnsigned (type) && value < 0)
2494 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2495 type == TypeManager.byte_type && value >= 0x100 ||
2496 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2497 type == TypeManager.ushort_type && value >= 0x10000 ||
2498 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2499 type == TypeManager.uint32_type && value >= 0x100000000;
2502 private static bool IsTypeIntegral (Type type)
2504 return type == TypeManager.uint64_type ||
2505 type == TypeManager.int64_type ||
2506 type == TypeManager.uint32_type ||
2507 type == TypeManager.int32_type ||
2508 type == TypeManager.ushort_type ||
2509 type == TypeManager.short_type ||
2510 type == TypeManager.sbyte_type ||
2511 type == TypeManager.byte_type ||
2512 type == TypeManager.char_type;
2515 private static bool IsTypeUnsigned (Type type)
2517 return type == TypeManager.uint64_type ||
2518 type == TypeManager.uint32_type ||
2519 type == TypeManager.ushort_type ||
2520 type == TypeManager.byte_type ||
2521 type == TypeManager.char_type;
2524 private void WarnUselessComparison (Type type)
2526 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}'",
2527 TypeManager.CSharpName (type));
2531 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2532 /// context of a conditional bool expression. This function will return
2533 /// false if it is was possible to use EmitBranchable, or true if it was.
2535 /// The expression's code is generated, and we will generate a branch to `target'
2536 /// if the resulting expression value is equal to isTrue
2538 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2540 ILGenerator ig = ec.ig;
2543 // This is more complicated than it looks, but its just to avoid
2544 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2545 // but on top of that we want for == and != to use a special path
2546 // if we are comparing against null
2548 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2549 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2552 // put the constant on the rhs, for simplicity
2554 if (left is Constant) {
2555 Expression swap = right;
2560 if (((Constant) right).IsZeroInteger) {
2563 ig.Emit (OpCodes.Brtrue, target);
2565 ig.Emit (OpCodes.Brfalse, target);
2568 } else if (right is BoolConstant) {
2570 if (my_on_true != ((BoolConstant) right).Value)
2571 ig.Emit (OpCodes.Brtrue, target);
2573 ig.Emit (OpCodes.Brfalse, target);
2578 } else if (oper == Operator.LogicalAnd) {
2581 Label tests_end = ig.DefineLabel ();
2583 left.EmitBranchable (ec, tests_end, false);
2584 right.EmitBranchable (ec, target, true);
2585 ig.MarkLabel (tests_end);
2588 // This optimizes code like this
2589 // if (true && i > 4)
2591 if (!(left is Constant))
2592 left.EmitBranchable (ec, target, false);
2594 if (!(right is Constant))
2595 right.EmitBranchable (ec, target, false);
2600 } else if (oper == Operator.LogicalOr){
2602 left.EmitBranchable (ec, target, true);
2603 right.EmitBranchable (ec, target, true);
2606 Label tests_end = ig.DefineLabel ();
2607 left.EmitBranchable (ec, tests_end, true);
2608 right.EmitBranchable (ec, target, false);
2609 ig.MarkLabel (tests_end);
2614 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2615 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2616 oper == Operator.Equality || oper == Operator.Inequality)) {
2617 base.EmitBranchable (ec, target, onTrue);
2625 bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2628 case Operator.Equality:
2630 ig.Emit (OpCodes.Beq, target);
2632 ig.Emit (OpCodes.Bne_Un, target);
2635 case Operator.Inequality:
2637 ig.Emit (OpCodes.Bne_Un, target);
2639 ig.Emit (OpCodes.Beq, target);
2642 case Operator.LessThan:
2645 ig.Emit (OpCodes.Blt_Un, target);
2647 ig.Emit (OpCodes.Blt, target);
2650 ig.Emit (OpCodes.Bge_Un, target);
2652 ig.Emit (OpCodes.Bge, target);
2655 case Operator.GreaterThan:
2658 ig.Emit (OpCodes.Bgt_Un, target);
2660 ig.Emit (OpCodes.Bgt, target);
2663 ig.Emit (OpCodes.Ble_Un, target);
2665 ig.Emit (OpCodes.Ble, target);
2668 case Operator.LessThanOrEqual:
2671 ig.Emit (OpCodes.Ble_Un, target);
2673 ig.Emit (OpCodes.Ble, target);
2676 ig.Emit (OpCodes.Bgt_Un, target);
2678 ig.Emit (OpCodes.Bgt, target);
2682 case Operator.GreaterThanOrEqual:
2685 ig.Emit (OpCodes.Bge_Un, target);
2687 ig.Emit (OpCodes.Bge, target);
2690 ig.Emit (OpCodes.Blt_Un, target);
2692 ig.Emit (OpCodes.Blt, target);
2695 Console.WriteLine (oper);
2696 throw new Exception ("what is THAT");
2700 public override void Emit (EmitContext ec)
2702 ILGenerator ig = ec.ig;
2707 // Handle short-circuit operators differently
2710 if (oper == Operator.LogicalAnd) {
2711 Label load_zero = ig.DefineLabel ();
2712 Label end = ig.DefineLabel ();
2714 left.EmitBranchable (ec, load_zero, false);
2716 ig.Emit (OpCodes.Br, end);
2718 ig.MarkLabel (load_zero);
2719 ig.Emit (OpCodes.Ldc_I4_0);
2722 } else if (oper == Operator.LogicalOr) {
2723 Label load_one = ig.DefineLabel ();
2724 Label end = ig.DefineLabel ();
2726 left.EmitBranchable (ec, load_one, true);
2728 ig.Emit (OpCodes.Br, end);
2730 ig.MarkLabel (load_one);
2731 ig.Emit (OpCodes.Ldc_I4_1);
2739 bool isUnsigned = is_unsigned (left.Type);
2742 case Operator.Multiply:
2744 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2745 opcode = OpCodes.Mul_Ovf;
2746 else if (isUnsigned)
2747 opcode = OpCodes.Mul_Ovf_Un;
2749 opcode = OpCodes.Mul;
2751 opcode = OpCodes.Mul;
2755 case Operator.Division:
2757 opcode = OpCodes.Div_Un;
2759 opcode = OpCodes.Div;
2762 case Operator.Modulus:
2764 opcode = OpCodes.Rem_Un;
2766 opcode = OpCodes.Rem;
2769 case Operator.Addition:
2771 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2772 opcode = OpCodes.Add_Ovf;
2773 else if (isUnsigned)
2774 opcode = OpCodes.Add_Ovf_Un;
2776 opcode = OpCodes.Add;
2778 opcode = OpCodes.Add;
2781 case Operator.Subtraction:
2783 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2784 opcode = OpCodes.Sub_Ovf;
2785 else if (isUnsigned)
2786 opcode = OpCodes.Sub_Ovf_Un;
2788 opcode = OpCodes.Sub;
2790 opcode = OpCodes.Sub;
2793 case Operator.RightShift:
2795 opcode = OpCodes.Shr_Un;
2797 opcode = OpCodes.Shr;
2800 case Operator.LeftShift:
2801 opcode = OpCodes.Shl;
2804 case Operator.Equality:
2805 opcode = OpCodes.Ceq;
2808 case Operator.Inequality:
2809 ig.Emit (OpCodes.Ceq);
2810 ig.Emit (OpCodes.Ldc_I4_0);
2812 opcode = OpCodes.Ceq;
2815 case Operator.LessThan:
2817 opcode = OpCodes.Clt_Un;
2819 opcode = OpCodes.Clt;
2822 case Operator.GreaterThan:
2824 opcode = OpCodes.Cgt_Un;
2826 opcode = OpCodes.Cgt;
2829 case Operator.LessThanOrEqual:
2830 Type lt = left.Type;
2832 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
2833 ig.Emit (OpCodes.Cgt_Un);
2835 ig.Emit (OpCodes.Cgt);
2836 ig.Emit (OpCodes.Ldc_I4_0);
2838 opcode = OpCodes.Ceq;
2841 case Operator.GreaterThanOrEqual:
2842 Type le = left.Type;
2844 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
2845 ig.Emit (OpCodes.Clt_Un);
2847 ig.Emit (OpCodes.Clt);
2849 ig.Emit (OpCodes.Ldc_I4_0);
2851 opcode = OpCodes.Ceq;
2854 case Operator.BitwiseOr:
2855 opcode = OpCodes.Or;
2858 case Operator.BitwiseAnd:
2859 opcode = OpCodes.And;
2862 case Operator.ExclusiveOr:
2863 opcode = OpCodes.Xor;
2867 throw new Exception ("This should not happen: Operator = "
2868 + oper.ToString ());
2874 protected override void CloneTo (CloneContext clonectx, Expression t)
2876 Binary target = (Binary) t;
2878 target.left = left.Clone (clonectx);
2879 target.right = right.Clone (clonectx);
2884 // Object created by Binary when the binary operator uses an method instead of being
2885 // a binary operation that maps to a CIL binary operation.
2887 public class BinaryMethod : Expression {
2888 public MethodBase method;
2889 public ArrayList Arguments;
2891 public BinaryMethod (Type t, MethodBase m, ArrayList args)
2896 eclass = ExprClass.Value;
2899 public override Expression DoResolve (EmitContext ec)
2904 public override void Emit (EmitContext ec)
2906 ILGenerator ig = ec.ig;
2908 if (Arguments != null)
2909 Invocation.EmitArguments (ec, method, Arguments, false, null);
2911 if (method is MethodInfo)
2912 ig.Emit (OpCodes.Call, (MethodInfo) method);
2914 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2919 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
2920 // b, c, d... may be strings or objects.
2922 public class StringConcat : Expression {
2924 bool invalid = false;
2925 bool emit_conv_done = false;
2927 // Are we also concating objects?
2929 bool is_strings_only = true;
2931 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
2934 type = TypeManager.string_type;
2935 eclass = ExprClass.Value;
2937 operands = new ArrayList (2);
2942 public override Expression DoResolve (EmitContext ec)
2950 public void Append (EmitContext ec, Expression operand)
2955 StringConstant sc = operand as StringConstant;
2957 // TODO: it will be better to do this silently as an optimalization
2959 // string s = "" + i;
2960 // because this code has poor performace
2961 // if (sc.Value.Length == 0)
2962 // Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?");
2964 if (operands.Count != 0) {
2965 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
2966 if (last_operand != null) {
2967 operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
2974 // Conversion to object
2976 if (operand.Type != TypeManager.string_type) {
2977 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
2980 Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
2986 operands.Add (operand);
2989 public override void Emit (EmitContext ec)
2991 MethodInfo concat_method = null;
2994 // Do conversion to arguments; check for strings only
2997 // This can get called multiple times, so we have to deal with that.
2998 if (!emit_conv_done) {
2999 emit_conv_done = true;
3000 for (int i = 0; i < operands.Count; i ++) {
3001 Expression e = (Expression) operands [i];
3002 is_strings_only &= e.Type == TypeManager.string_type;
3005 for (int i = 0; i < operands.Count; i ++) {
3006 Expression e = (Expression) operands [i];
3008 if (! is_strings_only && e.Type == TypeManager.string_type) {
3009 // need to make sure this is an object, because the EmitParams
3010 // method might look at the type of this expression, see it is a
3011 // string and emit a string [] when we want an object [];
3013 e = new EmptyCast (e, TypeManager.object_type);
3015 operands [i] = new Argument (e, Argument.AType.Expression);
3020 // Find the right method
3022 switch (operands.Count) {
3025 // This should not be possible, because simple constant folding
3026 // is taken care of in the Binary code.
3028 throw new Exception ("how did you get here?");
3031 concat_method = is_strings_only ?
3032 TypeManager.string_concat_string_string :
3033 TypeManager.string_concat_object_object ;
3036 concat_method = is_strings_only ?
3037 TypeManager.string_concat_string_string_string :
3038 TypeManager.string_concat_object_object_object ;
3042 // There is not a 4 param overlaod for object (the one that there is
3043 // is actually a varargs methods, and is only in corlib because it was
3044 // introduced there before.).
3046 if (!is_strings_only)
3049 concat_method = TypeManager.string_concat_string_string_string_string;
3052 concat_method = is_strings_only ?
3053 TypeManager.string_concat_string_dot_dot_dot :
3054 TypeManager.string_concat_object_dot_dot_dot ;
3058 Invocation.EmitArguments (ec, concat_method, operands, false, null);
3059 ec.ig.Emit (OpCodes.Call, concat_method);
3064 // Object created with +/= on delegates
3066 public class BinaryDelegate : Expression {
3070 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3075 eclass = ExprClass.Value;
3078 public override Expression DoResolve (EmitContext ec)
3083 public override void Emit (EmitContext ec)
3085 ILGenerator ig = ec.ig;
3087 Invocation.EmitArguments (ec, method, args, false, null);
3089 ig.Emit (OpCodes.Call, (MethodInfo) method);
3090 ig.Emit (OpCodes.Castclass, type);
3093 public Expression Right {
3095 Argument arg = (Argument) args [1];
3100 public bool IsAddition {
3102 return method == TypeManager.delegate_combine_delegate_delegate;
3108 // User-defined conditional logical operator
3109 public class ConditionalLogicalOperator : Expression {
3110 Expression left, right;
3113 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3116 eclass = ExprClass.Value;
3120 this.is_and = is_and;
3123 protected void Error19 ()
3125 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3128 protected void Error218 ()
3130 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3131 "declarations of operator true and operator false");
3134 Expression op_true, op_false, op;
3135 LocalTemporary left_temp;
3137 public override Expression DoResolve (EmitContext ec)
3139 MethodGroupExpr operator_group;
3141 operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc) as MethodGroupExpr;
3142 if (operator_group == null) {
3147 left_temp = new LocalTemporary (type);
3149 ArrayList arguments = new ArrayList (2);
3150 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3151 arguments.Add (new Argument (right, Argument.AType.Expression));
3152 operator_group = operator_group.OverloadResolve (ec, arguments, false, loc);
3153 if (operator_group == null) {
3158 MethodInfo method = (MethodInfo)operator_group;
3159 if (method.ReturnType != type) {
3160 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3161 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3165 op = new StaticCallExpr (method, arguments, loc);
3167 op_true = GetOperatorTrue (ec, left_temp, loc);
3168 op_false = GetOperatorFalse (ec, left_temp, loc);
3169 if ((op_true == null) || (op_false == null)) {
3177 public override void Emit (EmitContext ec)
3179 ILGenerator ig = ec.ig;
3180 Label false_target = ig.DefineLabel ();
3181 Label end_target = ig.DefineLabel ();
3184 left_temp.Store (ec);
3186 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3187 left_temp.Emit (ec);
3188 ig.Emit (OpCodes.Br, end_target);
3189 ig.MarkLabel (false_target);
3191 ig.MarkLabel (end_target);
3193 // We release 'left_temp' here since 'op' may refer to it too
3194 left_temp.Release (ec);
3198 public class PointerArithmetic : Expression {
3199 Expression left, right;
3203 // We assume that `l' is always a pointer
3205 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3211 is_add = is_addition;
3214 public override Expression DoResolve (EmitContext ec)
3216 eclass = ExprClass.Variable;
3218 if (left.Type == TypeManager.void_ptr_type) {
3219 Error (242, "The operation in question is undefined on void pointers");
3226 public override void Emit (EmitContext ec)
3228 Type op_type = left.Type;
3229 ILGenerator ig = ec.ig;
3231 // It must be either array or fixed buffer
3232 Type element = TypeManager.HasElementType (op_type) ?
3233 element = TypeManager.GetElementType (op_type) :
3234 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3236 int size = GetTypeSize (element);
3237 Type rtype = right.Type;
3239 if (rtype.IsPointer){
3241 // handle (pointer - pointer)
3245 ig.Emit (OpCodes.Sub);
3249 ig.Emit (OpCodes.Sizeof, element);
3251 IntLiteral.EmitInt (ig, size);
3252 ig.Emit (OpCodes.Div);
3254 ig.Emit (OpCodes.Conv_I8);
3257 // handle + and - on (pointer op int)
3260 ig.Emit (OpCodes.Conv_I);
3262 Constant right_const = right as Constant;
3263 if (right_const != null && size != 0) {
3264 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3272 ig.Emit (OpCodes.Sizeof, element);
3274 IntLiteral.EmitInt (ig, size);
3275 if (rtype == TypeManager.int64_type)
3276 ig.Emit (OpCodes.Conv_I8);
3277 else if (rtype == TypeManager.uint64_type)
3278 ig.Emit (OpCodes.Conv_U8);
3279 ig.Emit (OpCodes.Mul);
3283 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3284 ig.Emit (OpCodes.Conv_I);
3287 ig.Emit (OpCodes.Add);
3289 ig.Emit (OpCodes.Sub);
3295 /// Implements the ternary conditional operator (?:)
3297 public class Conditional : Expression {
3298 Expression expr, trueExpr, falseExpr;
3300 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
3303 this.trueExpr = trueExpr;
3304 this.falseExpr = falseExpr;
3305 this.loc = expr.Location;
3308 public Expression Expr {
3314 public Expression TrueExpr {
3320 public Expression FalseExpr {
3326 public override Expression DoResolve (EmitContext ec)
3328 expr = expr.Resolve (ec);
3334 if (TypeManager.IsNullableValueType (expr.Type))
3335 return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
3338 if (expr.Type != TypeManager.bool_type){
3339 expr = Expression.ResolveBoolean (
3346 Assign ass = expr as Assign;
3347 if (ass != null && ass.Source is Constant) {
3348 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3351 trueExpr = trueExpr.Resolve (ec);
3352 falseExpr = falseExpr.Resolve (ec);
3354 if (trueExpr == null || falseExpr == null)
3357 eclass = ExprClass.Value;
3358 if (trueExpr.Type == falseExpr.Type) {
3359 type = trueExpr.Type;
3360 if (type == TypeManager.null_type) {
3361 // TODO: probably will have to implement ConditionalConstant
3362 // to call method without return constant as well
3363 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3368 Type true_type = trueExpr.Type;
3369 Type false_type = falseExpr.Type;
3372 // First, if an implicit conversion exists from trueExpr
3373 // to falseExpr, then the result type is of type falseExpr.Type
3375 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3378 // Check if both can convert implicitl to each other's type
3380 if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3382 "Can not compute type of conditional expression " +
3383 "as `" + TypeManager.CSharpName (trueExpr.Type) +
3384 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3385 "' convert implicitly to each other");
3390 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3394 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3395 trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
3400 // Dead code optimalization
3401 if (expr is BoolConstant){
3402 BoolConstant bc = (BoolConstant) expr;
3404 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3405 return bc.Value ? trueExpr : falseExpr;
3411 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3416 public override void Emit (EmitContext ec)
3418 ILGenerator ig = ec.ig;
3419 Label false_target = ig.DefineLabel ();
3420 Label end_target = ig.DefineLabel ();
3422 expr.EmitBranchable (ec, false_target, false);
3424 ig.Emit (OpCodes.Br, end_target);
3425 ig.MarkLabel (false_target);
3426 falseExpr.Emit (ec);
3427 ig.MarkLabel (end_target);
3430 protected override void CloneTo (CloneContext clonectx, Expression t)
3432 Conditional target = (Conditional) t;
3434 target.expr = expr.Clone (clonectx);
3435 target.trueExpr = trueExpr.Clone (clonectx);
3436 target.falseExpr = falseExpr.Clone (clonectx);
3440 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3442 LocalTemporary temp;
3444 public abstract Variable Variable {
3448 public abstract bool IsRef {
3452 public override void Emit (EmitContext ec)
3458 // This method is used by parameters that are references, that are
3459 // being passed as references: we only want to pass the pointer (that
3460 // is already stored in the parameter, not the address of the pointer,
3461 // and not the value of the variable).
3463 public void EmitLoad (EmitContext ec)
3465 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3467 Variable.EmitInstance (ec);
3471 public void Emit (EmitContext ec, bool leave_copy)
3473 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3479 ec.ig.Emit (OpCodes.Dup);
3482 // If we are a reference, we loaded on the stack a pointer
3483 // Now lets load the real value
3485 LoadFromPtr (ec.ig, type);
3489 ec.ig.Emit (OpCodes.Dup);
3491 if (IsRef || Variable.NeedsTemporary) {
3492 temp = new LocalTemporary (Type);
3498 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3499 bool prepare_for_load)
3501 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3504 ILGenerator ig = ec.ig;
3505 prepared = prepare_for_load;
3507 Variable.EmitInstance (ec);
3508 if (prepare_for_load && Variable.HasInstance)
3509 ig.Emit (OpCodes.Dup);
3510 else if (IsRef && !prepared)
3516 ig.Emit (OpCodes.Dup);
3517 if (IsRef || Variable.NeedsTemporary) {
3518 temp = new LocalTemporary (Type);
3524 StoreFromPtr (ig, type);
3526 Variable.EmitAssign (ec);
3534 public void AddressOf (EmitContext ec, AddressOp mode)
3536 Variable.EmitInstance (ec);
3537 Variable.EmitAddressOf (ec);
3544 public class LocalVariableReference : VariableReference, IVariable {
3545 public readonly string Name;
3547 public LocalInfo local_info;
3551 public LocalVariableReference (Block block, string name, Location l)
3556 eclass = ExprClass.Variable;
3560 // Setting `is_readonly' to false will allow you to create a writable
3561 // reference to a read-only variable. This is used by foreach and using.
3563 public LocalVariableReference (Block block, string name, Location l,
3564 LocalInfo local_info, bool is_readonly)
3565 : this (block, name, l)
3567 this.local_info = local_info;
3568 this.is_readonly = is_readonly;
3571 public VariableInfo VariableInfo {
3572 get { return local_info.VariableInfo; }
3575 public override bool IsRef {
3576 get { return false; }
3579 public bool IsReadOnly {
3580 get { return is_readonly; }
3583 public bool VerifyAssigned (EmitContext ec)
3585 VariableInfo variable_info = local_info.VariableInfo;
3586 return variable_info == null || variable_info.IsAssigned (ec, loc);
3589 void ResolveLocalInfo ()
3591 if (local_info == null) {
3592 local_info = Block.GetLocalInfo (Name);
3593 type = local_info.VariableType;
3594 is_readonly = local_info.ReadOnly;
3598 protected Expression DoResolveBase (EmitContext ec)
3600 type = local_info.VariableType;
3602 Expression e = Block.GetConstantExpression (Name);
3604 return e.Resolve (ec);
3606 if (!VerifyAssigned (ec))
3610 // If we are referencing a variable from the external block
3611 // flag it for capturing
3613 if (ec.MustCaptureVariable (local_info)) {
3614 if (local_info.AddressTaken){
3615 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3619 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3620 variable = scope.AddLocal (local_info);
3621 type = variable.Type;
3627 public override Expression DoResolve (EmitContext ec)
3629 ResolveLocalInfo ();
3630 local_info.Used = true;
3632 if (type == null && local_info.Type is VarExpr) {
3633 local_info.VariableType = TypeManager.object_type;
3634 Error_VariableIsUsedBeforeItIsDeclared (Name);
3638 return DoResolveBase (ec);
3641 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3643 ResolveLocalInfo ();
3646 if (right_side == EmptyExpression.OutAccess)
3647 local_info.Used = true;
3649 // Infer implicitly typed local variable
3651 VarExpr ve = local_info.Type as VarExpr;
3653 ve.DoResolveLValue (ec, right_side);
3654 type = local_info.VariableType = ve.Type;
3661 if (right_side == EmptyExpression.OutAccess) {
3662 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3663 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3664 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3665 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3666 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3668 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3670 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3674 if (VariableInfo != null)
3675 VariableInfo.SetAssigned (ec);
3677 return DoResolveBase (ec);
3680 public bool VerifyFixed ()
3682 // A local Variable is always fixed.
3686 public override int GetHashCode ()
3688 return Name.GetHashCode ();
3691 public override bool Equals (object obj)
3693 LocalVariableReference lvr = obj as LocalVariableReference;
3697 return Name == lvr.Name && Block == lvr.Block;
3700 public override Variable Variable {
3701 get { return variable != null ? variable : local_info.Variable; }
3704 public override string ToString ()
3706 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3709 protected override void CloneTo (CloneContext clonectx, Expression t)
3711 LocalVariableReference target = (LocalVariableReference) t;
3713 target.Block = clonectx.LookupBlock (Block);
3718 /// This represents a reference to a parameter in the intermediate
3721 public class ParameterReference : VariableReference, IVariable {
3722 ToplevelParameterInfo pi;
3723 ToplevelBlock referenced;
3725 public bool is_ref, is_out;
3728 get { return is_out; }
3731 public override bool IsRef {
3732 get { return is_ref; }
3735 public string Name {
3736 get { return Parameter.Name; }
3739 public Parameter Parameter {
3740 get { return pi.Parameter; }
3745 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
3748 this.referenced = referenced;
3750 eclass = ExprClass.Variable;
3753 public VariableInfo VariableInfo {
3754 get { return pi.VariableInfo; }
3757 public override Variable Variable {
3758 get { return variable != null ? variable : Parameter.Variable; }
3761 public bool VerifyFixed ()
3763 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3764 return Parameter.ModFlags == Parameter.Modifier.NONE;
3767 public bool IsAssigned (EmitContext ec, Location loc)
3769 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
3772 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
3776 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3778 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
3781 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
3785 public void SetAssigned (EmitContext ec)
3787 if (is_out && ec.DoFlowAnalysis)
3788 ec.CurrentBranching.SetAssigned (VariableInfo);
3791 public void SetFieldAssigned (EmitContext ec, string field_name)
3793 if (is_out && ec.DoFlowAnalysis)
3794 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
3797 protected bool DoResolveBase (EmitContext ec)
3799 Parameter par = Parameter;
3800 if (!par.Resolve (ec)) {
3804 type = par.ParameterType;
3805 Parameter.Modifier mod = par.ModFlags;
3806 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3807 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3808 eclass = ExprClass.Variable;
3810 ToplevelBlock declared = pi.Block;
3812 AnonymousContainer am = ec.CurrentAnonymousMethod;
3816 if (is_ref && declared != referenced) {
3817 Report.Error (1628, Location,
3818 "Cannot use ref or out parameter `{0}' inside an " +
3819 "anonymous method block", par.Name);
3823 if (!am.IsIterator && declared == referenced)
3826 ScopeInfo scope = declared.CreateScopeInfo ();
3827 variable = scope.AddParameter (par, pi.Index);
3828 type = variable.Type;
3832 public override int GetHashCode ()
3834 return Name.GetHashCode ();
3837 public override bool Equals (object obj)
3839 ParameterReference pr = obj as ParameterReference;
3843 return Name == pr.Name && referenced == pr.referenced;
3847 // Notice that for ref/out parameters, the type exposed is not the
3848 // same type exposed externally.
3851 // externally we expose "int&"
3852 // here we expose "int".
3854 // We record this in "is_ref". This means that the type system can treat
3855 // the type as it is expected, but when we generate the code, we generate
3856 // the alternate kind of code.
3858 public override Expression DoResolve (EmitContext ec)
3860 if (!DoResolveBase (ec))
3863 if (is_out && ec.DoFlowAnalysis &&
3864 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3870 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3872 if (!DoResolveBase (ec))
3880 static public void EmitLdArg (ILGenerator ig, int x)
3884 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3885 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3886 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3887 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3888 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3891 ig.Emit (OpCodes.Ldarg, x);
3894 public override string ToString ()
3896 return "ParameterReference[" + Name + "]";
3901 /// Used for arguments to New(), Invocation()
3903 public class Argument {
3904 public enum AType : byte {
3911 public static readonly Argument[] Empty = new Argument [0];
3913 public readonly AType ArgType;
3914 public Expression Expr;
3916 public Argument (Expression expr, AType type)
3919 this.ArgType = type;
3922 public Argument (Expression expr)
3925 this.ArgType = AType.Expression;
3930 if (ArgType == AType.Ref || ArgType == AType.Out)
3931 return TypeManager.GetReferenceType (Expr.Type);
3937 public Parameter.Modifier Modifier
3942 return Parameter.Modifier.OUT;
3945 return Parameter.Modifier.REF;
3948 return Parameter.Modifier.NONE;
3953 public static string FullDesc (Argument a)
3955 if (a.ArgType == AType.ArgList)
3958 return (a.ArgType == AType.Ref ? "ref " :
3959 (a.ArgType == AType.Out ? "out " : "")) +
3960 TypeManager.CSharpName (a.Expr.Type);
3963 public bool ResolveMethodGroup (EmitContext ec)
3965 SimpleName sn = Expr as SimpleName;
3967 Expr = sn.GetMethodGroup ();
3969 // FIXME: csc doesn't report any error if you try to use `ref' or
3970 // `out' in a delegate creation expression.
3971 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3978 public bool Resolve (EmitContext ec, Location loc)
3980 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
3981 // Verify that the argument is readable
3982 if (ArgType != AType.Out)
3983 Expr = Expr.Resolve (ec);
3985 // Verify that the argument is writeable
3986 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
3987 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
3989 return Expr != null;
3993 public void Emit (EmitContext ec)
3995 if (ArgType != AType.Ref && ArgType != AType.Out) {
4000 AddressOp mode = AddressOp.Store;
4001 if (ArgType == AType.Ref)
4002 mode |= AddressOp.Load;
4004 IMemoryLocation ml = (IMemoryLocation) Expr;
4005 ParameterReference pr = ml as ParameterReference;
4008 // ParameterReferences might already be references, so we want
4009 // to pass just the value
4011 if (pr != null && pr.IsRef)
4014 ml.AddressOf (ec, mode);
4017 public Argument Clone (CloneContext clonectx)
4019 return new Argument (Expr.Clone (clonectx), ArgType);
4024 /// Invocation of methods or delegates.
4026 public class Invocation : ExpressionStatement {
4027 ArrayList Arguments;
4032 // arguments is an ArrayList, but we do not want to typecast,
4033 // as it might be null.
4035 public Invocation (Expression expr, ArrayList arguments)
4037 SimpleName sn = expr as SimpleName;
4039 this.expr = sn.GetMethodGroup ();
4043 Arguments = arguments;
4044 loc = expr.Location;
4047 public static string FullMethodDesc (MethodBase mb)
4053 if (mb is MethodInfo) {
4054 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4058 sb = new StringBuilder ();
4060 sb.Append (TypeManager.CSharpSignature (mb));
4061 return sb.ToString ();
4064 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4065 ArrayList arguments, int arg_count,
4066 ref MethodBase candidate)
4068 return IsParamsMethodApplicable (
4069 ec, me, arguments, arg_count, false, ref candidate) ||
4070 IsParamsMethodApplicable (
4071 ec, me, arguments, arg_count, true, ref candidate);
4076 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4077 ArrayList arguments, int arg_count,
4078 bool do_varargs, ref MethodBase candidate)
4081 if (!me.HasTypeArguments &&
4082 !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4085 if (TypeManager.IsGenericMethodDefinition (candidate))
4086 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4089 return IsParamsMethodApplicable (
4090 ec, arguments, arg_count, candidate, do_varargs);
4094 /// Determines if the candidate method, if a params method, is applicable
4095 /// in its expanded form to the given set of arguments
4097 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4098 int arg_count, MethodBase candidate,
4101 ParameterData pd = TypeManager.GetParameterData (candidate);
4103 int pd_count = pd.Count;
4107 int count = pd_count - 1;
4109 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4111 if (pd_count != arg_count)
4114 if (!(((Argument) arguments [count]).Expr is Arglist))
4122 if (count > arg_count)
4125 if (pd_count == 1 && arg_count == 0)
4129 // If we have come this far, the case which
4130 // remains is when the number of parameters is
4131 // less than or equal to the argument count.
4133 int argument_index = 0;
4135 for (int i = 0; i < pd_count; ++i) {
4137 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
4138 Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4139 int params_args_count = arg_count - pd_count;
4140 if (params_args_count < 0)
4144 a = (Argument) arguments [argument_index++];
4146 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4148 } while (params_args_count-- > 0);
4152 a = (Argument) arguments [argument_index++];
4154 Parameter.Modifier a_mod = a.Modifier &
4155 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4156 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4157 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4159 if (a_mod == p_mod) {
4161 if (a_mod == Parameter.Modifier.NONE)
4162 if (!Convert.ImplicitConversionExists (ec,
4164 pd.ParameterType (i)))
4167 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4168 Type pt = pd.ParameterType (i);
4171 pt = TypeManager.GetReferenceType (pt);
4184 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4185 ArrayList arguments, int arg_count,
4186 ref MethodBase method)
4188 MethodBase candidate = method;
4191 if (!me.HasTypeArguments &&
4192 !TypeManager.InferTypeArguments (ec, arguments, ref candidate))
4195 if (TypeManager.IsGenericMethodDefinition (candidate))
4196 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4199 if (IsApplicable (ec, arguments, arg_count, candidate)) {
4208 /// Determines if the candidate method is applicable (section 14.4.2.1)
4209 /// to the given set of arguments
4211 public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4212 MethodBase candidate)
4214 ParameterData pd = TypeManager.GetParameterData (candidate);
4216 if (arg_count != pd.Count)
4219 for (int i = arg_count; i > 0; ) {
4222 Argument a = (Argument) arguments [i];
4224 Parameter.Modifier a_mod = a.Modifier &
4225 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4227 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4228 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
4233 Type pt = pd.ParameterType (i);
4234 EmitContext prevec = EmitContext.TempEc;
4235 EmitContext.TempEc = ec;
4238 if (a_mod == Parameter.Modifier.NONE) {
4239 // It is already done in ImplicitConversion need to measure the performance, it causes problem in MWF
4240 if (TypeManager.IsEqual (a.Type, pt))
4243 if (!Convert.ImplicitConversionExists (ec, a.Expr, pt))
4248 EmitContext.TempEc = prevec;
4258 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4260 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4261 name, arg_count.ToString ());
4264 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4265 Type delegate_type, Argument a, ParameterData expected_par)
4267 if (delegate_type == null)
4268 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4269 TypeManager.CSharpSignature (method));
4271 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4272 TypeManager.CSharpName (delegate_type));
4274 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4276 string index = (idx + 1).ToString ();
4277 if (mod != Parameter.Modifier.ARGLIST && mod != a.Modifier) {
4278 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4279 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4280 index, Parameter.GetModifierSignature (a.Modifier));
4282 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4283 index, Parameter.GetModifierSignature (mod));
4285 string p1 = Argument.FullDesc (a);
4286 string p2 = TypeManager.CSharpName (expected_par.ParameterType (idx));
4289 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4290 Report.SymbolRelatedToPreviousError (a.Expr.Type);
4291 Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4293 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
4297 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4298 int arg_count, MethodBase method,
4299 bool chose_params_expanded,
4300 Type delegate_type, bool may_fail,
4303 ParameterData pd = TypeManager.GetParameterData (method);
4307 for (j = 0; j < pd.Count; j++) {
4308 Type parameter_type = pd.ParameterType (j);
4309 Parameter.Modifier pm = pd.ParameterModifier (j);
4311 if (pm == Parameter.Modifier.ARGLIST) {
4312 a = (Argument) Arguments [a_idx];
4313 if (!(a.Expr is Arglist))
4319 int params_arg_count = 1;
4320 if (pm == Parameter.Modifier.PARAMS) {
4321 pm = Parameter.Modifier.NONE;
4322 params_arg_count = arg_count - pd.Count + 1;
4323 if (chose_params_expanded)
4324 parameter_type = TypeManager.GetElementType (parameter_type);
4327 while (params_arg_count > 0) {
4328 a = (Argument) Arguments [a_idx];
4329 if (pm != a.Modifier)
4332 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4333 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4336 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4340 // Update the argument with the implicit conversion
4348 if (params_arg_count > 0)
4351 if (parameter_type.IsPointer && !ec.InUnsafe) {
4358 if (a_idx == arg_count)
4362 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4366 public override Expression DoResolve (EmitContext ec)
4368 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4369 if (expr_resolved == null)
4372 mg = expr_resolved as MethodGroupExpr;
4374 Type expr_type = expr_resolved.Type;
4376 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4377 return (new DelegateInvocation (
4378 expr_resolved, Arguments, loc)).Resolve (ec);
4380 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4385 // Next, evaluate all the expressions in the argument list
4387 if (Arguments != null){
4388 foreach (Argument a in Arguments){
4389 if (!a.Resolve (ec, loc))
4394 mg = mg.OverloadResolve (ec, Arguments, false, loc);
4398 MethodInfo method = (MethodInfo)mg;
4399 if (method != null) {
4400 type = TypeManager.TypeToCoreType (method.ReturnType);
4401 Expression iexpr = mg.InstanceExpression;
4402 if (method.IsStatic) {
4403 if (iexpr == null ||
4404 iexpr is This || iexpr is EmptyExpression ||
4405 mg.IdenticalTypeName) {
4406 mg.InstanceExpression = null;
4408 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4412 if (iexpr == null || iexpr is EmptyExpression) {
4413 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4419 if (type.IsPointer){
4427 // Only base will allow this invocation to happen.
4429 if (mg.IsBase && method.IsAbstract){
4430 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4434 if (Arguments == null && method.Name == "Finalize") {
4436 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4438 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4442 if (IsSpecialMethodInvocation (method)) {
4446 if (mg.InstanceExpression != null){
4447 mg.InstanceExpression.CheckMarshalByRefAccess ();
4450 // This is used to check that no methods are called in struct
4451 // constructors before all the fields on the struct have been
4454 if (!method.IsStatic){
4455 This mgthis = mg.InstanceExpression as This;
4456 if (mgthis != null){
4457 if (!mgthis.CheckThisUsage (ec))
4463 eclass = ExprClass.Value;
4467 bool IsSpecialMethodInvocation (MethodBase method)
4469 if (!TypeManager.IsSpecialMethod (method))
4472 Report.SymbolRelatedToPreviousError (method);
4473 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4474 TypeManager.CSharpSignature (method, true));
4480 // Emits the list of arguments as an array
4482 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
4484 ILGenerator ig = ec.ig;
4486 for (int j = 0; j < count; j++){
4487 Argument a = (Argument) arguments [j + idx];
4490 IntConstant.EmitInt (ig, count);
4491 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4494 ig.Emit (OpCodes.Dup);
4495 IntConstant.EmitInt (ig, j);
4497 bool is_stobj, has_type_arg;
4498 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
4500 ig.Emit (OpCodes.Ldelema, t);
4512 /// Emits a list of resolved Arguments that are in the arguments
4515 /// The MethodBase argument might be null if the
4516 /// emission of the arguments is known not to contain
4517 /// a `params' field (for example in constructors or other routines
4518 /// that keep their arguments in this structure)
4520 /// if `dup_args' is true, a copy of the arguments will be left
4521 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4522 /// which will be duplicated before any other args. Only EmitCall
4523 /// should be using this interface.
4525 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4527 ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
4529 LocalTemporary [] temps = null;
4531 if (dup_args && top != 0)
4532 temps = new LocalTemporary [top];
4534 int argument_index = 0;
4536 for (int i = 0; i < top; i++){
4538 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4539 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4540 int params_args_count = arguments == null ?
4541 0 : arguments.Count - top + 1;
4543 // Fill not provided argument
4544 if (params_args_count <= 0) {
4545 ILGenerator ig = ec.ig;
4546 IntConstant.EmitInt (ig, 0);
4547 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
4552 // Special case if we are passing the same data as the
4553 // params argument, we do not need to recreate an array.
4555 a = (Argument) arguments [argument_index];
4556 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
4562 EmitParams (ec, arguments, i, params_args_count);
4563 argument_index += params_args_count;
4568 a = (Argument) arguments [argument_index++];
4571 ec.ig.Emit (OpCodes.Dup);
4572 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4577 if (this_arg != null)
4580 for (int i = 0; i < top; i ++) {
4581 temps [i].Emit (ec);
4582 temps [i].Release (ec);
4587 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4589 ParameterData pd = TypeManager.GetParameterData (mb);
4591 if (arguments == null)
4592 return new Type [0];
4594 Argument a = (Argument) arguments [pd.Count - 1];
4595 Arglist list = (Arglist) a.Expr;
4597 return list.ArgumentTypes;
4601 /// This checks the ConditionalAttribute on the method
4603 static bool IsMethodExcluded (MethodBase method)
4605 if (method.IsConstructor)
4608 IMethodData md = TypeManager.GetMethod (method);
4610 return md.IsExcluded ();
4612 // For some methods (generated by delegate class) GetMethod returns null
4613 // because they are not included in builder_to_method table
4614 if (method.DeclaringType is TypeBuilder)
4617 return AttributeTester.IsConditionalMethodExcluded (method);
4621 /// is_base tells whether we want to force the use of the `call'
4622 /// opcode instead of using callvirt. Call is required to call
4623 /// a specific method, while callvirt will always use the most
4624 /// recent method in the vtable.
4626 /// is_static tells whether this is an invocation on a static method
4628 /// instance_expr is an expression that represents the instance
4629 /// it must be non-null if is_static is false.
4631 /// method is the method to invoke.
4633 /// Arguments is the list of arguments to pass to the method or constructor.
4635 public static void EmitCall (EmitContext ec, bool is_base,
4636 Expression instance_expr,
4637 MethodBase method, ArrayList Arguments, Location loc)
4639 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4642 // `dup_args' leaves an extra copy of the arguments on the stack
4643 // `omit_args' does not leave any arguments at all.
4644 // So, basically, you could make one call with `dup_args' set to true,
4645 // and then another with `omit_args' set to true, and the two calls
4646 // would have the same set of arguments. However, each argument would
4647 // only have been evaluated once.
4648 public static void EmitCall (EmitContext ec, bool is_base,
4649 Expression instance_expr,
4650 MethodBase method, ArrayList Arguments, Location loc,
4651 bool dup_args, bool omit_args)
4653 ILGenerator ig = ec.ig;
4654 bool struct_call = false;
4655 bool this_call = false;
4656 LocalTemporary this_arg = null;
4658 Type decl_type = method.DeclaringType;
4660 if (!RootContext.StdLib) {
4661 // Replace any calls to the system's System.Array type with calls to
4662 // the newly created one.
4663 if (method == TypeManager.system_int_array_get_length)
4664 method = TypeManager.int_array_get_length;
4665 else if (method == TypeManager.system_int_array_get_rank)
4666 method = TypeManager.int_array_get_rank;
4667 else if (method == TypeManager.system_object_array_clone)
4668 method = TypeManager.object_array_clone;
4669 else if (method == TypeManager.system_int_array_get_length_int)
4670 method = TypeManager.int_array_get_length_int;
4671 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4672 method = TypeManager.int_array_get_lower_bound_int;
4673 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4674 method = TypeManager.int_array_get_upper_bound_int;
4675 else if (method == TypeManager.system_void_array_copyto_array_int)
4676 method = TypeManager.void_array_copyto_array_int;
4679 if (!ec.IsInObsoleteScope) {
4681 // This checks ObsoleteAttribute on the method and on the declaring type
4683 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4685 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4687 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4689 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4693 if (IsMethodExcluded (method))
4696 bool is_static = method.IsStatic;
4698 if (instance_expr == EmptyExpression.Null) {
4699 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4703 this_call = instance_expr is This;
4704 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4708 // If this is ourselves, push "this"
4712 Type iexpr_type = instance_expr.Type;
4715 // Push the instance expression
4717 if (TypeManager.IsValueType (iexpr_type)) {
4719 // Special case: calls to a function declared in a
4720 // reference-type with a value-type argument need
4721 // to have their value boxed.
4722 if (decl_type.IsValueType ||
4723 TypeManager.IsGenericParameter (iexpr_type)) {
4725 // If the expression implements IMemoryLocation, then
4726 // we can optimize and use AddressOf on the
4729 // If not we have to use some temporary storage for
4731 if (instance_expr is IMemoryLocation) {
4732 ((IMemoryLocation)instance_expr).
4733 AddressOf (ec, AddressOp.LoadStore);
4735 LocalTemporary temp = new LocalTemporary (iexpr_type);
4736 instance_expr.Emit (ec);
4738 temp.AddressOf (ec, AddressOp.Load);
4741 // avoid the overhead of doing this all the time.
4743 t = TypeManager.GetReferenceType (iexpr_type);
4745 instance_expr.Emit (ec);
4746 ig.Emit (OpCodes.Box, instance_expr.Type);
4747 t = TypeManager.object_type;
4750 instance_expr.Emit (ec);
4751 t = instance_expr.Type;
4755 ig.Emit (OpCodes.Dup);
4756 if (Arguments != null && Arguments.Count != 0) {
4757 this_arg = new LocalTemporary (t);
4758 this_arg.Store (ec);
4765 EmitArguments (ec, method, Arguments, dup_args, this_arg);
4768 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4769 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4773 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4774 call_op = OpCodes.Call;
4776 call_op = OpCodes.Callvirt;
4778 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4779 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4780 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4787 // and DoFoo is not virtual, you can omit the callvirt,
4788 // because you don't need the null checking behavior.
4790 if (method is MethodInfo)
4791 ig.Emit (call_op, (MethodInfo) method);
4793 ig.Emit (call_op, (ConstructorInfo) method);
4796 public override void Emit (EmitContext ec)
4798 mg.EmitCall (ec, Arguments);
4801 public override void EmitStatement (EmitContext ec)
4806 // Pop the return value if there is one
4808 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4809 ec.ig.Emit (OpCodes.Pop);
4812 protected override void CloneTo (CloneContext clonectx, Expression t)
4814 Invocation target = (Invocation) t;
4816 if (Arguments != null){
4817 target.Arguments = new ArrayList ();
4818 foreach (Argument a in Arguments)
4819 target.Arguments.Add (a.Clone (clonectx));
4822 expr = expr.Clone (clonectx);
4826 public class InvocationOrCast : ExpressionStatement
4829 Expression argument;
4831 public InvocationOrCast (Expression expr, Expression argument)
4834 this.argument = argument;
4835 this.loc = expr.Location;
4838 public override Expression DoResolve (EmitContext ec)
4841 // First try to resolve it as a cast.
4843 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4844 if ((te != null) && (te.eclass == ExprClass.Type)) {
4845 Cast cast = new Cast (te, argument, loc);
4846 return cast.Resolve (ec);
4850 // This can either be a type or a delegate invocation.
4851 // Let's just resolve it and see what we'll get.
4853 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4858 // Ok, so it's a Cast.
4860 if (expr.eclass == ExprClass.Type) {
4861 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4862 return cast.Resolve (ec);
4866 // It's a delegate invocation.
4868 if (!TypeManager.IsDelegateType (expr.Type)) {
4869 Error (149, "Method name expected");
4873 ArrayList args = new ArrayList ();
4874 args.Add (new Argument (argument, Argument.AType.Expression));
4875 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4876 return invocation.Resolve (ec);
4879 public override ExpressionStatement ResolveStatement (EmitContext ec)
4882 // First try to resolve it as a cast.
4884 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4885 if ((te != null) && (te.eclass == ExprClass.Type)) {
4886 Error_InvalidExpressionStatement ();
4891 // This can either be a type or a delegate invocation.
4892 // Let's just resolve it and see what we'll get.
4894 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4895 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4896 Error_InvalidExpressionStatement ();
4901 // It's a delegate invocation.
4903 if (!TypeManager.IsDelegateType (expr.Type)) {
4904 Error (149, "Method name expected");
4908 ArrayList args = new ArrayList ();
4909 args.Add (new Argument (argument, Argument.AType.Expression));
4910 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4911 return invocation.ResolveStatement (ec);
4914 public override void Emit (EmitContext ec)
4916 throw new Exception ("Cannot happen");
4919 public override void EmitStatement (EmitContext ec)
4921 throw new Exception ("Cannot happen");
4924 protected override void CloneTo (CloneContext clonectx, Expression t)
4926 InvocationOrCast target = (InvocationOrCast) t;
4928 target.expr = expr.Clone (clonectx);
4929 target.argument = argument.Clone (clonectx);
4934 // This class is used to "disable" the code generation for the
4935 // temporary variable when initializing value types.
4937 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4938 public void AddressOf (EmitContext ec, AddressOp Mode)
4945 /// Implements the new expression
4947 public class New : ExpressionStatement, IMemoryLocation {
4948 ArrayList Arguments;
4951 // During bootstrap, it contains the RequestedType,
4952 // but if `type' is not null, it *might* contain a NewDelegate
4953 // (because of field multi-initialization)
4955 public Expression RequestedType;
4957 MethodGroupExpr method;
4960 // If set, the new expression is for a value_target, and
4961 // we will not leave anything on the stack.
4963 Expression value_target;
4964 bool value_target_set = false;
4965 bool is_type_parameter = false;
4967 public New (Expression requested_type, ArrayList arguments, Location l)
4969 RequestedType = requested_type;
4970 Arguments = arguments;
4974 public bool SetValueTypeVariable (Expression value)
4976 value_target = value;
4977 value_target_set = true;
4978 if (!(value_target is IMemoryLocation)){
4979 Error_UnexpectedKind (null, "variable", loc);
4986 // This function is used to disable the following code sequence for
4987 // value type initialization:
4989 // AddressOf (temporary)
4993 // Instead the provide will have provided us with the address on the
4994 // stack to store the results.
4996 static Expression MyEmptyExpression;
4998 public void DisableTemporaryValueType ()
5000 if (MyEmptyExpression == null)
5001 MyEmptyExpression = new EmptyAddressOf ();
5004 // To enable this, look into:
5005 // test-34 and test-89 and self bootstrapping.
5007 // For instance, we can avoid a copy by using `newobj'
5008 // instead of Call + Push-temp on value types.
5009 // value_target = MyEmptyExpression;
5014 /// Converts complex core type syntax like 'new int ()' to simple constant
5016 public static Constant Constantify (Type t)
5018 if (t == TypeManager.int32_type)
5019 return new IntConstant (0, Location.Null);
5020 if (t == TypeManager.uint32_type)
5021 return new UIntConstant (0, Location.Null);
5022 if (t == TypeManager.int64_type)
5023 return new LongConstant (0, Location.Null);
5024 if (t == TypeManager.uint64_type)
5025 return new ULongConstant (0, Location.Null);
5026 if (t == TypeManager.float_type)
5027 return new FloatConstant (0, Location.Null);
5028 if (t == TypeManager.double_type)
5029 return new DoubleConstant (0, Location.Null);
5030 if (t == TypeManager.short_type)
5031 return new ShortConstant (0, Location.Null);
5032 if (t == TypeManager.ushort_type)
5033 return new UShortConstant (0, Location.Null);
5034 if (t == TypeManager.sbyte_type)
5035 return new SByteConstant (0, Location.Null);
5036 if (t == TypeManager.byte_type)
5037 return new ByteConstant (0, Location.Null);
5038 if (t == TypeManager.char_type)
5039 return new CharConstant ('\0', Location.Null);
5040 if (t == TypeManager.bool_type)
5041 return new BoolConstant (false, Location.Null);
5042 if (t == TypeManager.decimal_type)
5043 return new DecimalConstant (0, Location.Null);
5044 if (TypeManager.IsEnumType (t))
5045 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5051 // Checks whether the type is an interface that has the
5052 // [ComImport, CoClass] attributes and must be treated
5055 public Expression CheckComImport (EmitContext ec)
5057 if (!type.IsInterface)
5061 // Turn the call into:
5062 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5064 Type real_class = AttributeTester.GetCoClassAttribute (type);
5065 if (real_class == null)
5068 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5069 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5070 return cast.Resolve (ec);
5073 public override Expression DoResolve (EmitContext ec)
5076 // The New DoResolve might be called twice when initializing field
5077 // expressions (see EmitFieldInitializers, the call to
5078 // GetInitializerExpression will perform a resolve on the expression,
5079 // and later the assign will trigger another resolution
5081 // This leads to bugs (#37014)
5084 if (RequestedType is NewDelegate)
5085 return RequestedType;
5089 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5095 if (type == TypeManager.void_type) {
5096 Error_VoidInvalidInTheContext (loc);
5100 if (Arguments == null) {
5101 Expression c = Constantify (type);
5106 if (TypeManager.IsDelegateType (type)) {
5107 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5108 if (RequestedType != null)
5109 if (!(RequestedType is DelegateCreation))
5110 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5111 return RequestedType;
5115 if (type.IsGenericParameter) {
5116 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5118 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5119 Error (304, String.Format (
5120 "Cannot create an instance of the " +
5121 "variable type '{0}' because it " +
5122 "doesn't have the new() constraint",
5127 if ((Arguments != null) && (Arguments.Count != 0)) {
5128 Error (417, String.Format (
5129 "`{0}': cannot provide arguments " +
5130 "when creating an instance of a " +
5131 "variable type.", type));
5135 is_type_parameter = true;
5136 eclass = ExprClass.Value;
5141 if (type.IsAbstract && type.IsSealed) {
5142 Report.SymbolRelatedToPreviousError (type);
5143 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5147 if (type.IsInterface || type.IsAbstract){
5148 if (!TypeManager.IsGenericType (type)) {
5149 RequestedType = CheckComImport (ec);
5150 if (RequestedType != null)
5151 return RequestedType;
5154 Report.SymbolRelatedToPreviousError (type);
5155 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5159 bool is_struct = type.IsValueType;
5160 eclass = ExprClass.Value;
5163 // SRE returns a match for .ctor () on structs (the object constructor),
5164 // so we have to manually ignore it.
5166 if (is_struct && Arguments == null)
5169 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5170 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5171 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5176 method = ml as MethodGroupExpr;
5178 if (method == null) {
5179 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5183 if (Arguments != null){
5184 foreach (Argument a in Arguments){
5185 if (!a.Resolve (ec, loc))
5190 method = method.OverloadResolve (ec, Arguments, false, loc);
5191 if (method == null) {
5192 if (almostMatchedMembers.Count != 0)
5193 MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
5200 bool DoEmitTypeParameter (EmitContext ec)
5203 ILGenerator ig = ec.ig;
5204 // IMemoryLocation ml;
5206 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5207 new Type [] { type });
5209 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5210 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5211 ig.Emit (OpCodes.Call, ci);
5215 // Allow DoEmit() to be called multiple times.
5216 // We need to create a new LocalTemporary each time since
5217 // you can't share LocalBuilders among ILGeneators.
5218 LocalTemporary temp = new LocalTemporary (type);
5220 Label label_activator = ig.DefineLabel ();
5221 Label label_end = ig.DefineLabel ();
5223 temp.AddressOf (ec, AddressOp.Store);
5224 ig.Emit (OpCodes.Initobj, type);
5227 ig.Emit (OpCodes.Box, type);
5228 ig.Emit (OpCodes.Brfalse, label_activator);
5230 temp.AddressOf (ec, AddressOp.Store);
5231 ig.Emit (OpCodes.Initobj, type);
5233 ig.Emit (OpCodes.Br, label_end);
5235 ig.MarkLabel (label_activator);
5237 ig.Emit (OpCodes.Call, ci);
5238 ig.MarkLabel (label_end);
5241 throw new InternalErrorException ();
5246 // This DoEmit can be invoked in two contexts:
5247 // * As a mechanism that will leave a value on the stack (new object)
5248 // * As one that wont (init struct)
5250 // You can control whether a value is required on the stack by passing
5251 // need_value_on_stack. The code *might* leave a value on the stack
5252 // so it must be popped manually
5254 // If we are dealing with a ValueType, we have a few
5255 // situations to deal with:
5257 // * The target is a ValueType, and we have been provided
5258 // the instance (this is easy, we are being assigned).
5260 // * The target of New is being passed as an argument,
5261 // to a boxing operation or a function that takes a
5264 // In this case, we need to create a temporary variable
5265 // that is the argument of New.
5267 // Returns whether a value is left on the stack
5269 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5271 bool is_value_type = TypeManager.IsValueType (type);
5272 ILGenerator ig = ec.ig;
5277 // Allow DoEmit() to be called multiple times.
5278 // We need to create a new LocalTemporary each time since
5279 // you can't share LocalBuilders among ILGeneators.
5280 if (!value_target_set)
5281 value_target = new LocalTemporary (type);
5283 ml = (IMemoryLocation) value_target;
5284 ml.AddressOf (ec, AddressOp.Store);
5288 method.EmitArguments (ec, Arguments);
5292 ig.Emit (OpCodes.Initobj, type);
5294 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5295 if (need_value_on_stack){
5296 value_target.Emit (ec);
5301 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5306 public override void Emit (EmitContext ec)
5308 if (is_type_parameter)
5309 DoEmitTypeParameter (ec);
5314 public override void EmitStatement (EmitContext ec)
5316 bool value_on_stack;
5318 if (is_type_parameter)
5319 value_on_stack = DoEmitTypeParameter (ec);
5321 value_on_stack = DoEmit (ec, false);
5324 ec.ig.Emit (OpCodes.Pop);
5328 public void AddressOf (EmitContext ec, AddressOp Mode)
5330 if (is_type_parameter) {
5331 LocalTemporary temp = new LocalTemporary (type);
5332 DoEmitTypeParameter (ec);
5334 temp.AddressOf (ec, Mode);
5338 if (!type.IsValueType){
5340 // We throw an exception. So far, I believe we only need to support
5342 // foreach (int j in new StructType ())
5345 throw new Exception ("AddressOf should not be used for classes");
5348 if (!value_target_set)
5349 value_target = new LocalTemporary (type);
5350 IMemoryLocation ml = (IMemoryLocation) value_target;
5352 ml.AddressOf (ec, AddressOp.Store);
5353 if (method == null) {
5354 ec.ig.Emit (OpCodes.Initobj, type);
5356 method.EmitArguments (ec, Arguments);
5357 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5360 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5363 protected override void CloneTo (CloneContext clonectx, Expression t)
5365 New target = (New) t;
5367 target.RequestedType = RequestedType.Clone (clonectx);
5368 if (Arguments != null){
5369 target.Arguments = new ArrayList ();
5370 foreach (Argument a in Arguments){
5371 target.Arguments.Add (a.Clone (clonectx));
5378 /// 14.5.10.2: Represents an array creation expression.
5382 /// There are two possible scenarios here: one is an array creation
5383 /// expression that specifies the dimensions and optionally the
5384 /// initialization data and the other which does not need dimensions
5385 /// specified but where initialization data is mandatory.
5387 public class ArrayCreation : Expression {
5388 Expression requested_base_type;
5389 ArrayList initializers;
5392 // The list of Argument types.
5393 // This is used to construct the `newarray' or constructor signature
5395 protected ArrayList arguments;
5397 protected Type array_element_type;
5398 bool expect_initializers = false;
5399 int num_arguments = 0;
5400 protected int dimensions;
5401 protected readonly string rank;
5403 protected ArrayList array_data;
5407 // The number of constants in array initializers
5408 int const_initializers_count;
5409 bool only_constant_initializers;
5411 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5413 this.requested_base_type = requested_base_type;
5414 this.initializers = initializers;
5418 arguments = new ArrayList ();
5420 foreach (Expression e in exprs) {
5421 arguments.Add (new Argument (e, Argument.AType.Expression));
5426 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5428 this.requested_base_type = requested_base_type;
5429 this.initializers = initializers;
5433 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5435 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5437 //dimensions = tmp.Length - 1;
5438 expect_initializers = true;
5441 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5443 StringBuilder sb = new StringBuilder (rank);
5446 for (int i = 1; i < idx_count; i++)
5451 return new ComposedCast (base_type, sb.ToString (), loc);
5454 void Error_IncorrectArrayInitializer ()
5456 Error (178, "Invalid rank specifier: expected `,' or `]'");
5459 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5461 if (specified_dims) {
5462 Argument a = (Argument) arguments [idx];
5464 if (!a.Resolve (ec, loc))
5467 Constant c = a.Expr as Constant;
5469 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5473 Report.Error (150, a.Expr.Location, "A constant value is expected");
5477 int value = (int) c.GetValue ();
5479 if (value != probe.Count) {
5480 Error_IncorrectArrayInitializer ();
5484 bounds [idx] = value;
5487 int child_bounds = -1;
5488 only_constant_initializers = true;
5489 for (int i = 0; i < probe.Count; ++i) {
5490 object o = probe [i];
5491 if (o is ArrayList) {
5492 ArrayList sub_probe = o as ArrayList;
5493 int current_bounds = sub_probe.Count;
5495 if (child_bounds == -1)
5496 child_bounds = current_bounds;
5498 else if (child_bounds != current_bounds){
5499 Error_IncorrectArrayInitializer ();
5502 if (idx + 1 >= dimensions){
5503 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5507 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5511 if (child_bounds != -1){
5512 Error_IncorrectArrayInitializer ();
5516 Expression element = ResolveArrayElement (ec, (Expression) o);
5517 if (element == null)
5520 // Initializers with the default values can be ignored
5521 Constant c = element as Constant;
5523 if (c.IsDefaultInitializer (array_element_type)) {
5527 ++const_initializers_count;
5530 only_constant_initializers = false;
5533 array_data.Add (element);
5540 public void UpdateIndices ()
5543 for (ArrayList probe = initializers; probe != null;) {
5544 if (probe.Count > 0 && probe [0] is ArrayList) {
5545 Expression e = new IntConstant (probe.Count, Location.Null);
5546 arguments.Add (new Argument (e, Argument.AType.Expression));
5548 bounds [i++] = probe.Count;
5550 probe = (ArrayList) probe [0];
5553 Expression e = new IntConstant (probe.Count, Location.Null);
5554 arguments.Add (new Argument (e, Argument.AType.Expression));
5556 bounds [i++] = probe.Count;
5563 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5565 element = element.Resolve (ec);
5566 if (element == null)
5569 return Convert.ImplicitConversionRequired (
5570 ec, element, array_element_type, loc);
5573 protected bool ResolveInitializers (EmitContext ec)
5575 if (initializers == null) {
5576 return !expect_initializers;
5580 // We use this to store all the date values in the order in which we
5581 // will need to store them in the byte blob later
5583 array_data = new ArrayList ();
5584 bounds = new System.Collections.Specialized.HybridDictionary ();
5586 if (arguments != null)
5587 return CheckIndices (ec, initializers, 0, true);
5589 arguments = new ArrayList ();
5591 if (!CheckIndices (ec, initializers, 0, false))
5600 // Resolved the type of the array
5602 bool ResolveArrayType (EmitContext ec)
5604 if (requested_base_type == null) {
5605 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5609 StringBuilder array_qualifier = new StringBuilder (rank);
5612 // `In the first form allocates an array instace of the type that results
5613 // from deleting each of the individual expression from the expression list'
5615 if (num_arguments > 0) {
5616 array_qualifier.Append ("[");
5617 for (int i = num_arguments-1; i > 0; i--)
5618 array_qualifier.Append (",");
5619 array_qualifier.Append ("]");
5625 TypeExpr array_type_expr;
5626 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5627 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5628 if (array_type_expr == null)
5631 type = array_type_expr.Type;
5632 array_element_type = TypeManager.GetElementType (type);
5633 dimensions = type.GetArrayRank ();
5638 public override Expression DoResolve (EmitContext ec)
5643 if (!ResolveArrayType (ec))
5646 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5647 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5648 TypeManager.CSharpName (array_element_type));
5652 // First step is to validate the initializers and fill
5653 // in any missing bits
5655 if (!ResolveInitializers (ec))
5658 if (arguments.Count != dimensions) {
5659 Error_IncorrectArrayInitializer ();
5662 foreach (Argument a in arguments){
5663 if (!a.Resolve (ec, loc))
5666 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5667 if (real_arg == null)
5673 eclass = ExprClass.Value;
5677 MethodInfo GetArrayMethod (int arguments)
5679 ModuleBuilder mb = CodeGen.Module.Builder;
5681 Type[] arg_types = new Type[arguments];
5682 for (int i = 0; i < arguments; i++)
5683 arg_types[i] = TypeManager.int32_type;
5685 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5689 Report.Error (-6, "New invocation: Can not find a constructor for " +
5690 "this argument list");
5697 byte [] MakeByteBlob ()
5702 int count = array_data.Count;
5704 if (array_element_type.IsEnum)
5705 array_element_type = TypeManager.EnumToUnderlying (array_element_type);
5707 factor = GetTypeSize (array_element_type);
5709 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5711 data = new byte [(count * factor + 4) & ~3];
5714 for (int i = 0; i < count; ++i) {
5715 object v = array_data [i];
5717 if (v is EnumConstant)
5718 v = ((EnumConstant) v).Child;
5720 if (v is Constant && !(v is StringConstant))
5721 v = ((Constant) v).GetValue ();
5727 if (array_element_type == TypeManager.int64_type){
5728 if (!(v is Expression)){
5729 long val = (long) v;
5731 for (int j = 0; j < factor; ++j) {
5732 data [idx + j] = (byte) (val & 0xFF);
5736 } else if (array_element_type == TypeManager.uint64_type){
5737 if (!(v is Expression)){
5738 ulong val = (ulong) v;
5740 for (int j = 0; j < factor; ++j) {
5741 data [idx + j] = (byte) (val & 0xFF);
5745 } else if (array_element_type == TypeManager.float_type) {
5746 if (!(v is Expression)){
5747 element = BitConverter.GetBytes ((float) v);
5749 for (int j = 0; j < factor; ++j)
5750 data [idx + j] = element [j];
5751 if (!BitConverter.IsLittleEndian)
5752 System.Array.Reverse (data, idx, 4);
5754 } else if (array_element_type == TypeManager.double_type) {
5755 if (!(v is Expression)){
5756 element = BitConverter.GetBytes ((double) v);
5758 for (int j = 0; j < factor; ++j)
5759 data [idx + j] = element [j];
5761 // FIXME: Handle the ARM float format.
5762 if (!BitConverter.IsLittleEndian)
5763 System.Array.Reverse (data, idx, 8);
5765 } else if (array_element_type == TypeManager.char_type){
5766 if (!(v is Expression)){
5767 int val = (int) ((char) v);
5769 data [idx] = (byte) (val & 0xff);
5770 data [idx+1] = (byte) (val >> 8);
5772 } else if (array_element_type == TypeManager.short_type){
5773 if (!(v is Expression)){
5774 int val = (int) ((short) v);
5776 data [idx] = (byte) (val & 0xff);
5777 data [idx+1] = (byte) (val >> 8);
5779 } else if (array_element_type == TypeManager.ushort_type){
5780 if (!(v is Expression)){
5781 int val = (int) ((ushort) v);
5783 data [idx] = (byte) (val & 0xff);
5784 data [idx+1] = (byte) (val >> 8);
5786 } else if (array_element_type == TypeManager.int32_type) {
5787 if (!(v is Expression)){
5790 data [idx] = (byte) (val & 0xff);
5791 data [idx+1] = (byte) ((val >> 8) & 0xff);
5792 data [idx+2] = (byte) ((val >> 16) & 0xff);
5793 data [idx+3] = (byte) (val >> 24);
5795 } else if (array_element_type == TypeManager.uint32_type) {
5796 if (!(v is Expression)){
5797 uint val = (uint) v;
5799 data [idx] = (byte) (val & 0xff);
5800 data [idx+1] = (byte) ((val >> 8) & 0xff);
5801 data [idx+2] = (byte) ((val >> 16) & 0xff);
5802 data [idx+3] = (byte) (val >> 24);
5804 } else if (array_element_type == TypeManager.sbyte_type) {
5805 if (!(v is Expression)){
5806 sbyte val = (sbyte) v;
5807 data [idx] = (byte) val;
5809 } else if (array_element_type == TypeManager.byte_type) {
5810 if (!(v is Expression)){
5811 byte val = (byte) v;
5812 data [idx] = (byte) val;
5814 } else if (array_element_type == TypeManager.bool_type) {
5815 if (!(v is Expression)){
5816 bool val = (bool) v;
5817 data [idx] = (byte) (val ? 1 : 0);
5819 } else if (array_element_type == TypeManager.decimal_type){
5820 if (!(v is Expression)){
5821 int [] bits = Decimal.GetBits ((decimal) v);
5824 // FIXME: For some reason, this doesn't work on the MS runtime.
5825 int [] nbits = new int [4];
5826 nbits [0] = bits [3];
5827 nbits [1] = bits [2];
5828 nbits [2] = bits [0];
5829 nbits [3] = bits [1];
5831 for (int j = 0; j < 4; j++){
5832 data [p++] = (byte) (nbits [j] & 0xff);
5833 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5834 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5835 data [p++] = (byte) (nbits [j] >> 24);
5839 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5848 // Emits the initializers for the array
5850 void EmitStaticInitializers (EmitContext ec)
5853 // First, the static data
5856 ILGenerator ig = ec.ig;
5858 byte [] data = MakeByteBlob ();
5860 fb = RootContext.MakeStaticData (data);
5862 ig.Emit (OpCodes.Dup);
5863 ig.Emit (OpCodes.Ldtoken, fb);
5864 ig.Emit (OpCodes.Call,
5865 TypeManager.void_initializearray_array_fieldhandle);
5869 // Emits pieces of the array that can not be computed at compile
5870 // time (variables and string locations).
5872 // This always expect the top value on the stack to be the array
5874 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5876 ILGenerator ig = ec.ig;
5877 int dims = bounds.Count;
5878 int [] current_pos = new int [dims];
5880 MethodInfo set = null;
5883 Type [] args = new Type [dims + 1];
5885 for (int j = 0; j < dims; j++)
5886 args [j] = TypeManager.int32_type;
5887 args [dims] = array_element_type;
5889 set = CodeGen.Module.Builder.GetArrayMethod (
5891 CallingConventions.HasThis | CallingConventions.Standard,
5892 TypeManager.void_type, args);
5895 for (int i = 0; i < array_data.Count; i++){
5897 Expression e = (Expression)array_data [i];
5899 // Constant can be initialized via StaticInitializer
5900 if (e != null && !(!emitConstants && e is Constant)) {
5901 Type etype = e.Type;
5903 ig.Emit (OpCodes.Dup);
5905 for (int idx = 0; idx < dims; idx++)
5906 IntConstant.EmitInt (ig, current_pos [idx]);
5909 // If we are dealing with a struct, get the
5910 // address of it, so we can store it.
5912 if ((dims == 1) && etype.IsValueType &&
5913 (!TypeManager.IsBuiltinOrEnum (etype) ||
5914 etype == TypeManager.decimal_type)) {
5919 // Let new know that we are providing
5920 // the address where to store the results
5922 n.DisableTemporaryValueType ();
5925 ig.Emit (OpCodes.Ldelema, etype);
5931 bool is_stobj, has_type_arg;
5932 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5934 ig.Emit (OpCodes.Stobj, etype);
5935 else if (has_type_arg)
5936 ig.Emit (op, etype);
5940 ig.Emit (OpCodes.Call, set);
5947 for (int j = dims - 1; j >= 0; j--){
5949 if (current_pos [j] < (int) bounds [j])
5951 current_pos [j] = 0;
5956 void EmitArrayArguments (EmitContext ec)
5958 ILGenerator ig = ec.ig;
5960 foreach (Argument a in arguments) {
5961 Type atype = a.Type;
5964 if (atype == TypeManager.uint64_type)
5965 ig.Emit (OpCodes.Conv_Ovf_U4);
5966 else if (atype == TypeManager.int64_type)
5967 ig.Emit (OpCodes.Conv_Ovf_I4);
5971 public override void Emit (EmitContext ec)
5973 ILGenerator ig = ec.ig;
5975 EmitArrayArguments (ec);
5976 if (arguments.Count == 1)
5977 ig.Emit (OpCodes.Newarr, array_element_type);
5979 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
5982 if (initializers == null)
5985 // Emit static initializer for arrays which have contain more than 4 items and
5986 // the static initializer will initialize at least 25% of array values.
5987 // NOTE: const_initializers_count does not contain default constant values.
5988 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
5989 TypeManager.IsPrimitiveType (array_element_type)) {
5990 EmitStaticInitializers (ec);
5992 if (!only_constant_initializers)
5993 EmitDynamicInitializers (ec, false);
5995 EmitDynamicInitializers (ec, true);
5999 public override bool GetAttributableValue (Type valueType, out object value)
6001 if (arguments.Count != 1) {
6002 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6003 return base.GetAttributableValue (null, out value);
6006 if (array_data == null) {
6007 Constant c = (Constant)((Argument)arguments [0]).Expr;
6008 if (c.IsDefaultValue) {
6009 value = Array.CreateInstance (array_element_type, 0);
6012 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6013 return base.GetAttributableValue (null, out value);
6016 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6017 object element_value;
6018 for (int i = 0; i < ret.Length; ++i)
6020 Expression e = (Expression)array_data [i];
6022 // Is null when an initializer is optimized (value == predefined value)
6026 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6030 ret.SetValue (element_value, i);
6036 protected override void CloneTo (CloneContext clonectx, Expression t)
6038 ArrayCreation target = (ArrayCreation) t;
6040 target.requested_base_type = requested_base_type.Clone (clonectx);
6041 target.arguments = new ArrayList ();
6042 foreach (Argument a in arguments)
6043 target.arguments.Add (a.Clone (clonectx));
6045 if (initializers != null){
6046 target.initializers = new ArrayList ();
6047 foreach (Expression initializer in initializers)
6048 target.initializers.Add (initializer.Clone (clonectx));
6054 // Represents an implicitly typed array epxression
6056 public class ImplicitlyTypedArrayCreation : ArrayCreation
6058 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6059 : base (null, rank, initializers, loc)
6061 if (rank.Length > 2) {
6062 while (rank [++dimensions] == ',');
6068 public override Expression DoResolve (EmitContext ec)
6073 if (!ResolveInitializers (ec))
6076 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6077 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6078 arguments.Count != dimensions) {
6079 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6084 // At this point we found common base type for all initializer elements
6085 // but we have to be sure that all static initializer elements are of
6088 UnifyInitializerElement (ec);
6090 type = TypeManager.GetConstructedType (array_element_type, rank);
6091 eclass = ExprClass.Value;
6096 // Converts static initializer only
6098 void UnifyInitializerElement (EmitContext ec)
6100 for (int i = 0; i < array_data.Count; ++i) {
6101 Expression e = (Expression)array_data[i];
6103 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6107 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6109 element = element.Resolve (ec);
6110 if (element == null)
6113 if (array_element_type == null) {
6114 array_element_type = element.Type;
6118 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6122 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6123 array_element_type = element.Type;
6127 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6132 public sealed class CompilerGeneratedThis : This
6134 public static This Instance = new CompilerGeneratedThis ();
6136 private CompilerGeneratedThis ()
6137 : base (Location.Null)
6141 public override Expression DoResolve (EmitContext ec)
6143 eclass = ExprClass.Variable;
6144 type = ec.ContainerType;
6145 variable = new SimpleThis (type);
6151 /// Represents the `this' construct
6154 public class This : VariableReference, IVariable
6157 VariableInfo variable_info;
6158 protected Variable variable;
6161 public This (Block block, Location loc)
6167 public This (Location loc)
6172 public VariableInfo VariableInfo {
6173 get { return variable_info; }
6176 public bool VerifyFixed ()
6178 return !TypeManager.IsValueType (Type);
6181 public override bool IsRef {
6182 get { return is_struct; }
6185 public override Variable Variable {
6186 get { return variable; }
6189 public bool ResolveBase (EmitContext ec)
6191 eclass = ExprClass.Variable;
6193 if (ec.TypeContainer.CurrentType != null)
6194 type = ec.TypeContainer.CurrentType;
6196 type = ec.ContainerType;
6198 is_struct = ec.TypeContainer is Struct;
6201 Error (26, "Keyword `this' is not valid in a static property, " +
6202 "static method, or static field initializer");
6206 if (block != null) {
6207 if (block.Toplevel.ThisVariable != null)
6208 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6210 AnonymousContainer am = ec.CurrentAnonymousMethod;
6211 if (is_struct && (am != null) && !am.IsIterator) {
6212 Report.Error (1673, loc, "Anonymous methods inside structs " +
6213 "cannot access instance members of `this'. " +
6214 "Consider copying `this' to a local variable " +
6215 "outside the anonymous method and using the " +
6220 RootScopeInfo host = block.Toplevel.RootScope;
6221 if ((host != null) && !ec.IsConstructor &&
6222 (!is_struct || host.IsIterator)) {
6223 variable = host.CaptureThis ();
6224 type = variable.Type;
6229 if (variable == null)
6230 variable = new SimpleThis (type);
6236 // Called from Invocation to check if the invocation is correct
6238 public bool CheckThisUsage (EmitContext ec)
6240 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6241 !variable_info.IsAssigned (ec)) {
6242 Error (188, "The `this' object cannot be used before all of its " +
6243 "fields are assigned to");
6244 variable_info.SetAssigned (ec);
6251 public override Expression DoResolve (EmitContext ec)
6253 if (!ResolveBase (ec))
6257 if (ec.IsFieldInitializer) {
6258 Error (27, "Keyword `this' is not available in the current context");
6265 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6267 if (!ResolveBase (ec))
6270 if (variable_info != null)
6271 variable_info.SetAssigned (ec);
6273 if (ec.TypeContainer is Class){
6274 Error (1604, "Cannot assign to 'this' because it is read-only");
6280 public override int GetHashCode()
6282 return block.GetHashCode ();
6285 public override bool Equals (object obj)
6287 This t = obj as This;
6291 return block == t.block;
6294 protected class SimpleThis : Variable
6298 public SimpleThis (Type type)
6303 public override Type Type {
6304 get { return type; }
6307 public override bool HasInstance {
6308 get { return false; }
6311 public override bool NeedsTemporary {
6312 get { return false; }
6315 public override void EmitInstance (EmitContext ec)
6320 public override void Emit (EmitContext ec)
6322 ec.ig.Emit (OpCodes.Ldarg_0);
6325 public override void EmitAssign (EmitContext ec)
6327 throw new InvalidOperationException ();
6330 public override void EmitAddressOf (EmitContext ec)
6332 ec.ig.Emit (OpCodes.Ldarg_0);
6336 protected override void CloneTo (CloneContext clonectx, Expression t)
6338 This target = (This) t;
6340 target.block = clonectx.LookupBlock (block);
6345 /// Represents the `__arglist' construct
6347 public class ArglistAccess : Expression
6349 public ArglistAccess (Location loc)
6354 public override Expression DoResolve (EmitContext ec)
6356 eclass = ExprClass.Variable;
6357 type = TypeManager.runtime_argument_handle_type;
6359 if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6361 Error (190, "The __arglist construct is valid only within " +
6362 "a variable argument method");
6369 public override void Emit (EmitContext ec)
6371 ec.ig.Emit (OpCodes.Arglist);
6374 protected override void CloneTo (CloneContext clonectx, Expression target)
6381 /// Represents the `__arglist (....)' construct
6383 public class Arglist : Expression
6385 public Argument[] Arguments;
6387 public Arglist (Location loc)
6388 : this (Argument.Empty, loc)
6392 public Arglist (Argument[] args, Location l)
6398 public Type[] ArgumentTypes {
6400 Type[] retval = new Type [Arguments.Length];
6401 for (int i = 0; i < Arguments.Length; i++)
6402 retval [i] = Arguments [i].Type;
6407 public override Expression DoResolve (EmitContext ec)
6409 eclass = ExprClass.Variable;
6410 type = TypeManager.runtime_argument_handle_type;
6412 foreach (Argument arg in Arguments) {
6413 if (!arg.Resolve (ec, loc))
6420 public override void Emit (EmitContext ec)
6422 foreach (Argument arg in Arguments)
6426 protected override void CloneTo (CloneContext clonectx, Expression t)
6428 Arglist target = (Arglist) t;
6430 target.Arguments = new Argument [Arguments.Length];
6431 for (int i = 0; i < Arguments.Length; i++)
6432 target.Arguments [i] = Arguments [i].Clone (clonectx);
6437 // This produces the value that renders an instance, used by the iterators code
6439 public class ProxyInstance : Expression, IMemoryLocation {
6440 public override Expression DoResolve (EmitContext ec)
6442 eclass = ExprClass.Variable;
6443 type = ec.ContainerType;
6447 public override void Emit (EmitContext ec)
6449 ec.ig.Emit (OpCodes.Ldarg_0);
6453 public void AddressOf (EmitContext ec, AddressOp mode)
6455 ec.ig.Emit (OpCodes.Ldarg_0);
6460 /// Implements the typeof operator
6462 public class TypeOf : Expression {
6463 Expression QueriedType;
6464 protected Type typearg;
6466 public TypeOf (Expression queried_type, Location l)
6468 QueriedType = queried_type;
6472 public override Expression DoResolve (EmitContext ec)
6474 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6478 typearg = texpr.Type;
6480 if (typearg == TypeManager.void_type) {
6481 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6485 if (typearg.IsPointer && !ec.InUnsafe){
6490 type = TypeManager.type_type;
6491 // Even though what is returned is a type object, it's treated as a value by the compiler.
6492 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6493 eclass = ExprClass.Value;
6497 public override void Emit (EmitContext ec)
6499 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6500 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6503 public override bool GetAttributableValue (Type valueType, out object value)
6505 if (TypeManager.ContainsGenericParameters (typearg)) {
6506 Report.SymbolRelatedToPreviousError(typearg);
6507 Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters",
6508 TypeManager.CSharpName(typearg));
6513 if (valueType == TypeManager.object_type) {
6514 value = (object)typearg;
6521 public Type TypeArgument
6529 protected override void CloneTo (CloneContext clonectx, Expression t)
6531 TypeOf target = (TypeOf) t;
6533 target.QueriedType = QueriedType.Clone (clonectx);
6538 /// Implements the `typeof (void)' operator
6540 public class TypeOfVoid : TypeOf {
6541 public TypeOfVoid (Location l) : base (null, l)
6546 public override Expression DoResolve (EmitContext ec)
6548 type = TypeManager.type_type;
6549 typearg = TypeManager.void_type;
6550 // See description in TypeOf.
6551 eclass = ExprClass.Value;
6557 /// Implements the sizeof expression
6559 public class SizeOf : Expression {
6560 public Expression QueriedType;
6563 public SizeOf (Expression queried_type, Location l)
6565 this.QueriedType = queried_type;
6569 public override Expression DoResolve (EmitContext ec)
6571 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6576 if (texpr is TypeParameterExpr){
6577 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6582 type_queried = texpr.Type;
6583 if (type_queried.IsEnum)
6584 type_queried = TypeManager.EnumToUnderlying (type_queried);
6586 if (type_queried == TypeManager.void_type) {
6587 Expression.Error_VoidInvalidInTheContext (loc);
6591 int size_of = GetTypeSize (type_queried);
6593 return new IntConstant (size_of, loc);
6597 Report.Error (233, loc, "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
6598 TypeManager.CSharpName (type_queried));
6602 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6606 type = TypeManager.int32_type;
6607 eclass = ExprClass.Value;
6611 public override void Emit (EmitContext ec)
6613 int size = GetTypeSize (type_queried);
6616 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6618 IntConstant.EmitInt (ec.ig, size);
6621 protected override void CloneTo (CloneContext clonectx, Expression t)
6623 SizeOf target = (SizeOf) t;
6625 target.QueriedType = QueriedType.Clone (clonectx);
6630 /// Implements the qualified-alias-member (::) expression.
6632 public class QualifiedAliasMember : Expression
6634 string alias, identifier;
6636 public QualifiedAliasMember (string alias, string identifier, Location l)
6638 if (RootContext.Version == LanguageVersion.ISO_1)
6639 Report.FeatureIsNotISO1 (l, "namespace alias qualifier");
6642 this.identifier = identifier;
6646 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6648 if (alias == "global")
6649 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6651 int errors = Report.Errors;
6652 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6654 if (errors == Report.Errors)
6655 Report.Error (432, loc, "Alias `{0}' not found", alias);
6658 if (fne.eclass != ExprClass.Namespace) {
6660 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6663 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6666 public override Expression DoResolve (EmitContext ec)
6668 FullNamedExpression fne;
6669 if (alias == "global") {
6670 fne = RootNamespace.Global;
6672 int errors = Report.Errors;
6673 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6675 if (errors == Report.Errors)
6676 Report.Error (432, loc, "Alias `{0}' not found", alias);
6681 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6685 if (!(retval is FullNamedExpression)) {
6686 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6690 // We defer this check till the end to match the behaviour of CSC
6691 if (fne.eclass != ExprClass.Namespace) {
6692 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6698 public override void Emit (EmitContext ec)
6700 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6704 public override string ToString ()
6706 return alias + "::" + identifier;
6709 public override string GetSignatureForError ()
6714 protected override void CloneTo (CloneContext clonectx, Expression t)
6721 /// Implements the member access expression
6723 public class MemberAccess : Expression {
6724 public readonly string Identifier;
6727 public MemberAccess (Expression expr, string id)
6728 : this (expr, id, expr.Location)
6732 public MemberAccess (Expression expr, string identifier, Location loc)
6735 Identifier = identifier;
6739 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6740 : this (expr, identifier, loc)
6747 protected string LookupIdentifier {
6748 get { return MemberName.MakeName (Identifier, args); }
6751 // TODO: this method has very poor performace for Enum fields and
6752 // probably for other constants as well
6753 Expression DoResolve (EmitContext ec, Expression right_side)
6756 throw new Exception ();
6759 // Resolve the expression with flow analysis turned off, we'll do the definite
6760 // assignment checks later. This is because we don't know yet what the expression
6761 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6762 // definite assignment check on the actual field and not on the whole struct.
6765 SimpleName original = expr as SimpleName;
6766 Expression expr_resolved = expr.Resolve (ec,
6767 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6768 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6770 if (expr_resolved == null)
6773 if (expr_resolved is Namespace) {
6774 Namespace ns = (Namespace) expr_resolved;
6775 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6777 if ((retval != null) && (args != null))
6778 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6782 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6786 Type expr_type = expr_resolved.Type;
6787 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6788 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6791 if (expr_type == TypeManager.anonymous_method_type){
6792 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6796 Constant c = expr_resolved as Constant;
6797 if (c != null && c.GetValue () == null) {
6798 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6799 "System.NullReferenceException");
6802 Expression member_lookup;
6803 member_lookup = MemberLookup (
6804 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6806 if ((member_lookup == null) && (args != null)) {
6807 member_lookup = MemberLookup (
6808 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6811 if (member_lookup == null) {
6812 ExtensionMethodGroupExpr ex_method_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
6813 if (ex_method_lookup != null) {
6814 ex_method_lookup.ExtensionExpression = expr_resolved;
6815 return ex_method_lookup.DoResolve (ec);
6818 MemberLookupFailed (
6819 ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
6823 TypeExpr texpr = member_lookup as TypeExpr;
6824 if (texpr != null) {
6825 if (!(expr_resolved is TypeExpr) &&
6826 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6827 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6828 Identifier, member_lookup.GetSignatureForError ());
6832 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6833 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6834 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6839 ConstructedType ct = expr_resolved as ConstructedType;
6842 // When looking up a nested type in a generic instance
6843 // via reflection, we always get a generic type definition
6844 // and not a generic instance - so we have to do this here.
6846 // See gtest-172-lib.cs and gtest-172.cs for an example.
6848 ct = new ConstructedType (
6849 member_lookup.Type, ct.TypeArguments, loc);
6851 return ct.ResolveAsTypeStep (ec, false);
6854 return member_lookup;
6857 MemberExpr me = (MemberExpr) member_lookup;
6858 member_lookup = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
6859 if (member_lookup == null)
6863 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6865 throw new InternalErrorException ();
6867 return mg.ResolveGeneric (ec, args);
6870 if (original != null && !TypeManager.IsValueType (expr_type)) {
6871 me = member_lookup as MemberExpr;
6872 if (me != null && me.IsInstance) {
6873 LocalVariableReference var = expr_resolved as LocalVariableReference;
6874 if (var != null && !var.VerifyAssigned (ec))
6879 // The following DoResolve/DoResolveLValue will do the definite assignment
6882 if (right_side != null)
6883 return member_lookup.DoResolveLValue (ec, right_side);
6885 return member_lookup.DoResolve (ec);
6888 public override Expression DoResolve (EmitContext ec)
6890 return DoResolve (ec, null);
6893 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6895 return DoResolve (ec, right_side);
6898 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6900 return ResolveNamespaceOrType (ec, silent);
6903 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6905 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6907 if (new_expr == null)
6910 if (new_expr is Namespace) {
6911 Namespace ns = (Namespace) new_expr;
6912 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6914 if ((retval != null) && (args != null))
6915 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6917 if (!silent && retval == null)
6918 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6922 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6923 if (tnew_expr == null)
6926 Type expr_type = tnew_expr.Type;
6928 if (expr_type.IsPointer){
6929 Error (23, "The `.' operator can not be applied to pointer operands (" +
6930 TypeManager.CSharpName (expr_type) + ")");
6934 Expression member_lookup = MemberLookup (
6935 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6936 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6937 if (member_lookup == null) {
6941 member_lookup = MemberLookup(
6942 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6943 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6945 if (member_lookup == null) {
6946 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6947 Identifier, new_expr.GetSignatureForError ());
6949 // TODO: Report.SymbolRelatedToPreviousError
6950 member_lookup.Error_UnexpectedKind (null, "type", loc);
6955 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6960 TypeArguments the_args = args;
6961 if (TypeManager.HasGenericArguments (expr_type)) {
6962 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
6964 TypeArguments new_args = new TypeArguments (loc);
6965 foreach (Type decl in decl_args)
6966 new_args.Add (new TypeExpression (decl, loc));
6969 new_args.Add (args);
6971 the_args = new_args;
6974 if (the_args != null) {
6975 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
6976 return ctype.ResolveAsTypeStep (rc, false);
6983 public override void Emit (EmitContext ec)
6985 throw new Exception ("Should not happen");
6988 public override string ToString ()
6990 return expr + "." + MemberName.MakeName (Identifier, args);
6993 public override string GetSignatureForError ()
6995 return expr.GetSignatureForError () + "." + Identifier;
6998 protected override void CloneTo (CloneContext clonectx, Expression t)
7000 MemberAccess target = (MemberAccess) t;
7002 target.expr = expr.Clone (clonectx);
7007 /// Implements checked expressions
7009 public class CheckedExpr : Expression {
7011 public Expression Expr;
7013 public CheckedExpr (Expression e, Location l)
7019 public override Expression DoResolve (EmitContext ec)
7021 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7022 Expr = Expr.Resolve (ec);
7027 if (Expr is Constant)
7030 eclass = Expr.eclass;
7035 public override void Emit (EmitContext ec)
7037 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7041 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7043 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7044 Expr.EmitBranchable (ec, target, onTrue);
7047 protected override void CloneTo (CloneContext clonectx, Expression t)
7049 CheckedExpr target = (CheckedExpr) t;
7051 target.Expr = Expr.Clone (clonectx);
7056 /// Implements the unchecked expression
7058 public class UnCheckedExpr : Expression {
7060 public Expression Expr;
7062 public UnCheckedExpr (Expression e, Location l)
7068 public override Expression DoResolve (EmitContext ec)
7070 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7071 Expr = Expr.Resolve (ec);
7076 if (Expr is Constant)
7079 eclass = Expr.eclass;
7084 public override void Emit (EmitContext ec)
7086 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7090 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7092 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7093 Expr.EmitBranchable (ec, target, onTrue);
7096 protected override void CloneTo (CloneContext clonectx, Expression t)
7098 UnCheckedExpr target = (UnCheckedExpr) t;
7100 target.Expr = Expr.Clone (clonectx);
7105 /// An Element Access expression.
7107 /// During semantic analysis these are transformed into
7108 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7110 public class ElementAccess : Expression {
7111 public ArrayList Arguments;
7112 public Expression Expr;
7114 public ElementAccess (Expression e, ArrayList e_list)
7123 Arguments = new ArrayList ();
7124 foreach (Expression tmp in e_list)
7125 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7129 bool CommonResolve (EmitContext ec)
7131 Expr = Expr.Resolve (ec);
7136 if (Arguments == null)
7139 foreach (Argument a in Arguments){
7140 if (!a.Resolve (ec, loc))
7147 Expression MakePointerAccess (EmitContext ec, Type t)
7149 if (t == TypeManager.void_ptr_type){
7150 Error (242, "The array index operation is not valid on void pointers");
7153 if (Arguments.Count != 1){
7154 Error (196, "A pointer must be indexed by only one value");
7159 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7162 return new Indirection (p, loc).Resolve (ec);
7165 public override Expression DoResolve (EmitContext ec)
7167 if (!CommonResolve (ec))
7171 // We perform some simple tests, and then to "split" the emit and store
7172 // code we create an instance of a different class, and return that.
7174 // I am experimenting with this pattern.
7178 if (t == TypeManager.array_type){
7179 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7184 return (new ArrayAccess (this, loc)).Resolve (ec);
7186 return MakePointerAccess (ec, Expr.Type);
7188 FieldExpr fe = Expr as FieldExpr;
7190 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7192 return MakePointerAccess (ec, ff.ElementType);
7195 return (new IndexerAccess (this, loc)).Resolve (ec);
7198 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7200 if (!CommonResolve (ec))
7205 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7208 return MakePointerAccess (ec, Expr.Type);
7210 FieldExpr fe = Expr as FieldExpr;
7212 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7214 if (!(fe.InstanceExpression is LocalVariableReference) &&
7215 !(fe.InstanceExpression is This)) {
7216 Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields");
7219 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
7220 Error (1666, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
7223 return MakePointerAccess (ec, ff.ElementType);
7226 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7229 public override void Emit (EmitContext ec)
7231 throw new Exception ("Should never be reached");
7234 protected override void CloneTo (CloneContext clonectx, Expression t)
7236 ElementAccess target = (ElementAccess) t;
7238 target.Expr = Expr.Clone (clonectx);
7239 target.Arguments = new ArrayList ();
7240 foreach (Argument a in Arguments)
7241 target.Arguments.Add (a.Clone (clonectx));
7246 /// Implements array access
7248 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7250 // Points to our "data" repository
7254 LocalTemporary temp;
7257 public ArrayAccess (ElementAccess ea_data, Location l)
7260 eclass = ExprClass.Variable;
7264 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7266 return DoResolve (ec);
7269 public override Expression DoResolve (EmitContext ec)
7272 ExprClass eclass = ea.Expr.eclass;
7274 // As long as the type is valid
7275 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7276 eclass == ExprClass.Value)) {
7277 ea.Expr.Error_UnexpectedKind ("variable or value");
7282 Type t = ea.Expr.Type;
7283 if (t.GetArrayRank () != ea.Arguments.Count){
7284 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7285 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7289 type = TypeManager.GetElementType (t);
7290 if (type.IsPointer && !ec.InUnsafe){
7291 UnsafeError (ea.Location);
7295 foreach (Argument a in ea.Arguments){
7296 Type argtype = a.Type;
7298 if (argtype == TypeManager.int32_type ||
7299 argtype == TypeManager.uint32_type ||
7300 argtype == TypeManager.int64_type ||
7301 argtype == TypeManager.uint64_type) {
7302 Constant c = a.Expr as Constant;
7303 if (c != null && c.IsNegative) {
7304 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7310 // Mhm. This is strage, because the Argument.Type is not the same as
7311 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7313 // Wonder if I will run into trouble for this.
7315 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7320 eclass = ExprClass.Variable;
7326 /// Emits the right opcode to load an object of Type `t'
7327 /// from an array of T
7329 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7331 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7332 ig.Emit (OpCodes.Ldelem_U1);
7333 else if (type == TypeManager.sbyte_type)
7334 ig.Emit (OpCodes.Ldelem_I1);
7335 else if (type == TypeManager.short_type)
7336 ig.Emit (OpCodes.Ldelem_I2);
7337 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7338 ig.Emit (OpCodes.Ldelem_U2);
7339 else if (type == TypeManager.int32_type)
7340 ig.Emit (OpCodes.Ldelem_I4);
7341 else if (type == TypeManager.uint32_type)
7342 ig.Emit (OpCodes.Ldelem_U4);
7343 else if (type == TypeManager.uint64_type)
7344 ig.Emit (OpCodes.Ldelem_I8);
7345 else if (type == TypeManager.int64_type)
7346 ig.Emit (OpCodes.Ldelem_I8);
7347 else if (type == TypeManager.float_type)
7348 ig.Emit (OpCodes.Ldelem_R4);
7349 else if (type == TypeManager.double_type)
7350 ig.Emit (OpCodes.Ldelem_R8);
7351 else if (type == TypeManager.intptr_type)
7352 ig.Emit (OpCodes.Ldelem_I);
7353 else if (TypeManager.IsEnumType (type)){
7354 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7355 } else if (type.IsValueType){
7356 ig.Emit (OpCodes.Ldelema, type);
7357 ig.Emit (OpCodes.Ldobj, type);
7359 } else if (type.IsGenericParameter) {
7360 ig.Emit (OpCodes.Ldelem, type);
7362 } else if (type.IsPointer)
7363 ig.Emit (OpCodes.Ldelem_I);
7365 ig.Emit (OpCodes.Ldelem_Ref);
7369 /// Returns the right opcode to store an object of Type `t'
7370 /// from an array of T.
7372 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7374 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7375 has_type_arg = false; is_stobj = false;
7376 t = TypeManager.TypeToCoreType (t);
7377 if (TypeManager.IsEnumType (t))
7378 t = TypeManager.EnumToUnderlying (t);
7379 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7380 t == TypeManager.bool_type)
7381 return OpCodes.Stelem_I1;
7382 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7383 t == TypeManager.char_type)
7384 return OpCodes.Stelem_I2;
7385 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7386 return OpCodes.Stelem_I4;
7387 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7388 return OpCodes.Stelem_I8;
7389 else if (t == TypeManager.float_type)
7390 return OpCodes.Stelem_R4;
7391 else if (t == TypeManager.double_type)
7392 return OpCodes.Stelem_R8;
7393 else if (t == TypeManager.intptr_type) {
7394 has_type_arg = true;
7396 return OpCodes.Stobj;
7397 } else if (t.IsValueType) {
7398 has_type_arg = true;
7400 return OpCodes.Stobj;
7402 } else if (t.IsGenericParameter) {
7403 has_type_arg = true;
7404 return OpCodes.Stelem;
7407 } else if (t.IsPointer)
7408 return OpCodes.Stelem_I;
7410 return OpCodes.Stelem_Ref;
7413 MethodInfo FetchGetMethod ()
7415 ModuleBuilder mb = CodeGen.Module.Builder;
7416 int arg_count = ea.Arguments.Count;
7417 Type [] args = new Type [arg_count];
7420 for (int i = 0; i < arg_count; i++){
7421 //args [i++] = a.Type;
7422 args [i] = TypeManager.int32_type;
7425 get = mb.GetArrayMethod (
7426 ea.Expr.Type, "Get",
7427 CallingConventions.HasThis |
7428 CallingConventions.Standard,
7434 MethodInfo FetchAddressMethod ()
7436 ModuleBuilder mb = CodeGen.Module.Builder;
7437 int arg_count = ea.Arguments.Count;
7438 Type [] args = new Type [arg_count];
7442 ret_type = TypeManager.GetReferenceType (type);
7444 for (int i = 0; i < arg_count; i++){
7445 //args [i++] = a.Type;
7446 args [i] = TypeManager.int32_type;
7449 address = mb.GetArrayMethod (
7450 ea.Expr.Type, "Address",
7451 CallingConventions.HasThis |
7452 CallingConventions.Standard,
7459 // Load the array arguments into the stack.
7461 // If we have been requested to cache the values (cached_locations array
7462 // initialized), then load the arguments the first time and store them
7463 // in locals. otherwise load from local variables.
7465 void LoadArrayAndArguments (EmitContext ec)
7467 ILGenerator ig = ec.ig;
7470 foreach (Argument a in ea.Arguments){
7471 Type argtype = a.Expr.Type;
7475 if (argtype == TypeManager.int64_type)
7476 ig.Emit (OpCodes.Conv_Ovf_I);
7477 else if (argtype == TypeManager.uint64_type)
7478 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7482 public void Emit (EmitContext ec, bool leave_copy)
7484 int rank = ea.Expr.Type.GetArrayRank ();
7485 ILGenerator ig = ec.ig;
7488 LoadArrayAndArguments (ec);
7491 EmitLoadOpcode (ig, type);
7495 method = FetchGetMethod ();
7496 ig.Emit (OpCodes.Call, method);
7499 LoadFromPtr (ec.ig, this.type);
7502 ec.ig.Emit (OpCodes.Dup);
7503 temp = new LocalTemporary (this.type);
7508 public override void Emit (EmitContext ec)
7513 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7515 int rank = ea.Expr.Type.GetArrayRank ();
7516 ILGenerator ig = ec.ig;
7517 Type t = source.Type;
7518 prepared = prepare_for_load;
7520 if (prepare_for_load) {
7521 AddressOf (ec, AddressOp.LoadStore);
7522 ec.ig.Emit (OpCodes.Dup);
7525 ec.ig.Emit (OpCodes.Dup);
7526 temp = new LocalTemporary (this.type);
7529 StoreFromPtr (ec.ig, t);
7539 LoadArrayAndArguments (ec);
7542 bool is_stobj, has_type_arg;
7543 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7545 // The stobj opcode used by value types will need
7546 // an address on the stack, not really an array/array
7550 ig.Emit (OpCodes.Ldelema, t);
7554 ec.ig.Emit (OpCodes.Dup);
7555 temp = new LocalTemporary (this.type);
7560 ig.Emit (OpCodes.Stobj, t);
7561 else if (has_type_arg)
7566 ModuleBuilder mb = CodeGen.Module.Builder;
7567 int arg_count = ea.Arguments.Count;
7568 Type [] args = new Type [arg_count + 1];
7573 ec.ig.Emit (OpCodes.Dup);
7574 temp = new LocalTemporary (this.type);
7578 for (int i = 0; i < arg_count; i++){
7579 //args [i++] = a.Type;
7580 args [i] = TypeManager.int32_type;
7583 args [arg_count] = type;
7585 set = mb.GetArrayMethod (
7586 ea.Expr.Type, "Set",
7587 CallingConventions.HasThis |
7588 CallingConventions.Standard,
7589 TypeManager.void_type, args);
7591 ig.Emit (OpCodes.Call, set);
7600 public void AddressOf (EmitContext ec, AddressOp mode)
7602 int rank = ea.Expr.Type.GetArrayRank ();
7603 ILGenerator ig = ec.ig;
7605 LoadArrayAndArguments (ec);
7608 ig.Emit (OpCodes.Ldelema, type);
7610 MethodInfo address = FetchAddressMethod ();
7611 ig.Emit (OpCodes.Call, address);
7615 public void EmitGetLength (EmitContext ec, int dim)
7617 int rank = ea.Expr.Type.GetArrayRank ();
7618 ILGenerator ig = ec.ig;
7622 ig.Emit (OpCodes.Ldlen);
7623 ig.Emit (OpCodes.Conv_I4);
7625 IntLiteral.EmitInt (ig, dim);
7626 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7632 // note that the ArrayList itself in mutable. We just can't assign to 'Properties' again.
7633 public readonly ArrayList Properties;
7634 static Indexers empty;
7636 public struct Indexer {
7637 public readonly PropertyInfo PropertyInfo;
7638 public readonly MethodInfo Getter, Setter;
7640 public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7642 this.PropertyInfo = property_info;
7650 empty = new Indexers (null);
7653 Indexers (ArrayList array)
7658 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
7663 foreach (PropertyInfo property in mi){
7664 MethodInfo get, set;
7666 get = property.GetGetMethod (true);
7667 set = property.GetSetMethod (true);
7668 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
7670 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
7672 if (get != null || set != null) {
7674 ix = new Indexers (new ArrayList ());
7675 ix.Properties.Add (new Indexer (property, get, set));
7680 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7682 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7684 return TypeManager.MemberLookup (
7685 caller_type, caller_type, lookup_type, MemberTypes.Property,
7686 BindingFlags.Public | BindingFlags.Instance |
7687 BindingFlags.DeclaredOnly, p_name, null);
7690 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7692 Indexers ix = empty;
7695 if (lookup_type.IsGenericParameter) {
7696 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7700 if (gc.HasClassConstraint)
7701 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7703 Type[] ifaces = gc.InterfaceConstraints;
7704 foreach (Type itype in ifaces)
7705 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7711 Type copy = lookup_type;
7712 while (copy != TypeManager.object_type && copy != null){
7713 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7714 copy = copy.BaseType;
7717 if (lookup_type.IsInterface) {
7718 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7719 if (ifaces != null) {
7720 foreach (Type itype in ifaces)
7721 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7730 /// Expressions that represent an indexer call.
7732 public class IndexerAccess : Expression, IAssignMethod {
7734 // Points to our "data" repository
7736 MethodInfo get, set;
7737 ArrayList set_arguments;
7738 bool is_base_indexer;
7740 protected Type indexer_type;
7741 protected Type current_type;
7742 protected Expression instance_expr;
7743 protected ArrayList arguments;
7745 public IndexerAccess (ElementAccess ea, Location loc)
7746 : this (ea.Expr, false, loc)
7748 this.arguments = ea.Arguments;
7751 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7754 this.instance_expr = instance_expr;
7755 this.is_base_indexer = is_base_indexer;
7756 this.eclass = ExprClass.Value;
7760 protected virtual bool CommonResolve (EmitContext ec)
7762 indexer_type = instance_expr.Type;
7763 current_type = ec.ContainerType;
7768 public override Expression DoResolve (EmitContext ec)
7770 if (!CommonResolve (ec))
7774 // Step 1: Query for all `Item' *properties*. Notice
7775 // that the actual methods are pointed from here.
7777 // This is a group of properties, piles of them.
7779 ArrayList AllGetters = null;
7781 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7782 if (ilist.Properties != null) {
7783 AllGetters = new ArrayList(ilist.Properties.Count);
7784 foreach (Indexers.Indexer ix in ilist.Properties) {
7785 if (ix.Getter != null)
7786 AllGetters.Add (ix.Getter);
7790 if (AllGetters == null) {
7791 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7792 TypeManager.CSharpName (indexer_type));
7796 if (AllGetters.Count == 0) {
7797 // FIXME: we cannot simply select first one as the error message is missleading when
7798 // multiple indexers exist
7799 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
7800 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7801 TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
7805 get = (MethodInfo)new MethodGroupExpr (AllGetters, loc).OverloadResolve (ec,
7806 arguments, false, loc);
7809 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7814 // Only base will allow this invocation to happen.
7816 if (get.IsAbstract && this is BaseIndexerAccess){
7817 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
7821 type = get.ReturnType;
7822 if (type.IsPointer && !ec.InUnsafe){
7827 instance_expr.CheckMarshalByRefAccess ();
7829 eclass = ExprClass.IndexerAccess;
7833 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7835 if (right_side == EmptyExpression.OutAccess) {
7836 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7837 GetSignatureForError ());
7841 // if the indexer returns a value type, and we try to set a field in it
7842 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7843 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7844 GetSignatureForError ());
7848 ArrayList AllSetters = new ArrayList();
7849 if (!CommonResolve (ec))
7852 bool found_any = false, found_any_setters = false;
7854 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7855 if (ilist.Properties != null) {
7857 foreach (Indexers.Indexer ix in ilist.Properties) {
7858 if (ix.Setter != null)
7859 AllSetters.Add (ix.Setter);
7862 if (AllSetters.Count > 0) {
7863 found_any_setters = true;
7864 set_arguments = (ArrayList) arguments.Clone ();
7865 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7866 set = (MethodInfo)(new MethodGroupExpr (AllSetters, loc)).OverloadResolve (
7868 set_arguments, false, loc);
7872 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7873 TypeManager.CSharpName (indexer_type));
7877 if (!found_any_setters) {
7878 Error (154, "indexer can not be used in this context, because " +
7879 "it lacks a `set' accessor");
7884 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7889 // Only base will allow this invocation to happen.
7891 if (set.IsAbstract && this is BaseIndexerAccess){
7892 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
7897 // Now look for the actual match in the list of indexers to set our "return" type
7899 type = TypeManager.void_type; // default value
7900 foreach (Indexers.Indexer ix in ilist.Properties){
7901 if (ix.Setter == set){
7902 type = ix.PropertyInfo.PropertyType;
7907 instance_expr.CheckMarshalByRefAccess ();
7909 eclass = ExprClass.IndexerAccess;
7913 bool prepared = false;
7914 LocalTemporary temp;
7916 public void Emit (EmitContext ec, bool leave_copy)
7918 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get, arguments, loc, prepared, false);
7920 ec.ig.Emit (OpCodes.Dup);
7921 temp = new LocalTemporary (Type);
7927 // source is ignored, because we already have a copy of it from the
7928 // LValue resolution and we have already constructed a pre-cached
7929 // version of the arguments (ea.set_arguments);
7931 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7933 prepared = prepare_for_load;
7934 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
7939 ec.ig.Emit (OpCodes.Dup);
7940 temp = new LocalTemporary (Type);
7943 } else if (leave_copy) {
7944 temp = new LocalTemporary (Type);
7950 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, set_arguments, loc, false, prepared);
7959 public override void Emit (EmitContext ec)
7964 public override string GetSignatureForError ()
7966 // FIXME: print the argument list of the indexer
7967 return instance_expr.GetSignatureForError () + ".this[...]";
7970 protected override void CloneTo (CloneContext clonectx, Expression t)
7972 IndexerAccess target = (IndexerAccess) t;
7974 if (arguments != null){
7975 target.arguments = new ArrayList ();
7976 foreach (Argument a in arguments)
7977 target.arguments.Add (a.Clone (clonectx));
7979 if (instance_expr != null)
7980 target.instance_expr = instance_expr.Clone (clonectx);
7985 /// The base operator for method names
7987 public class BaseAccess : Expression {
7988 public readonly string Identifier;
7991 public BaseAccess (string member, Location l)
7993 this.Identifier = member;
7997 public BaseAccess (string member, TypeArguments args, Location l)
8003 public override Expression DoResolve (EmitContext ec)
8005 Expression c = CommonResolve (ec);
8011 // MethodGroups use this opportunity to flag an error on lacking ()
8013 if (!(c is MethodGroupExpr))
8014 return c.Resolve (ec);
8018 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8020 Expression c = CommonResolve (ec);
8026 // MethodGroups use this opportunity to flag an error on lacking ()
8028 if (! (c is MethodGroupExpr))
8029 return c.DoResolveLValue (ec, right_side);
8034 Expression CommonResolve (EmitContext ec)
8036 Expression member_lookup;
8037 Type current_type = ec.ContainerType;
8038 Type base_type = current_type.BaseType;
8041 Error (1511, "Keyword `base' is not available in a static method");
8045 if (ec.IsFieldInitializer){
8046 Error (1512, "Keyword `base' is not available in the current context");
8050 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8051 AllMemberTypes, AllBindingFlags, loc);
8052 if (member_lookup == null) {
8053 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8060 left = new TypeExpression (base_type, loc);
8062 left = ec.GetThis (loc);
8064 MemberExpr me = (MemberExpr) member_lookup;
8066 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8068 if (e is PropertyExpr) {
8069 PropertyExpr pe = (PropertyExpr) e;
8074 MethodGroupExpr mg = e as MethodGroupExpr;
8080 return mg.ResolveGeneric (ec, args);
8082 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8090 public override void Emit (EmitContext ec)
8092 throw new Exception ("Should never be called");
8095 protected override void CloneTo (CloneContext clonectx, Expression t)
8097 BaseAccess target = (BaseAccess) t;
8099 target.args = args.Clone ();
8104 /// The base indexer operator
8106 public class BaseIndexerAccess : IndexerAccess {
8107 public BaseIndexerAccess (ArrayList args, Location loc)
8108 : base (null, true, loc)
8110 arguments = new ArrayList ();
8111 foreach (Expression tmp in args)
8112 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8115 protected override bool CommonResolve (EmitContext ec)
8117 instance_expr = ec.GetThis (loc);
8119 current_type = ec.ContainerType.BaseType;
8120 indexer_type = current_type;
8122 foreach (Argument a in arguments){
8123 if (!a.Resolve (ec, loc))
8132 /// This class exists solely to pass the Type around and to be a dummy
8133 /// that can be passed to the conversion functions (this is used by
8134 /// foreach implementation to typecast the object return value from
8135 /// get_Current into the proper type. All code has been generated and
8136 /// we only care about the side effect conversions to be performed
8138 /// This is also now used as a placeholder where a no-action expression
8139 /// is needed (the `New' class).
8141 public class EmptyExpression : Expression {
8142 public static readonly EmptyExpression Null = new EmptyExpression ();
8144 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8145 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8146 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8148 static EmptyExpression temp = new EmptyExpression ();
8149 public static EmptyExpression Grab ()
8151 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8156 public static void Release (EmptyExpression e)
8161 // TODO: should be protected
8162 public EmptyExpression ()
8164 type = TypeManager.object_type;
8165 eclass = ExprClass.Value;
8166 loc = Location.Null;
8169 public EmptyExpression (Type t)
8172 eclass = ExprClass.Value;
8173 loc = Location.Null;
8176 public override Expression DoResolve (EmitContext ec)
8181 public override void Emit (EmitContext ec)
8183 // nothing, as we only exist to not do anything.
8187 // This is just because we might want to reuse this bad boy
8188 // instead of creating gazillions of EmptyExpressions.
8189 // (CanImplicitConversion uses it)
8191 public void SetType (Type t)
8197 public class UserCast : Expression {
8201 public UserCast (MethodInfo method, Expression source, Location l)
8203 this.method = method;
8204 this.source = source;
8205 type = method.ReturnType;
8206 eclass = ExprClass.Value;
8210 public Expression Source {
8216 public override Expression DoResolve (EmitContext ec)
8219 // We are born fully resolved
8224 public override void Emit (EmitContext ec)
8226 ILGenerator ig = ec.ig;
8230 if (method is MethodInfo)
8231 ig.Emit (OpCodes.Call, (MethodInfo) method);
8233 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8239 // This class is used to "construct" the type during a typecast
8240 // operation. Since the Type.GetType class in .NET can parse
8241 // the type specification, we just use this to construct the type
8242 // one bit at a time.
8244 public class ComposedCast : TypeExpr {
8248 public ComposedCast (Expression left, string dim)
8249 : this (left, dim, left.Location)
8253 public ComposedCast (Expression left, string dim, Location l)
8261 public Expression RemoveNullable ()
8263 if (dim.EndsWith ("?")) {
8264 dim = dim.Substring (0, dim.Length - 1);
8273 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8275 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8279 Type ltype = lexpr.Type;
8280 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8281 Error_VoidInvalidInTheContext (loc);
8286 if ((dim.Length > 0) && (dim [0] == '?')) {
8287 TypeExpr nullable = new NullableType (left, loc);
8289 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8290 return nullable.ResolveAsTypeTerminal (ec, false);
8294 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8297 if (dim != "" && dim [0] == '[' &&
8298 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8299 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8304 type = TypeManager.GetConstructedType (ltype, dim);
8309 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8311 if (type.IsPointer && !ec.IsInUnsafeScope){
8316 eclass = ExprClass.Type;
8320 public override string Name {
8321 get { return left + dim; }
8324 public override string FullName {
8325 get { return type.FullName; }
8328 public override string GetSignatureForError ()
8330 return left.GetSignatureForError () + dim;
8333 protected override void CloneTo (CloneContext clonectx, Expression t)
8335 ComposedCast target = (ComposedCast) t;
8337 target.left = left.Clone (clonectx);
8341 public class FixedBufferPtr : Expression {
8344 public FixedBufferPtr (Expression array, Type array_type, Location l)
8349 type = TypeManager.GetPointerType (array_type);
8350 eclass = ExprClass.Value;
8353 public override void Emit(EmitContext ec)
8358 public override Expression DoResolve (EmitContext ec)
8361 // We are born fully resolved
8369 // This class is used to represent the address of an array, used
8370 // only by the Fixed statement, this generates "&a [0]" construct
8371 // for fixed (char *pa = a)
8373 public class ArrayPtr : FixedBufferPtr {
8376 public ArrayPtr (Expression array, Type array_type, Location l):
8377 base (array, array_type, l)
8379 this.array_type = array_type;
8382 public override void Emit (EmitContext ec)
8386 ILGenerator ig = ec.ig;
8387 IntLiteral.EmitInt (ig, 0);
8388 ig.Emit (OpCodes.Ldelema, array_type);
8393 // Used by the fixed statement
8395 public class StringPtr : Expression {
8398 public StringPtr (LocalBuilder b, Location l)
8401 eclass = ExprClass.Value;
8402 type = TypeManager.char_ptr_type;
8406 public override Expression DoResolve (EmitContext ec)
8408 // This should never be invoked, we are born in fully
8409 // initialized state.
8414 public override void Emit (EmitContext ec)
8416 ILGenerator ig = ec.ig;
8418 ig.Emit (OpCodes.Ldloc, b);
8419 ig.Emit (OpCodes.Conv_I);
8420 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8421 ig.Emit (OpCodes.Add);
8426 // Implements the `stackalloc' keyword
8428 public class StackAlloc : Expression {
8433 public StackAlloc (Expression type, Expression count, Location l)
8440 public override Expression DoResolve (EmitContext ec)
8442 count = count.Resolve (ec);
8446 if (count.Type != TypeManager.int32_type){
8447 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8452 Constant c = count as Constant;
8453 if (c != null && c.IsNegative) {
8454 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8458 if (ec.InCatch || ec.InFinally) {
8459 Error (255, "Cannot use stackalloc in finally or catch");
8463 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8469 if (!TypeManager.VerifyUnManaged (otype, loc))
8472 type = TypeManager.GetPointerType (otype);
8473 eclass = ExprClass.Value;
8478 public override void Emit (EmitContext ec)
8480 int size = GetTypeSize (otype);
8481 ILGenerator ig = ec.ig;
8484 ig.Emit (OpCodes.Sizeof, otype);
8486 IntConstant.EmitInt (ig, size);
8488 ig.Emit (OpCodes.Mul);
8489 ig.Emit (OpCodes.Localloc);
8492 protected override void CloneTo (CloneContext clonectx, Expression t)
8494 StackAlloc target = (StackAlloc) t;
8495 target.count = count.Clone (clonectx);
8496 target.t = t.Clone (clonectx);
8500 public interface IInitializable
8502 bool Initialize (EmitContext ec, Expression target);
8505 public class Initializer
8507 public readonly string Name;
8508 public readonly object Value;
8510 public Initializer (string name, Expression value)
8516 public Initializer (string name, IInitializable value)
8523 public class ObjectInitializer : IInitializable
8525 readonly ArrayList initializers;
8526 public ObjectInitializer (ArrayList initializers)
8528 this.initializers = initializers;
8531 public bool Initialize (EmitContext ec, Expression target)
8533 ArrayList initialized = new ArrayList (initializers.Count);
8534 for (int i = initializers.Count - 1; i >= 0; i--) {
8535 Initializer initializer = initializers[i] as Initializer;
8536 if (initialized.Contains (initializer.Name)) {
8537 //FIXME proper error
8538 Console.WriteLine ("Object member can only be initialized once");
8542 MemberAccess ma = new MemberAccess (target, initializer.Name);
8543 Expression expr = initializer.Value as Expression;
8544 // If it's an expresison, append the assign.
8546 Assign a = new Assign (ma, expr);
8547 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (a));
8549 // If it's another initializer (object or collection), initialize it.
8550 else if (!((IInitializable)initializer.Value).Initialize (ec, ma))
8553 initialized.Add (initializer.Name);
8559 public class CollectionInitializer : IInitializable
8561 readonly ArrayList items;
8562 public CollectionInitializer (ArrayList items)
8567 bool CheckCollection (EmitContext ec, Expression e)
8569 if (e == null || e.Type == null)
8571 bool is_ienumerable = false;
8572 foreach (Type t in TypeManager.GetInterfaces (e.Type))
8573 if (t == typeof (IEnumerable)) {
8574 is_ienumerable = true;
8578 if (!is_ienumerable)
8581 MethodGroupExpr mg = Expression.MemberLookup (
8582 ec.ContainerType, e.Type, "Add", MemberTypes.Method,
8583 Expression.AllBindingFlags, Location.Null) as MethodGroupExpr;
8588 foreach (MethodInfo mi in mg.Methods) {
8589 if (TypeManager.GetParameterData (mi).Count != 1)
8591 if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
8598 public bool Initialize (EmitContext ec, Expression target)
8600 if (!CheckCollection (ec, target.Resolve (ec))) {
8601 // FIXME throw proper error
8602 Console.WriteLine ("Error: This is not a collection");
8606 for (int i = items.Count - 1; i >= 0; i--) {
8607 MemberAccess ma = new MemberAccess (target, "Add");
8608 ArrayList array = new ArrayList ();
8609 array.Add (new Argument ((Expression)items[i]));
8610 Invocation invoke = new Invocation (ma, array);
8611 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (invoke));
8617 public class AnonymousTypeInitializer : IInitializable
8619 readonly ArrayList initializers;
8620 public AnonymousTypeInitializer (ArrayList initializers)
8622 this.initializers = initializers;
8625 public bool Initialize (EmitContext ec, Expression target)
8627 foreach (AnonymousTypeParameter p in initializers) {
8628 MemberAccess ma = new MemberAccess (target, p.Name);
8629 Assign a = p.Expression as Assign;
8630 Assign assign = new Assign (ma, (a != null) ? a.Source : p.Expression);
8631 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (assign));
8637 public class NewInitialize : New, IInitializable
8639 IInitializable initializer;
8641 public bool Initialize (EmitContext ec, Expression target)
8643 return initializer.Initialize (ec, target);
8646 public NewInitialize (Expression requested_type, ArrayList arguments, IInitializable initializer, Location l)
8647 : base (requested_type, arguments, l)
8649 this.initializer = initializer;
8653 public class AnonymousType : Expression
8655 ArrayList parameters;
8656 TypeContainer parent;
8657 TypeContainer anonymous_type;
8659 public AnonymousType (ArrayList parameters, TypeContainer parent, Location loc)
8661 this.parameters = parameters;
8662 this.parent = parent;
8666 public override Expression DoResolve (EmitContext ec)
8668 foreach (AnonymousTypeParameter p in parameters)
8671 anonymous_type = GetAnonymousType (ec);
8673 TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
8674 AnonymousTypeInitializer ati = new AnonymousTypeInitializer (parameters);
8675 return new NewInitialize (te, null, ati, loc).Resolve (ec);
8678 TypeContainer GetAnonymousType (EmitContext ec)
8680 // See if we already have an anonymous type with the right fields.
8681 // If not, create one.
8683 // Look through all availible pre-existing anonymous types:
8684 foreach (DictionaryEntry d in parent.AnonymousTypes) {
8685 ArrayList p = d.Key as ArrayList;
8686 if (p.Count != parameters.Count)
8689 // And for each of the fields we need...
8690 foreach (AnonymousTypeParameter atp in parameters) {
8691 // ... check each of the pre-existing A-type's fields.
8693 foreach (AnonymousTypeParameter a in p)
8694 if (atp.Equals(a)) {
8698 // If the pre-existing A-type doesn't have one of our fields, try the next one
8704 // If it's a match, return it.
8706 return d.Value as TypeContainer;
8708 // Otherwise, create a new type.
8709 return CreateAnonymousType (ec);
8712 TypeContainer CreateAnonymousType (EmitContext ec)
8714 TypeContainer type = new AnonymousClass (parent, loc);
8715 foreach (AnonymousTypeParameter p in parameters) {
8716 TypeExpression te = new TypeExpression (p.Type, loc);
8717 Field field = new Field (type, te, Modifiers.PUBLIC, p.Name, null, loc);
8718 type.AddField (field);
8721 type.DefineMembers ();
8722 parent.AnonymousTypes.Add (parameters, type);
8726 public override void Emit (EmitContext ec)
8728 TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
8729 new New (te, null, loc).Emit(ec);
8733 public class AnonymousTypeParameter : Expression
8737 Expression expression;
8739 public LocatedToken Token {
8740 get { return token; }
8743 public string Name {
8744 get { return name; }
8747 public Expression Expression {
8748 get { return expression; }
8751 public override bool Equals (object o)
8753 AnonymousTypeParameter other = o as AnonymousTypeParameter;
8754 return other != null && Name == other.Name && Type == other.Type;
8757 public override int GetHashCode ()
8759 return name.GetHashCode ();
8762 public override Expression DoResolve (EmitContext ec)
8764 Expression e = expression.Resolve(ec);
8769 public override void Emit (EmitContext ec)
8771 expression.Emit(ec);
8774 public AnonymousTypeParameter (Expression expression, string name)
8777 this.expression = expression;
8778 type = expression.Type;