(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / mcs / expression.cs
blobc04d1e34e1bb7705840864a5807d1f59bec565fe
1 //
2 // expression.cs: Expression representation for the IL tree.
3 //
4 // Author:
5 // Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001, 2002, 2003 Ximian, Inc.
8 // (C) 2003, 2004 Novell, Inc.
9 //
10 #define USE_OLD
12 namespace Mono.CSharp {
13 using System;
14 using System.Collections;
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Text;
19 /// <summary>
20 /// This is just a helper class, it is generated by Unary, UnaryMutator
21 /// when an overloaded method has been found. It just emits the code for a
22 /// static call.
23 /// </summary>
24 public class StaticCallExpr : ExpressionStatement {
25 ArrayList args;
26 MethodInfo mi;
28 public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
30 mi = m;
31 args = a;
33 type = m.ReturnType;
34 eclass = ExprClass.Value;
35 loc = l;
38 public override Expression DoResolve (EmitContext ec)
41 // We are born fully resolved
43 return this;
46 public override void Emit (EmitContext ec)
48 if (args != null)
49 Invocation.EmitArguments (ec, mi, args, false, null);
51 ec.ig.Emit (OpCodes.Call, mi);
52 return;
55 static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
56 Expression e, Location loc)
58 ArrayList args;
59 MethodBase method;
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))
66 return null;
68 args.Add (a);
69 method = Invocation.OverloadResolve (
70 ec, (MethodGroupExpr) mg, args, false, loc);
72 if (method == null)
73 return null;
75 return new StaticCallExpr ((MethodInfo) method, args, loc);
78 public override void EmitStatement (EmitContext ec)
80 Emit (ec);
81 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
82 ec.ig.Emit (OpCodes.Pop);
85 public MethodInfo Method {
86 get { return mi; }
90 public class ParenthesizedExpression : Expression
92 public Expression Expr;
94 public ParenthesizedExpression (Expression expr, Location loc)
96 this.Expr = expr;
97 this.loc = loc;
100 public override Expression DoResolve (EmitContext ec)
102 Expr = Expr.Resolve (ec);
103 return Expr;
106 public override void Emit (EmitContext ec)
108 throw new Exception ("Should not happen");
112 /// <summary>
113 /// Unary expressions.
114 /// </summary>
116 /// <remarks>
117 /// Unary implements unary expressions. It derives from
118 /// ExpressionStatement becuase the pre/post increment/decrement
119 /// operators can be used in a statement context.
120 /// </remarks>
121 public class Unary : Expression {
122 public enum Operator : byte {
123 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
124 Indirection, AddressOf, TOP
127 public Operator Oper;
128 public Expression Expr;
130 public Unary (Operator op, Expression expr, Location loc)
132 this.Oper = op;
133 this.Expr = expr;
134 this.loc = loc;
137 /// <summary>
138 /// Returns a stringified representation of the Operator
139 /// </summary>
140 static public string OperName (Operator oper)
142 switch (oper){
143 case Operator.UnaryPlus:
144 return "+";
145 case Operator.UnaryNegation:
146 return "-";
147 case Operator.LogicalNot:
148 return "!";
149 case Operator.OnesComplement:
150 return "~";
151 case Operator.AddressOf:
152 return "&";
153 case Operator.Indirection:
154 return "*";
157 return oper.ToString ();
160 public static readonly string [] oper_names;
162 static Unary ()
164 oper_names = new string [(int)Operator.TOP];
166 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
167 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
168 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
169 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
170 oper_names [(int) Operator.Indirection] = "op_Indirection";
171 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
174 void Error23 (Type t)
176 Error (
177 23, "Operator " + OperName (Oper) +
178 " cannot be applied to operand of type `" +
179 TypeManager.CSharpName (t) + "'");
182 /// <remarks>
183 /// The result has been already resolved:
185 /// FIXME: a minus constant -128 sbyte cant be turned into a
186 /// constant byte.
187 /// </remarks>
188 static Expression TryReduceNegative (Constant expr)
190 Expression e = null;
192 if (expr is IntConstant)
193 e = new IntConstant (-((IntConstant) expr).Value);
194 else if (expr is UIntConstant){
195 uint value = ((UIntConstant) expr).Value;
197 if (value < 2147483649)
198 return new IntConstant (-(int)value);
199 else
200 e = new LongConstant (-value);
202 else if (expr is LongConstant)
203 e = new LongConstant (-((LongConstant) expr).Value);
204 else if (expr is ULongConstant){
205 ulong value = ((ULongConstant) expr).Value;
207 if (value < 9223372036854775809)
208 return new LongConstant(-(long)value);
210 else if (expr is FloatConstant)
211 e = new FloatConstant (-((FloatConstant) expr).Value);
212 else if (expr is DoubleConstant)
213 e = new DoubleConstant (-((DoubleConstant) expr).Value);
214 else if (expr is DecimalConstant)
215 e = new DecimalConstant (-((DecimalConstant) expr).Value);
216 else if (expr is ShortConstant)
217 e = new IntConstant (-((ShortConstant) expr).Value);
218 else if (expr is UShortConstant)
219 e = new IntConstant (-((UShortConstant) expr).Value);
220 return e;
223 // <summary>
224 // This routine will attempt to simplify the unary expression when the
225 // argument is a constant. The result is returned in `result' and the
226 // function returns true or false depending on whether a reduction
227 // was performed or not
228 // </summary>
229 bool Reduce (EmitContext ec, Constant e, out Expression result)
231 Type expr_type = e.Type;
233 switch (Oper){
234 case Operator.UnaryPlus:
235 result = e;
236 return true;
238 case Operator.UnaryNegation:
239 result = TryReduceNegative (e);
240 return true;
242 case Operator.LogicalNot:
243 if (expr_type != TypeManager.bool_type) {
244 result = null;
245 Error23 (expr_type);
246 return false;
249 BoolConstant b = (BoolConstant) e;
250 result = new BoolConstant (!(b.Value));
251 return true;
253 case Operator.OnesComplement:
254 if (!((expr_type == TypeManager.int32_type) ||
255 (expr_type == TypeManager.uint32_type) ||
256 (expr_type == TypeManager.int64_type) ||
257 (expr_type == TypeManager.uint64_type) ||
258 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
260 result = null;
261 if (Convert.ImplicitConversionExists (ec, e, TypeManager.int32_type)){
262 result = new Cast (new TypeExpression (TypeManager.int32_type, loc), e, loc);
263 result = result.Resolve (ec);
264 } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint32_type)){
265 result = new Cast (new TypeExpression (TypeManager.uint32_type, loc), e, loc);
266 result = result.Resolve (ec);
267 } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.int64_type)){
268 result = new Cast (new TypeExpression (TypeManager.int64_type, loc), e, loc);
269 result = result.Resolve (ec);
270 } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint64_type)){
271 result = new Cast (new TypeExpression (TypeManager.uint64_type, loc), e, loc);
272 result = result.Resolve (ec);
275 if (result == null || !(result is Constant)){
276 result = null;
277 Error23 (expr_type);
278 return false;
281 expr_type = result.Type;
282 e = (Constant) result;
285 if (e is EnumConstant){
286 EnumConstant enum_constant = (EnumConstant) e;
287 Expression reduced;
289 if (Reduce (ec, enum_constant.Child, out reduced)){
290 result = new EnumConstant ((Constant) reduced, enum_constant.Type);
291 return true;
292 } else {
293 result = null;
294 return false;
298 if (expr_type == TypeManager.int32_type){
299 result = new IntConstant (~ ((IntConstant) e).Value);
300 } else if (expr_type == TypeManager.uint32_type){
301 result = new UIntConstant (~ ((UIntConstant) e).Value);
302 } else if (expr_type == TypeManager.int64_type){
303 result = new LongConstant (~ ((LongConstant) e).Value);
304 } else if (expr_type == TypeManager.uint64_type){
305 result = new ULongConstant (~ ((ULongConstant) e).Value);
306 } else {
307 result = null;
308 Error23 (expr_type);
309 return false;
311 return true;
313 case Operator.AddressOf:
314 result = this;
315 return false;
317 case Operator.Indirection:
318 result = this;
319 return false;
321 throw new Exception ("Can not constant fold: " + Oper.ToString());
324 Expression ResolveOperator (EmitContext ec)
326 Type expr_type = Expr.Type;
329 // Step 1: Perform Operator Overload location
331 Expression mg;
332 string op_name;
334 op_name = oper_names [(int) Oper];
336 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
338 if (mg != null) {
339 Expression e = StaticCallExpr.MakeSimpleCall (
340 ec, (MethodGroupExpr) mg, Expr, loc);
342 if (e == null){
343 Error23 (expr_type);
344 return null;
347 return e;
350 // Only perform numeric promotions on:
351 // +, -
353 if (expr_type == null)
354 return null;
357 // Step 2: Default operations on CLI native types.
360 // Attempt to use a constant folding operation.
361 if (Expr is Constant){
362 Expression result;
364 if (Reduce (ec, (Constant) Expr, out result))
365 return result;
368 switch (Oper){
369 case Operator.LogicalNot:
370 if (expr_type != TypeManager.bool_type) {
371 Expr = ResolveBoolean (ec, Expr, loc);
372 if (Expr == null){
373 Error23 (expr_type);
374 return null;
378 type = TypeManager.bool_type;
379 return this;
381 case Operator.OnesComplement:
382 if (!((expr_type == TypeManager.int32_type) ||
383 (expr_type == TypeManager.uint32_type) ||
384 (expr_type == TypeManager.int64_type) ||
385 (expr_type == TypeManager.uint64_type) ||
386 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
387 Expression e;
389 e = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
390 if (e != null){
391 type = TypeManager.int32_type;
392 return this;
394 e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint32_type, loc);
395 if (e != null){
396 type = TypeManager.uint32_type;
397 return this;
399 e = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
400 if (e != null){
401 type = TypeManager.int64_type;
402 return this;
404 e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint64_type, loc);
405 if (e != null){
406 type = TypeManager.uint64_type;
407 return this;
409 Error23 (expr_type);
410 return null;
412 type = expr_type;
413 return this;
415 case Operator.AddressOf:
416 if (Expr.eclass != ExprClass.Variable){
417 Error (211, "Cannot take the address of non-variables");
418 return null;
421 if (!ec.InUnsafe) {
422 UnsafeError (loc);
423 return null;
426 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
427 return null;
430 IVariable variable = Expr as IVariable;
431 if (!ec.InFixedInitializer && ((variable == null) || !variable.VerifyFixed (false))) {
432 Error (212, "You can only take the address of an unfixed expression inside " +
433 "of a fixed statement initializer");
434 return null;
437 if (ec.InFixedInitializer && ((variable != null) && variable.VerifyFixed (false))) {
438 Error (213, "You can not fix an already fixed expression");
439 return null;
442 // According to the specs, a variable is considered definitely assigned if you take
443 // its address.
444 if ((variable != null) && (variable.VariableInfo != null))
445 variable.VariableInfo.SetAssigned (ec);
447 type = TypeManager.GetPointerType (Expr.Type);
448 return this;
450 case Operator.Indirection:
451 if (!ec.InUnsafe){
452 UnsafeError (loc);
453 return null;
456 if (!expr_type.IsPointer){
457 Error (193, "The * or -> operator can only be applied to pointers");
458 return null;
462 // We create an Indirection expression, because
463 // it can implement the IMemoryLocation.
465 return new Indirection (Expr, loc);
467 case Operator.UnaryPlus:
469 // A plus in front of something is just a no-op, so return the child.
471 return Expr;
473 case Operator.UnaryNegation:
475 // Deals with -literals
476 // int operator- (int x)
477 // long operator- (long x)
478 // float operator- (float f)
479 // double operator- (double d)
480 // decimal operator- (decimal d)
482 Expression expr = null;
485 // transform - - expr into expr
487 if (Expr is Unary){
488 Unary unary = (Unary) Expr;
490 if (unary.Oper == Operator.UnaryNegation)
491 return unary.Expr;
495 // perform numeric promotions to int,
496 // long, double.
499 // The following is inneficient, because we call
500 // ImplicitConversion too many times.
502 // It is also not clear if we should convert to Float
503 // or Double initially.
505 if (expr_type == TypeManager.uint32_type){
507 // FIXME: handle exception to this rule that
508 // permits the int value -2147483648 (-2^31) to
509 // bt wrote as a decimal interger literal
511 type = TypeManager.int64_type;
512 Expr = Convert.ImplicitConversion (ec, Expr, type, loc);
513 return this;
516 if (expr_type == TypeManager.uint64_type){
518 // FIXME: Handle exception of `long value'
519 // -92233720368547758087 (-2^63) to be wrote as
520 // decimal integer literal.
522 Error23 (expr_type);
523 return null;
526 if (expr_type == TypeManager.float_type){
527 type = expr_type;
528 return this;
531 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
532 if (expr != null){
533 Expr = expr;
534 type = expr.Type;
535 return this;
538 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
539 if (expr != null){
540 Expr = expr;
541 type = expr.Type;
542 return this;
545 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.double_type, loc);
546 if (expr != null){
547 Expr = expr;
548 type = expr.Type;
549 return this;
552 Error23 (expr_type);
553 return null;
556 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
557 TypeManager.CSharpName (expr_type) + "'");
558 return null;
561 public override Expression DoResolve (EmitContext ec)
563 if (Oper == Operator.AddressOf)
564 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
565 else
566 Expr = Expr.Resolve (ec);
568 if (Expr == null)
569 return null;
571 eclass = ExprClass.Value;
572 return ResolveOperator (ec);
575 public override Expression DoResolveLValue (EmitContext ec, Expression right)
577 if (Oper == Operator.Indirection)
578 return base.DoResolveLValue (ec, right);
580 Error (131, "The left-hand side of an assignment must be a " +
581 "variable, property or indexer");
582 return null;
585 public override void Emit (EmitContext ec)
587 ILGenerator ig = ec.ig;
589 switch (Oper) {
590 case Operator.UnaryPlus:
591 throw new Exception ("This should be caught by Resolve");
593 case Operator.UnaryNegation:
594 if (ec.CheckState) {
595 ig.Emit (OpCodes.Ldc_I4_0);
596 if (type == TypeManager.int64_type)
597 ig.Emit (OpCodes.Conv_U8);
598 Expr.Emit (ec);
599 ig.Emit (OpCodes.Sub_Ovf);
600 } else {
601 Expr.Emit (ec);
602 ig.Emit (OpCodes.Neg);
605 break;
607 case Operator.LogicalNot:
608 Expr.Emit (ec);
609 ig.Emit (OpCodes.Ldc_I4_0);
610 ig.Emit (OpCodes.Ceq);
611 break;
613 case Operator.OnesComplement:
614 Expr.Emit (ec);
615 ig.Emit (OpCodes.Not);
616 break;
618 case Operator.AddressOf:
619 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
620 break;
622 default:
623 throw new Exception ("This should not happen: Operator = "
624 + Oper.ToString ());
628 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
630 if (Oper == Operator.LogicalNot)
631 Expr.EmitBranchable (ec, target, !onTrue);
632 else
633 base.EmitBranchable (ec, target, onTrue);
636 public override string ToString ()
638 return "Unary (" + Oper + ", " + Expr + ")";
644 // Unary operators are turned into Indirection expressions
645 // after semantic analysis (this is so we can take the address
646 // of an indirection).
648 public class Indirection : Expression, IMemoryLocation, IAssignMethod {
649 Expression expr;
650 LocalTemporary temporary;
651 bool prepared;
653 public Indirection (Expression expr, Location l)
655 this.expr = expr;
656 this.type = TypeManager.GetElementType (expr.Type);
657 eclass = ExprClass.Variable;
658 loc = l;
661 void LoadExprValue (EmitContext ec)
665 public override void Emit (EmitContext ec)
667 if (!prepared)
668 expr.Emit (ec);
670 LoadFromPtr (ec.ig, Type);
673 public void Emit (EmitContext ec, bool leave_copy)
675 Emit (ec);
676 if (leave_copy) {
677 ec.ig.Emit (OpCodes.Dup);
678 temporary = new LocalTemporary (ec, expr.Type);
679 temporary.Store (ec);
683 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
685 prepared = prepare_for_load;
687 expr.Emit (ec);
689 if (prepare_for_load)
690 ec.ig.Emit (OpCodes.Dup);
692 source.Emit (ec);
693 if (leave_copy) {
694 ec.ig.Emit (OpCodes.Dup);
695 temporary = new LocalTemporary (ec, expr.Type);
696 temporary.Store (ec);
699 StoreFromPtr (ec.ig, type);
701 if (temporary != null)
702 temporary.Emit (ec);
705 public void AddressOf (EmitContext ec, AddressOp Mode)
707 expr.Emit (ec);
710 public override Expression DoResolve (EmitContext ec)
713 // Born fully resolved
715 return this;
718 public override string ToString ()
720 return "*(" + expr + ")";
724 /// <summary>
725 /// Unary Mutator expressions (pre and post ++ and --)
726 /// </summary>
728 /// <remarks>
729 /// UnaryMutator implements ++ and -- expressions. It derives from
730 /// ExpressionStatement becuase the pre/post increment/decrement
731 /// operators can be used in a statement context.
733 /// FIXME: Idea, we could split this up in two classes, one simpler
734 /// for the common case, and one with the extra fields for more complex
735 /// classes (indexers require temporary access; overloaded require method)
737 /// </remarks>
738 public class UnaryMutator : ExpressionStatement {
739 [Flags]
740 public enum Mode : byte {
741 IsIncrement = 0,
742 IsDecrement = 1,
743 IsPre = 0,
744 IsPost = 2,
746 PreIncrement = 0,
747 PreDecrement = IsDecrement,
748 PostIncrement = IsPost,
749 PostDecrement = IsPost | IsDecrement
752 Mode mode;
753 bool is_expr = false;
754 bool recurse = false;
756 Expression expr;
759 // This is expensive for the simplest case.
761 StaticCallExpr method;
763 public UnaryMutator (Mode m, Expression e, Location l)
765 mode = m;
766 loc = l;
767 expr = e;
770 static string OperName (Mode mode)
772 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
773 "++" : "--";
776 void Error23 (Type t)
778 Error (
779 23, "Operator " + OperName (mode) +
780 " cannot be applied to operand of type `" +
781 TypeManager.CSharpName (t) + "'");
784 /// <summary>
785 /// Returns whether an object of type `t' can be incremented
786 /// or decremented with add/sub (ie, basically whether we can
787 /// use pre-post incr-decr operations on it, but it is not a
788 /// System.Decimal, which we require operator overloading to catch)
789 /// </summary>
790 static bool IsIncrementableNumber (Type t)
792 return (t == TypeManager.sbyte_type) ||
793 (t == TypeManager.byte_type) ||
794 (t == TypeManager.short_type) ||
795 (t == TypeManager.ushort_type) ||
796 (t == TypeManager.int32_type) ||
797 (t == TypeManager.uint32_type) ||
798 (t == TypeManager.int64_type) ||
799 (t == TypeManager.uint64_type) ||
800 (t == TypeManager.char_type) ||
801 (t.IsSubclassOf (TypeManager.enum_type)) ||
802 (t == TypeManager.float_type) ||
803 (t == TypeManager.double_type) ||
804 (t.IsPointer && t != TypeManager.void_ptr_type);
807 Expression ResolveOperator (EmitContext ec)
809 Type expr_type = expr.Type;
812 // Step 1: Perform Operator Overload location
814 Expression mg;
815 string op_name;
817 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
818 op_name = "op_Increment";
819 else
820 op_name = "op_Decrement";
822 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
824 if (mg == null && expr_type.BaseType != null)
825 mg = MemberLookup (ec, expr_type.BaseType, op_name,
826 MemberTypes.Method, AllBindingFlags, loc);
828 if (mg != null) {
829 method = StaticCallExpr.MakeSimpleCall (
830 ec, (MethodGroupExpr) mg, expr, loc);
832 type = method.Type;
833 return this;
837 // The operand of the prefix/postfix increment decrement operators
838 // should be an expression that is classified as a variable,
839 // a property access or an indexer access
841 type = expr_type;
842 if (expr.eclass == ExprClass.Variable){
843 LocalVariableReference var = expr as LocalVariableReference;
844 if ((var != null) && var.IsReadOnly)
845 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
846 if (IsIncrementableNumber (expr_type) ||
847 expr_type == TypeManager.decimal_type){
848 return this;
850 } else if (expr.eclass == ExprClass.IndexerAccess){
851 IndexerAccess ia = (IndexerAccess) expr;
853 expr = ia.ResolveLValue (ec, this);
854 if (expr == null)
855 return null;
857 return this;
858 } else if (expr.eclass == ExprClass.PropertyAccess){
859 PropertyExpr pe = (PropertyExpr) expr;
861 if (pe.VerifyAssignable ())
862 return this;
864 return null;
865 } else {
866 expr.Error_UnexpectedKind ("variable, indexer or property access", loc);
867 return null;
870 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
871 TypeManager.CSharpName (expr_type) + "'");
872 return null;
875 public override Expression DoResolve (EmitContext ec)
877 expr = expr.Resolve (ec);
879 if (expr == null)
880 return null;
882 eclass = ExprClass.Value;
883 return ResolveOperator (ec);
886 static int PtrTypeSize (Type t)
888 return GetTypeSize (TypeManager.GetElementType (t));
892 // Loads the proper "1" into the stack based on the type, then it emits the
893 // opcode for the operation requested
895 void LoadOneAndEmitOp (EmitContext ec, Type t)
898 // Measure if getting the typecode and using that is more/less efficient
899 // that comparing types. t.GetTypeCode() is an internal call.
901 ILGenerator ig = ec.ig;
903 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
904 LongConstant.EmitLong (ig, 1);
905 else if (t == TypeManager.double_type)
906 ig.Emit (OpCodes.Ldc_R8, 1.0);
907 else if (t == TypeManager.float_type)
908 ig.Emit (OpCodes.Ldc_R4, 1.0F);
909 else if (t.IsPointer){
910 int n = PtrTypeSize (t);
912 if (n == 0)
913 ig.Emit (OpCodes.Sizeof, t);
914 else
915 IntConstant.EmitInt (ig, n);
916 } else
917 ig.Emit (OpCodes.Ldc_I4_1);
920 // Now emit the operation
922 if (ec.CheckState){
923 if (t == TypeManager.int32_type ||
924 t == TypeManager.int64_type){
925 if ((mode & Mode.IsDecrement) != 0)
926 ig.Emit (OpCodes.Sub_Ovf);
927 else
928 ig.Emit (OpCodes.Add_Ovf);
929 } else if (t == TypeManager.uint32_type ||
930 t == TypeManager.uint64_type){
931 if ((mode & Mode.IsDecrement) != 0)
932 ig.Emit (OpCodes.Sub_Ovf_Un);
933 else
934 ig.Emit (OpCodes.Add_Ovf_Un);
935 } else {
936 if ((mode & Mode.IsDecrement) != 0)
937 ig.Emit (OpCodes.Sub_Ovf);
938 else
939 ig.Emit (OpCodes.Add_Ovf);
941 } else {
942 if ((mode & Mode.IsDecrement) != 0)
943 ig.Emit (OpCodes.Sub);
944 else
945 ig.Emit (OpCodes.Add);
948 if (t == TypeManager.sbyte_type){
949 if (ec.CheckState)
950 ig.Emit (OpCodes.Conv_Ovf_I1);
951 else
952 ig.Emit (OpCodes.Conv_I1);
953 } else if (t == TypeManager.byte_type){
954 if (ec.CheckState)
955 ig.Emit (OpCodes.Conv_Ovf_U1);
956 else
957 ig.Emit (OpCodes.Conv_U1);
958 } else if (t == TypeManager.short_type){
959 if (ec.CheckState)
960 ig.Emit (OpCodes.Conv_Ovf_I2);
961 else
962 ig.Emit (OpCodes.Conv_I2);
963 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
964 if (ec.CheckState)
965 ig.Emit (OpCodes.Conv_Ovf_U2);
966 else
967 ig.Emit (OpCodes.Conv_U2);
972 void EmitCode (EmitContext ec, bool is_expr)
974 recurse = true;
975 this.is_expr = is_expr;
976 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
980 public override void Emit (EmitContext ec)
983 // We use recurse to allow ourselfs to be the source
984 // of an assignment. This little hack prevents us from
985 // having to allocate another expression
987 if (recurse) {
988 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
989 if (method == null)
990 LoadOneAndEmitOp (ec, expr.Type);
991 else
992 ec.ig.Emit (OpCodes.Call, method.Method);
993 recurse = false;
994 return;
997 EmitCode (ec, true);
1000 public override void EmitStatement (EmitContext ec)
1002 EmitCode (ec, false);
1006 /// <summary>
1007 /// Base class for the `Is' and `As' classes.
1008 /// </summary>
1010 /// <remarks>
1011 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1012 /// size.
1013 /// </remarks>
1014 public abstract class Probe : Expression {
1015 public Expression ProbeType;
1016 protected Expression expr;
1017 protected Type probe_type;
1019 public Probe (Expression expr, Expression probe_type, Location l)
1021 ProbeType = probe_type;
1022 loc = l;
1023 this.expr = expr;
1026 public Expression Expr {
1027 get {
1028 return expr;
1032 public override Expression DoResolve (EmitContext ec)
1034 TypeExpr texpr = ProbeType.ResolveAsTypeTerminal (ec, false);
1035 if (texpr == null)
1036 return null;
1037 probe_type = texpr.ResolveType (ec);
1039 CheckObsoleteAttribute (probe_type);
1041 expr = expr.Resolve (ec);
1042 if (expr == null)
1043 return null;
1045 if (expr.Type.IsPointer) {
1046 Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types");
1047 return null;
1049 return this;
1053 /// <summary>
1054 /// Implementation of the `is' operator.
1055 /// </summary>
1056 public class Is : Probe {
1057 public Is (Expression expr, Expression probe_type, Location l)
1058 : base (expr, probe_type, l)
1062 enum Action {
1063 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1066 Action action;
1068 public override void Emit (EmitContext ec)
1070 ILGenerator ig = ec.ig;
1072 expr.Emit (ec);
1074 switch (action){
1075 case Action.AlwaysFalse:
1076 ig.Emit (OpCodes.Pop);
1077 IntConstant.EmitInt (ig, 0);
1078 return;
1079 case Action.AlwaysTrue:
1080 ig.Emit (OpCodes.Pop);
1081 IntConstant.EmitInt (ig, 1);
1082 return;
1083 case Action.LeaveOnStack:
1084 // the `e != null' rule.
1085 ig.Emit (OpCodes.Ldnull);
1086 ig.Emit (OpCodes.Ceq);
1087 ig.Emit (OpCodes.Ldc_I4_0);
1088 ig.Emit (OpCodes.Ceq);
1089 return;
1090 case Action.Probe:
1091 ig.Emit (OpCodes.Isinst, probe_type);
1092 ig.Emit (OpCodes.Ldnull);
1093 ig.Emit (OpCodes.Cgt_Un);
1094 return;
1096 throw new Exception ("never reached");
1099 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
1101 ILGenerator ig = ec.ig;
1103 switch (action){
1104 case Action.AlwaysFalse:
1105 if (! onTrue)
1106 ig.Emit (OpCodes.Br, target);
1108 return;
1109 case Action.AlwaysTrue:
1110 if (onTrue)
1111 ig.Emit (OpCodes.Br, target);
1113 return;
1114 case Action.LeaveOnStack:
1115 // the `e != null' rule.
1116 expr.Emit (ec);
1117 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1118 return;
1119 case Action.Probe:
1120 expr.Emit (ec);
1121 ig.Emit (OpCodes.Isinst, probe_type);
1122 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1123 return;
1125 throw new Exception ("never reached");
1128 public override Expression DoResolve (EmitContext ec)
1130 Expression e = base.DoResolve (ec);
1132 if ((e == null) || (expr == null))
1133 return null;
1135 Type etype = expr.Type;
1136 bool warning_always_matches = false;
1137 bool warning_never_matches = false;
1139 type = TypeManager.bool_type;
1140 eclass = ExprClass.Value;
1143 // First case, if at compile time, there is an implicit conversion
1144 // then e != null (objects) or true (value types)
1146 e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
1147 if (e != null){
1148 expr = e;
1149 if (etype.IsValueType)
1150 action = Action.AlwaysTrue;
1151 else
1152 action = Action.LeaveOnStack;
1154 warning_always_matches = true;
1155 } else if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1157 // Second case: explicit reference convresion
1159 if (expr is NullLiteral)
1160 action = Action.AlwaysFalse;
1161 else
1162 action = Action.Probe;
1163 } else {
1164 action = Action.AlwaysFalse;
1165 warning_never_matches = true;
1168 if (warning_always_matches)
1169 Warning (183, "The given expression is always of the provided ('{0}') type", TypeManager.CSharpName (probe_type));
1170 else if (warning_never_matches){
1171 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1172 Warning (184, "The given expression is never of the provided ('{0}') type", TypeManager.CSharpName (probe_type));
1175 return this;
1179 /// <summary>
1180 /// Implementation of the `as' operator.
1181 /// </summary>
1182 public class As : Probe {
1183 public As (Expression expr, Expression probe_type, Location l)
1184 : base (expr, probe_type, l)
1188 bool do_isinst = false;
1190 public override void Emit (EmitContext ec)
1192 ILGenerator ig = ec.ig;
1194 expr.Emit (ec);
1196 if (do_isinst)
1197 ig.Emit (OpCodes.Isinst, probe_type);
1200 static void Error_CannotConvertType (Type source, Type target, Location loc)
1202 Report.Error (
1203 39, loc, "as operator can not convert from `" +
1204 TypeManager.CSharpName (source) + "' to `" +
1205 TypeManager.CSharpName (target) + "'");
1208 public override Expression DoResolve (EmitContext ec)
1210 Expression e = base.DoResolve (ec);
1212 if (e == null)
1213 return null;
1215 type = probe_type;
1216 eclass = ExprClass.Value;
1217 Type etype = expr.Type;
1219 if (TypeManager.IsValueType (probe_type)){
1220 Report.Error (77, loc, "The as operator should be used with a reference type only (" +
1221 TypeManager.CSharpName (probe_type) + " is a value type)");
1222 return null;
1226 e = Convert.ImplicitConversion (ec, expr, probe_type, loc);
1227 if (e != null){
1228 expr = e;
1229 do_isinst = false;
1230 return this;
1233 if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1234 do_isinst = true;
1235 return this;
1238 Error_CannotConvertType (etype, probe_type, loc);
1239 return null;
1243 /// <summary>
1244 /// This represents a typecast in the source language.
1246 /// FIXME: Cast expressions have an unusual set of parsing
1247 /// rules, we need to figure those out.
1248 /// </summary>
1249 public class Cast : Expression {
1250 Expression target_type;
1251 Expression expr;
1253 public Cast (Expression cast_type, Expression expr, Location loc)
1255 this.target_type = cast_type;
1256 this.expr = expr;
1257 this.loc = loc;
1260 public Expression TargetType {
1261 get {
1262 return target_type;
1266 public Expression Expr {
1267 get {
1268 return expr;
1270 set {
1271 expr = value;
1275 bool CheckRange (EmitContext ec, long value, Type type, long min, long max)
1277 if (!ec.ConstantCheckState)
1278 return true;
1280 if ((value < min) || (value > max)) {
1281 Error (221, "Constant value `" + value + "' cannot be converted " +
1282 "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1283 "syntax to override)");
1284 return false;
1287 return true;
1290 bool CheckRange (EmitContext ec, ulong value, Type type, ulong max)
1292 if (!ec.ConstantCheckState)
1293 return true;
1295 if (value > max) {
1296 Error (221, "Constant value `" + value + "' cannot be converted " +
1297 "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1298 "syntax to override)");
1299 return false;
1302 return true;
1305 bool CheckUnsigned (EmitContext ec, long value, Type type)
1307 if (!ec.ConstantCheckState)
1308 return true;
1310 if (value < 0) {
1311 Error (221, "Constant value `" + value + "' cannot be converted " +
1312 "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1313 "syntax to override)");
1314 return false;
1317 return true;
1320 /// <summary>
1321 /// Attempts to do a compile-time folding of a constant cast.
1322 /// </summary>
1323 Expression TryReduce (EmitContext ec, Type target_type)
1325 Expression real_expr = expr;
1326 if (real_expr is EnumConstant)
1327 real_expr = ((EnumConstant) real_expr).Child;
1329 if (real_expr is ByteConstant){
1330 byte v = ((ByteConstant) real_expr).Value;
1332 if (target_type == TypeManager.sbyte_type) {
1333 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1334 return null;
1335 return new SByteConstant ((sbyte) v);
1337 if (target_type == TypeManager.short_type)
1338 return new ShortConstant ((short) v);
1339 if (target_type == TypeManager.ushort_type)
1340 return new UShortConstant ((ushort) v);
1341 if (target_type == TypeManager.int32_type)
1342 return new IntConstant ((int) v);
1343 if (target_type == TypeManager.uint32_type)
1344 return new UIntConstant ((uint) v);
1345 if (target_type == TypeManager.int64_type)
1346 return new LongConstant ((long) v);
1347 if (target_type == TypeManager.uint64_type)
1348 return new ULongConstant ((ulong) v);
1349 if (target_type == TypeManager.float_type)
1350 return new FloatConstant ((float) v);
1351 if (target_type == TypeManager.double_type)
1352 return new DoubleConstant ((double) v);
1353 if (target_type == TypeManager.char_type)
1354 return new CharConstant ((char) v);
1355 if (target_type == TypeManager.decimal_type)
1356 return new DecimalConstant ((decimal) v);
1358 if (real_expr is SByteConstant){
1359 sbyte v = ((SByteConstant) real_expr).Value;
1361 if (target_type == TypeManager.byte_type) {
1362 if (!CheckUnsigned (ec, v, target_type))
1363 return null;
1364 return new ByteConstant ((byte) v);
1366 if (target_type == TypeManager.short_type)
1367 return new ShortConstant ((short) v);
1368 if (target_type == TypeManager.ushort_type) {
1369 if (!CheckUnsigned (ec, v, target_type))
1370 return null;
1371 return new UShortConstant ((ushort) v);
1372 } if (target_type == TypeManager.int32_type)
1373 return new IntConstant ((int) v);
1374 if (target_type == TypeManager.uint32_type) {
1375 if (!CheckUnsigned (ec, v, target_type))
1376 return null;
1377 return new UIntConstant ((uint) v);
1378 } if (target_type == TypeManager.int64_type)
1379 return new LongConstant ((long) v);
1380 if (target_type == TypeManager.uint64_type) {
1381 if (!CheckUnsigned (ec, v, target_type))
1382 return null;
1383 return new ULongConstant ((ulong) v);
1385 if (target_type == TypeManager.float_type)
1386 return new FloatConstant ((float) v);
1387 if (target_type == TypeManager.double_type)
1388 return new DoubleConstant ((double) v);
1389 if (target_type == TypeManager.char_type) {
1390 if (!CheckUnsigned (ec, v, target_type))
1391 return null;
1392 return new CharConstant ((char) v);
1394 if (target_type == TypeManager.decimal_type)
1395 return new DecimalConstant ((decimal) v);
1397 if (real_expr is ShortConstant){
1398 short v = ((ShortConstant) real_expr).Value;
1400 if (target_type == TypeManager.byte_type) {
1401 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1402 return null;
1403 return new ByteConstant ((byte) v);
1405 if (target_type == TypeManager.sbyte_type) {
1406 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1407 return null;
1408 return new SByteConstant ((sbyte) v);
1410 if (target_type == TypeManager.ushort_type) {
1411 if (!CheckUnsigned (ec, v, target_type))
1412 return null;
1413 return new UShortConstant ((ushort) v);
1415 if (target_type == TypeManager.int32_type)
1416 return new IntConstant ((int) v);
1417 if (target_type == TypeManager.uint32_type) {
1418 if (!CheckUnsigned (ec, v, target_type))
1419 return null;
1420 return new UIntConstant ((uint) v);
1422 if (target_type == TypeManager.int64_type)
1423 return new LongConstant ((long) v);
1424 if (target_type == TypeManager.uint64_type) {
1425 if (!CheckUnsigned (ec, v, target_type))
1426 return null;
1427 return new ULongConstant ((ulong) v);
1429 if (target_type == TypeManager.float_type)
1430 return new FloatConstant ((float) v);
1431 if (target_type == TypeManager.double_type)
1432 return new DoubleConstant ((double) v);
1433 if (target_type == TypeManager.char_type) {
1434 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1435 return null;
1436 return new CharConstant ((char) v);
1438 if (target_type == TypeManager.decimal_type)
1439 return new DecimalConstant ((decimal) v);
1441 if (real_expr is UShortConstant){
1442 ushort v = ((UShortConstant) real_expr).Value;
1444 if (target_type == TypeManager.byte_type) {
1445 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1446 return null;
1447 return new ByteConstant ((byte) v);
1449 if (target_type == TypeManager.sbyte_type) {
1450 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1451 return null;
1452 return new SByteConstant ((sbyte) v);
1454 if (target_type == TypeManager.short_type) {
1455 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1456 return null;
1457 return new ShortConstant ((short) v);
1459 if (target_type == TypeManager.int32_type)
1460 return new IntConstant ((int) v);
1461 if (target_type == TypeManager.uint32_type)
1462 return new UIntConstant ((uint) v);
1463 if (target_type == TypeManager.int64_type)
1464 return new LongConstant ((long) v);
1465 if (target_type == TypeManager.uint64_type)
1466 return new ULongConstant ((ulong) v);
1467 if (target_type == TypeManager.float_type)
1468 return new FloatConstant ((float) v);
1469 if (target_type == TypeManager.double_type)
1470 return new DoubleConstant ((double) v);
1471 if (target_type == TypeManager.char_type) {
1472 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1473 return null;
1474 return new CharConstant ((char) v);
1476 if (target_type == TypeManager.decimal_type)
1477 return new DecimalConstant ((decimal) v);
1479 if (real_expr is IntConstant){
1480 int v = ((IntConstant) real_expr).Value;
1482 if (target_type == TypeManager.byte_type) {
1483 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1484 return null;
1485 return new ByteConstant ((byte) v);
1487 if (target_type == TypeManager.sbyte_type) {
1488 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1489 return null;
1490 return new SByteConstant ((sbyte) v);
1492 if (target_type == TypeManager.short_type) {
1493 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1494 return null;
1495 return new ShortConstant ((short) v);
1497 if (target_type == TypeManager.ushort_type) {
1498 if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1499 return null;
1500 return new UShortConstant ((ushort) v);
1502 if (target_type == TypeManager.uint32_type) {
1503 if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1504 return null;
1505 return new UIntConstant ((uint) v);
1507 if (target_type == TypeManager.int64_type)
1508 return new LongConstant ((long) v);
1509 if (target_type == TypeManager.uint64_type) {
1510 if (!CheckUnsigned (ec, v, target_type))
1511 return null;
1512 return new ULongConstant ((ulong) v);
1514 if (target_type == TypeManager.float_type)
1515 return new FloatConstant ((float) v);
1516 if (target_type == TypeManager.double_type)
1517 return new DoubleConstant ((double) v);
1518 if (target_type == TypeManager.char_type) {
1519 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1520 return null;
1521 return new CharConstant ((char) v);
1523 if (target_type == TypeManager.decimal_type)
1524 return new DecimalConstant ((decimal) v);
1526 if (real_expr is UIntConstant){
1527 uint v = ((UIntConstant) real_expr).Value;
1529 if (target_type == TypeManager.byte_type) {
1530 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1531 return null;
1532 return new ByteConstant ((byte) v);
1534 if (target_type == TypeManager.sbyte_type) {
1535 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1536 return null;
1537 return new SByteConstant ((sbyte) v);
1539 if (target_type == TypeManager.short_type) {
1540 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1541 return null;
1542 return new ShortConstant ((short) v);
1544 if (target_type == TypeManager.ushort_type) {
1545 if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1546 return null;
1547 return new UShortConstant ((ushort) v);
1549 if (target_type == TypeManager.int32_type) {
1550 if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1551 return null;
1552 return new IntConstant ((int) v);
1554 if (target_type == TypeManager.int64_type)
1555 return new LongConstant ((long) v);
1556 if (target_type == TypeManager.uint64_type)
1557 return new ULongConstant ((ulong) v);
1558 if (target_type == TypeManager.float_type)
1559 return new FloatConstant ((float) v);
1560 if (target_type == TypeManager.double_type)
1561 return new DoubleConstant ((double) v);
1562 if (target_type == TypeManager.char_type) {
1563 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1564 return null;
1565 return new CharConstant ((char) v);
1567 if (target_type == TypeManager.decimal_type)
1568 return new DecimalConstant ((decimal) v);
1570 if (real_expr is LongConstant){
1571 long v = ((LongConstant) real_expr).Value;
1573 if (target_type == TypeManager.byte_type) {
1574 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1575 return null;
1576 return new ByteConstant ((byte) v);
1578 if (target_type == TypeManager.sbyte_type) {
1579 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1580 return null;
1581 return new SByteConstant ((sbyte) v);
1583 if (target_type == TypeManager.short_type) {
1584 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1585 return null;
1586 return new ShortConstant ((short) v);
1588 if (target_type == TypeManager.ushort_type) {
1589 if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1590 return null;
1591 return new UShortConstant ((ushort) v);
1593 if (target_type == TypeManager.int32_type) {
1594 if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1595 return null;
1596 return new IntConstant ((int) v);
1598 if (target_type == TypeManager.uint32_type) {
1599 if (!CheckRange (ec, v, target_type, UInt32.MinValue, UInt32.MaxValue))
1600 return null;
1601 return new UIntConstant ((uint) v);
1603 if (target_type == TypeManager.uint64_type) {
1604 if (!CheckUnsigned (ec, v, target_type))
1605 return null;
1606 return new ULongConstant ((ulong) v);
1608 if (target_type == TypeManager.float_type)
1609 return new FloatConstant ((float) v);
1610 if (target_type == TypeManager.double_type)
1611 return new DoubleConstant ((double) v);
1612 if (target_type == TypeManager.char_type) {
1613 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1614 return null;
1615 return new CharConstant ((char) v);
1617 if (target_type == TypeManager.decimal_type)
1618 return new DecimalConstant ((decimal) v);
1620 if (real_expr is ULongConstant){
1621 ulong v = ((ULongConstant) real_expr).Value;
1623 if (target_type == TypeManager.byte_type) {
1624 if (!CheckRange (ec, v, target_type, Byte.MaxValue))
1625 return null;
1626 return new ByteConstant ((byte) v);
1628 if (target_type == TypeManager.sbyte_type) {
1629 if (!CheckRange (ec, v, target_type, (ulong) SByte.MaxValue))
1630 return null;
1631 return new SByteConstant ((sbyte) v);
1633 if (target_type == TypeManager.short_type) {
1634 if (!CheckRange (ec, v, target_type, (ulong) Int16.MaxValue))
1635 return null;
1636 return new ShortConstant ((short) v);
1638 if (target_type == TypeManager.ushort_type) {
1639 if (!CheckRange (ec, v, target_type, UInt16.MaxValue))
1640 return null;
1641 return new UShortConstant ((ushort) v);
1643 if (target_type == TypeManager.int32_type) {
1644 if (!CheckRange (ec, v, target_type, Int32.MaxValue))
1645 return null;
1646 return new IntConstant ((int) v);
1648 if (target_type == TypeManager.uint32_type) {
1649 if (!CheckRange (ec, v, target_type, UInt32.MaxValue))
1650 return null;
1651 return new UIntConstant ((uint) v);
1653 if (target_type == TypeManager.int64_type) {
1654 if (!CheckRange (ec, v, target_type, (ulong) Int64.MaxValue))
1655 return null;
1656 return new LongConstant ((long) v);
1658 if (target_type == TypeManager.float_type)
1659 return new FloatConstant ((float) v);
1660 if (target_type == TypeManager.double_type)
1661 return new DoubleConstant ((double) v);
1662 if (target_type == TypeManager.char_type) {
1663 if (!CheckRange (ec, v, target_type, Char.MaxValue))
1664 return null;
1665 return new CharConstant ((char) v);
1667 if (target_type == TypeManager.decimal_type)
1668 return new DecimalConstant ((decimal) v);
1670 if (real_expr is FloatConstant){
1671 float v = ((FloatConstant) real_expr).Value;
1673 if (target_type == TypeManager.byte_type)
1674 return new ByteConstant ((byte) v);
1675 if (target_type == TypeManager.sbyte_type)
1676 return new SByteConstant ((sbyte) v);
1677 if (target_type == TypeManager.short_type)
1678 return new ShortConstant ((short) v);
1679 if (target_type == TypeManager.ushort_type)
1680 return new UShortConstant ((ushort) v);
1681 if (target_type == TypeManager.int32_type)
1682 return new IntConstant ((int) v);
1683 if (target_type == TypeManager.uint32_type)
1684 return new UIntConstant ((uint) v);
1685 if (target_type == TypeManager.int64_type)
1686 return new LongConstant ((long) v);
1687 if (target_type == TypeManager.uint64_type)
1688 return new ULongConstant ((ulong) v);
1689 if (target_type == TypeManager.double_type)
1690 return new DoubleConstant ((double) v);
1691 if (target_type == TypeManager.char_type)
1692 return new CharConstant ((char) v);
1693 if (target_type == TypeManager.decimal_type)
1694 return new DecimalConstant ((decimal) v);
1696 if (real_expr is DoubleConstant){
1697 double v = ((DoubleConstant) real_expr).Value;
1699 if (target_type == TypeManager.byte_type){
1700 return new ByteConstant ((byte) v);
1701 } if (target_type == TypeManager.sbyte_type)
1702 return new SByteConstant ((sbyte) v);
1703 if (target_type == TypeManager.short_type)
1704 return new ShortConstant ((short) v);
1705 if (target_type == TypeManager.ushort_type)
1706 return new UShortConstant ((ushort) v);
1707 if (target_type == TypeManager.int32_type)
1708 return new IntConstant ((int) v);
1709 if (target_type == TypeManager.uint32_type)
1710 return new UIntConstant ((uint) v);
1711 if (target_type == TypeManager.int64_type)
1712 return new LongConstant ((long) v);
1713 if (target_type == TypeManager.uint64_type)
1714 return new ULongConstant ((ulong) v);
1715 if (target_type == TypeManager.float_type)
1716 return new FloatConstant ((float) v);
1717 if (target_type == TypeManager.char_type)
1718 return new CharConstant ((char) v);
1719 if (target_type == TypeManager.decimal_type)
1720 return new DecimalConstant ((decimal) v);
1723 if (real_expr is CharConstant){
1724 char v = ((CharConstant) real_expr).Value;
1726 if (target_type == TypeManager.byte_type) {
1727 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1728 return null;
1729 return new ByteConstant ((byte) v);
1731 if (target_type == TypeManager.sbyte_type) {
1732 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1733 return null;
1734 return new SByteConstant ((sbyte) v);
1736 if (target_type == TypeManager.short_type) {
1737 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1738 return null;
1739 return new ShortConstant ((short) v);
1741 if (target_type == TypeManager.int32_type)
1742 return new IntConstant ((int) v);
1743 if (target_type == TypeManager.uint32_type)
1744 return new UIntConstant ((uint) v);
1745 if (target_type == TypeManager.int64_type)
1746 return new LongConstant ((long) v);
1747 if (target_type == TypeManager.uint64_type)
1748 return new ULongConstant ((ulong) v);
1749 if (target_type == TypeManager.float_type)
1750 return new FloatConstant ((float) v);
1751 if (target_type == TypeManager.double_type)
1752 return new DoubleConstant ((double) v);
1753 if (target_type == TypeManager.char_type) {
1754 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1755 return null;
1756 return new CharConstant ((char) v);
1758 if (target_type == TypeManager.decimal_type)
1759 return new DecimalConstant ((decimal) v);
1762 return null;
1765 public override Expression DoResolve (EmitContext ec)
1767 expr = expr.Resolve (ec);
1768 if (expr == null)
1769 return null;
1771 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1772 if (target == null)
1773 return null;
1775 type = target.ResolveType (ec);
1777 CheckObsoleteAttribute (type);
1779 if (type.IsAbstract && type.IsSealed) {
1780 Report.Error (716, loc, "Cannot convert to static type '{0}'", TypeManager.CSharpName (type));
1781 return null;
1784 eclass = ExprClass.Value;
1786 if (expr is Constant){
1787 Expression e = TryReduce (ec, type);
1789 if (e != null)
1790 return e;
1793 if (type.IsPointer && !ec.InUnsafe) {
1794 UnsafeError (loc);
1795 return null;
1797 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1798 return expr;
1801 public override void Emit (EmitContext ec)
1804 // This one will never happen
1806 throw new Exception ("Should not happen");
1810 /// <summary>
1811 /// Binary operators
1812 /// </summary>
1813 public class Binary : Expression {
1814 public enum Operator : byte {
1815 Multiply, Division, Modulus,
1816 Addition, Subtraction,
1817 LeftShift, RightShift,
1818 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1819 Equality, Inequality,
1820 BitwiseAnd,
1821 ExclusiveOr,
1822 BitwiseOr,
1823 LogicalAnd,
1824 LogicalOr,
1828 Operator oper;
1829 Expression left, right;
1831 // This must be kept in sync with Operator!!!
1832 public static readonly string [] oper_names;
1834 static Binary ()
1836 oper_names = new string [(int) Operator.TOP];
1838 oper_names [(int) Operator.Multiply] = "op_Multiply";
1839 oper_names [(int) Operator.Division] = "op_Division";
1840 oper_names [(int) Operator.Modulus] = "op_Modulus";
1841 oper_names [(int) Operator.Addition] = "op_Addition";
1842 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1843 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1844 oper_names [(int) Operator.RightShift] = "op_RightShift";
1845 oper_names [(int) Operator.LessThan] = "op_LessThan";
1846 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1847 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1848 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1849 oper_names [(int) Operator.Equality] = "op_Equality";
1850 oper_names [(int) Operator.Inequality] = "op_Inequality";
1851 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1852 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1853 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1854 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1855 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1858 public Binary (Operator oper, Expression left, Expression right, Location loc)
1860 this.oper = oper;
1861 this.left = left;
1862 this.right = right;
1863 this.loc = loc;
1866 public Operator Oper {
1867 get {
1868 return oper;
1870 set {
1871 oper = value;
1875 public Expression Left {
1876 get {
1877 return left;
1879 set {
1880 left = value;
1884 public Expression Right {
1885 get {
1886 return right;
1888 set {
1889 right = value;
1894 /// <summary>
1895 /// Returns a stringified representation of the Operator
1896 /// </summary>
1897 static string OperName (Operator oper)
1899 switch (oper){
1900 case Operator.Multiply:
1901 return "*";
1902 case Operator.Division:
1903 return "/";
1904 case Operator.Modulus:
1905 return "%";
1906 case Operator.Addition:
1907 return "+";
1908 case Operator.Subtraction:
1909 return "-";
1910 case Operator.LeftShift:
1911 return "<<";
1912 case Operator.RightShift:
1913 return ">>";
1914 case Operator.LessThan:
1915 return "<";
1916 case Operator.GreaterThan:
1917 return ">";
1918 case Operator.LessThanOrEqual:
1919 return "<=";
1920 case Operator.GreaterThanOrEqual:
1921 return ">=";
1922 case Operator.Equality:
1923 return "==";
1924 case Operator.Inequality:
1925 return "!=";
1926 case Operator.BitwiseAnd:
1927 return "&";
1928 case Operator.BitwiseOr:
1929 return "|";
1930 case Operator.ExclusiveOr:
1931 return "^";
1932 case Operator.LogicalOr:
1933 return "||";
1934 case Operator.LogicalAnd:
1935 return "&&";
1938 return oper.ToString ();
1941 public override string ToString ()
1943 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1944 right.ToString () + ")";
1947 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1949 if (expr.Type == target_type)
1950 return expr;
1952 return Convert.ImplicitConversion (ec, expr, target_type, loc);
1955 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1957 Report.Error (
1958 34, loc, "Operator `" + OperName (oper)
1959 + "' is ambiguous on operands of type `"
1960 + TypeManager.CSharpName (l) + "' "
1961 + "and `" + TypeManager.CSharpName (r)
1962 + "'");
1965 bool IsOfType (EmitContext ec, Type l, Type r, Type t, bool check_user_conversions)
1967 if ((l == t) || (r == t))
1968 return true;
1970 if (!check_user_conversions)
1971 return false;
1973 if (Convert.ImplicitUserConversionExists (ec, l, t))
1974 return true;
1975 else if (Convert.ImplicitUserConversionExists (ec, r, t))
1976 return true;
1977 else
1978 return false;
1982 // Note that handling the case l == Decimal || r == Decimal
1983 // is taken care of by the Step 1 Operator Overload resolution.
1985 // If `check_user_conv' is true, we also check whether a user-defined conversion
1986 // exists. Note that we only need to do this if both arguments are of a user-defined
1987 // type, otherwise ConvertImplict() already finds the user-defined conversion for us,
1988 // so we don't explicitly check for performance reasons.
1990 bool DoNumericPromotions (EmitContext ec, Type l, Type r, bool check_user_conv)
1992 if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){
1994 // If either operand is of type double, the other operand is
1995 // conveted to type double.
1997 if (r != TypeManager.double_type)
1998 right = Convert.ImplicitConversion (ec, right, TypeManager.double_type, loc);
1999 if (l != TypeManager.double_type)
2000 left = Convert.ImplicitConversion (ec, left, TypeManager.double_type, loc);
2002 type = TypeManager.double_type;
2003 } else if (IsOfType (ec, l, r, TypeManager.float_type, check_user_conv)){
2005 // if either operand is of type float, the other operand is
2006 // converted to type float.
2008 if (r != TypeManager.double_type)
2009 right = Convert.ImplicitConversion (ec, right, TypeManager.float_type, loc);
2010 if (l != TypeManager.double_type)
2011 left = Convert.ImplicitConversion (ec, left, TypeManager.float_type, loc);
2012 type = TypeManager.float_type;
2013 } else if (IsOfType (ec, l, r, TypeManager.uint64_type, check_user_conv)){
2014 Expression e;
2015 Type other;
2017 // If either operand is of type ulong, the other operand is
2018 // converted to type ulong. or an error ocurrs if the other
2019 // operand is of type sbyte, short, int or long
2021 if (l == TypeManager.uint64_type){
2022 if (r != TypeManager.uint64_type){
2023 if (right is IntConstant){
2024 IntConstant ic = (IntConstant) right;
2026 e = Convert.TryImplicitIntConversion (l, ic);
2027 if (e != null)
2028 right = e;
2029 } else if (right is LongConstant){
2030 long ll = ((LongConstant) right).Value;
2032 if (ll >= 0)
2033 right = new ULongConstant ((ulong) ll);
2034 } else {
2035 e = Convert.ImplicitNumericConversion (ec, right, l, loc);
2036 if (e != null)
2037 right = e;
2040 other = right.Type;
2041 } else {
2042 if (left is IntConstant){
2043 e = Convert.TryImplicitIntConversion (r, (IntConstant) left);
2044 if (e != null)
2045 left = e;
2046 } else if (left is LongConstant){
2047 long ll = ((LongConstant) left).Value;
2049 if (ll > 0)
2050 left = new ULongConstant ((ulong) ll);
2051 } else {
2052 e = Convert.ImplicitNumericConversion (ec, left, r, loc);
2053 if (e != null)
2054 left = e;
2056 other = left.Type;
2059 if ((other == TypeManager.sbyte_type) ||
2060 (other == TypeManager.short_type) ||
2061 (other == TypeManager.int32_type) ||
2062 (other == TypeManager.int64_type))
2063 Error_OperatorAmbiguous (loc, oper, l, r);
2064 else {
2065 left = ForceConversion (ec, left, TypeManager.uint64_type);
2066 right = ForceConversion (ec, right, TypeManager.uint64_type);
2068 type = TypeManager.uint64_type;
2069 } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){
2071 // If either operand is of type long, the other operand is converted
2072 // to type long.
2074 if (l != TypeManager.int64_type)
2075 left = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc);
2076 if (r != TypeManager.int64_type)
2077 right = Convert.ImplicitConversion (ec, right, TypeManager.int64_type, loc);
2079 type = TypeManager.int64_type;
2080 } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){
2082 // If either operand is of type uint, and the other
2083 // operand is of type sbyte, short or int, othe operands are
2084 // converted to type long (unless we have an int constant).
2086 Type other = null;
2088 if (l == TypeManager.uint32_type){
2089 if (right is IntConstant){
2090 IntConstant ic = (IntConstant) right;
2091 int val = ic.Value;
2093 if (val >= 0){
2094 right = new UIntConstant ((uint) val);
2095 type = l;
2097 return true;
2100 other = r;
2101 } else if (r == TypeManager.uint32_type){
2102 if (left is IntConstant){
2103 IntConstant ic = (IntConstant) left;
2104 int val = ic.Value;
2106 if (val >= 0){
2107 left = new UIntConstant ((uint) val);
2108 type = r;
2109 return true;
2113 other = l;
2116 if ((other == TypeManager.sbyte_type) ||
2117 (other == TypeManager.short_type) ||
2118 (other == TypeManager.int32_type)){
2119 left = ForceConversion (ec, left, TypeManager.int64_type);
2120 right = ForceConversion (ec, right, TypeManager.int64_type);
2121 type = TypeManager.int64_type;
2122 } else {
2124 // if either operand is of type uint, the other
2125 // operand is converd to type uint
2127 left = ForceConversion (ec, left, TypeManager.uint32_type);
2128 right = ForceConversion (ec, right, TypeManager.uint32_type);
2129 type = TypeManager.uint32_type;
2131 } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
2132 if (l != TypeManager.decimal_type)
2133 left = Convert.ImplicitConversion (ec, left, TypeManager.decimal_type, loc);
2135 if (r != TypeManager.decimal_type)
2136 right = Convert.ImplicitConversion (ec, right, TypeManager.decimal_type, loc);
2137 type = TypeManager.decimal_type;
2138 } else {
2139 left = ForceConversion (ec, left, TypeManager.int32_type);
2140 right = ForceConversion (ec, right, TypeManager.int32_type);
2142 type = TypeManager.int32_type;
2145 return (left != null) && (right != null);
2148 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
2150 Report.Error (19, loc,
2151 "Operator " + name + " cannot be applied to operands of type `" +
2152 TypeManager.CSharpName (l) + "' and `" +
2153 TypeManager.CSharpName (r) + "'");
2156 void Error_OperatorCannotBeApplied ()
2158 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
2161 static bool is_unsigned (Type t)
2163 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2164 t == TypeManager.short_type || t == TypeManager.byte_type);
2167 static bool is_user_defined (Type t)
2169 if (t.IsSubclassOf (TypeManager.value_type) &&
2170 (!TypeManager.IsBuiltinType (t) || t == TypeManager.decimal_type))
2171 return true;
2172 else
2173 return false;
2176 Expression Make32or64 (EmitContext ec, Expression e)
2178 Type t= e.Type;
2180 if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
2181 t == TypeManager.int64_type || t == TypeManager.uint64_type)
2182 return e;
2183 Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
2184 if (ee != null)
2185 return ee;
2186 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
2187 if (ee != null)
2188 return ee;
2189 ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
2190 if (ee != null)
2191 return ee;
2192 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
2193 if (ee != null)
2194 return ee;
2195 return null;
2198 Expression CheckShiftArguments (EmitContext ec)
2200 Expression e;
2202 e = ForceConversion (ec, right, TypeManager.int32_type);
2203 if (e == null){
2204 Error_OperatorCannotBeApplied ();
2205 return null;
2207 right = e;
2209 if (((e = Convert.ImplicitConversion (ec, left, TypeManager.int32_type, loc)) != null) ||
2210 ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint32_type, loc)) != null) ||
2211 ((e = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc)) != null) ||
2212 ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint64_type, loc)) != null)){
2213 left = e;
2214 type = e.Type;
2216 if (type == TypeManager.int32_type || type == TypeManager.uint32_type){
2217 right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (31), loc);
2218 right = right.DoResolve (ec);
2219 } else {
2220 right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (63), loc);
2221 right = right.DoResolve (ec);
2224 return this;
2226 Error_OperatorCannotBeApplied ();
2227 return null;
2230 Expression ResolveOperator (EmitContext ec)
2232 Type l = left.Type;
2233 Type r = right.Type;
2236 // Special cases: string comapred to null
2238 if (oper == Operator.Equality || oper == Operator.Inequality){
2239 if ((!TypeManager.IsValueType (l) && (right is NullLiteral)) ||
2240 (!TypeManager.IsValueType (r) && (left is NullLiteral))) {
2241 Type = TypeManager.bool_type;
2243 return this;
2246 // IntPtr equality
2247 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
2248 Type = TypeManager.bool_type;
2250 return this;
2255 // Do not perform operator overload resolution when both sides are
2256 // built-in types
2258 if (!(TypeManager.IsCLRType (l) && TypeManager.IsCLRType (r))){
2260 // Step 1: Perform Operator Overload location
2262 Expression left_expr, right_expr;
2264 string op = oper_names [(int) oper];
2266 MethodGroupExpr union;
2267 left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
2268 if (r != l){
2269 right_expr = MemberLookup (
2270 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
2271 union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
2272 } else
2273 union = (MethodGroupExpr) left_expr;
2275 if (union != null) {
2276 ArrayList args = new ArrayList (2);
2277 args.Add (new Argument (left, Argument.AType.Expression));
2278 args.Add (new Argument (right, Argument.AType.Expression));
2280 MethodBase method = Invocation.OverloadResolve (
2281 ec, union, args, true, Location.Null);
2283 if (method != null) {
2284 MethodInfo mi = (MethodInfo) method;
2286 return new BinaryMethod (mi.ReturnType, method, args);
2292 // Step 0: String concatenation (because overloading will get this wrong)
2294 if (oper == Operator.Addition){
2296 // If any of the arguments is a string, cast to string
2299 // Simple constant folding
2300 if (left is StringConstant && right is StringConstant)
2301 return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value);
2303 if (l == TypeManager.string_type || r == TypeManager.string_type) {
2305 if (r == TypeManager.void_type || l == TypeManager.void_type) {
2306 Error_OperatorCannotBeApplied ();
2307 return null;
2310 // try to fold it in on the left
2311 if (left is StringConcat) {
2314 // We have to test here for not-null, since we can be doubly-resolved
2315 // take care of not appending twice
2317 if (type == null){
2318 type = TypeManager.string_type;
2319 ((StringConcat) left).Append (ec, right);
2320 return left.Resolve (ec);
2321 } else {
2322 return left;
2326 // Otherwise, start a new concat expression
2327 return new StringConcat (ec, loc, left, right).Resolve (ec);
2331 // Transform a + ( - b) into a - b
2333 if (right is Unary){
2334 Unary right_unary = (Unary) right;
2336 if (right_unary.Oper == Unary.Operator.UnaryNegation){
2337 oper = Operator.Subtraction;
2338 right = right_unary.Expr;
2339 r = right.Type;
2344 if (oper == Operator.Equality || oper == Operator.Inequality){
2345 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
2346 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
2347 Error_OperatorCannotBeApplied ();
2348 return null;
2351 type = TypeManager.bool_type;
2352 return this;
2356 // operator != (object a, object b)
2357 // operator == (object a, object b)
2359 // For this to be used, both arguments have to be reference-types.
2360 // Read the rationale on the spec (14.9.6)
2362 // Also, if at compile time we know that the classes do not inherit
2363 // one from the other, then we catch the error there.
2365 if (!(l.IsValueType || r.IsValueType)){
2366 type = TypeManager.bool_type;
2368 if (l == r)
2369 return this;
2371 if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
2372 return this;
2375 // Also, a standard conversion must exist from either one
2377 if (!(Convert.ImplicitStandardConversionExists (ec, left, r) ||
2378 Convert.ImplicitStandardConversionExists (ec, right, l))){
2379 Error_OperatorCannotBeApplied ();
2380 return null;
2383 // We are going to have to convert to an object to compare
2385 if (l != TypeManager.object_type)
2386 left = new EmptyCast (left, TypeManager.object_type);
2387 if (r != TypeManager.object_type)
2388 right = new EmptyCast (right, TypeManager.object_type);
2391 // FIXME: CSC here catches errors cs254 and cs252
2393 return this;
2397 // One of them is a valuetype, but the other one is not.
2399 if (!l.IsValueType || !r.IsValueType) {
2400 Error_OperatorCannotBeApplied ();
2401 return null;
2405 // Only perform numeric promotions on:
2406 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2408 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2409 if (l.IsSubclassOf (TypeManager.delegate_type)){
2410 if (((right.eclass == ExprClass.MethodGroup) ||
2411 (r == TypeManager.anonymous_method_type))){
2412 if ((RootContext.Version != LanguageVersion.ISO_1)){
2413 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2414 if (tmp == null)
2415 return null;
2416 right = tmp;
2417 r = right.Type;
2421 if (r.IsSubclassOf (TypeManager.delegate_type)){
2422 MethodInfo method;
2423 ArrayList args = new ArrayList (2);
2425 args = new ArrayList (2);
2426 args.Add (new Argument (left, Argument.AType.Expression));
2427 args.Add (new Argument (right, Argument.AType.Expression));
2429 if (oper == Operator.Addition)
2430 method = TypeManager.delegate_combine_delegate_delegate;
2431 else
2432 method = TypeManager.delegate_remove_delegate_delegate;
2434 if (l != r) {
2435 Error_OperatorCannotBeApplied ();
2436 return null;
2439 return new BinaryDelegate (l, method, args);
2444 // Pointer arithmetic:
2446 // T* operator + (T* x, int y);
2447 // T* operator + (T* x, uint y);
2448 // T* operator + (T* x, long y);
2449 // T* operator + (T* x, ulong y);
2451 // T* operator + (int y, T* x);
2452 // T* operator + (uint y, T *x);
2453 // T* operator + (long y, T *x);
2454 // T* operator + (ulong y, T *x);
2456 // T* operator - (T* x, int y);
2457 // T* operator - (T* x, uint y);
2458 // T* operator - (T* x, long y);
2459 // T* operator - (T* x, ulong y);
2461 // long operator - (T* x, T *y)
2463 if (l.IsPointer){
2464 if (r.IsPointer && oper == Operator.Subtraction){
2465 if (r == l)
2466 return new PointerArithmetic (
2467 false, left, right, TypeManager.int64_type,
2468 loc).Resolve (ec);
2469 } else {
2470 Expression t = Make32or64 (ec, right);
2471 if (t != null)
2472 return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2474 } else if (r.IsPointer && oper == Operator.Addition){
2475 Expression t = Make32or64 (ec, left);
2476 if (t != null)
2477 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2482 // Enumeration operators
2484 bool lie = TypeManager.IsEnumType (l);
2485 bool rie = TypeManager.IsEnumType (r);
2486 if (lie || rie){
2487 Expression temp;
2489 // U operator - (E e, E f)
2490 if (lie && rie){
2491 if (oper == Operator.Subtraction){
2492 if (l == r){
2493 type = TypeManager.EnumToUnderlying (l);
2494 return this;
2496 Error_OperatorCannotBeApplied ();
2497 return null;
2502 // operator + (E e, U x)
2503 // operator - (E e, U x)
2505 if (oper == Operator.Addition || oper == Operator.Subtraction){
2506 Type enum_type = lie ? l : r;
2507 Type other_type = lie ? r : l;
2508 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2510 if (underlying_type != other_type){
2511 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2512 if (temp != null){
2513 if (lie)
2514 right = temp;
2515 else
2516 left = temp;
2517 type = enum_type;
2518 return this;
2521 Error_OperatorCannotBeApplied ();
2522 return null;
2525 type = enum_type;
2526 return this;
2529 if (!rie){
2530 temp = Convert.ImplicitConversion (ec, right, l, loc);
2531 if (temp != null)
2532 right = temp;
2533 else {
2534 Error_OperatorCannotBeApplied ();
2535 return null;
2537 } if (!lie){
2538 temp = Convert.ImplicitConversion (ec, left, r, loc);
2539 if (temp != null){
2540 left = temp;
2541 l = r;
2542 } else {
2543 Error_OperatorCannotBeApplied ();
2544 return null;
2548 if (oper == Operator.Equality || oper == Operator.Inequality ||
2549 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2550 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2551 if (left.Type != right.Type){
2552 Error_OperatorCannotBeApplied ();
2553 return null;
2555 type = TypeManager.bool_type;
2556 return this;
2559 if (oper == Operator.BitwiseAnd ||
2560 oper == Operator.BitwiseOr ||
2561 oper == Operator.ExclusiveOr){
2562 type = l;
2563 return this;
2565 Error_OperatorCannotBeApplied ();
2566 return null;
2569 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2570 return CheckShiftArguments (ec);
2572 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2573 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2574 type = TypeManager.bool_type;
2575 return this;
2578 if (l != r) {
2579 Error_OperatorCannotBeApplied ();
2580 return null;
2583 Expression e = new ConditionalLogicalOperator (
2584 oper == Operator.LogicalAnd, left, right, l, loc);
2585 return e.Resolve (ec);
2589 // operator & (bool x, bool y)
2590 // operator | (bool x, bool y)
2591 // operator ^ (bool x, bool y)
2593 if (l == TypeManager.bool_type && r == TypeManager.bool_type){
2594 if (oper == Operator.BitwiseAnd ||
2595 oper == Operator.BitwiseOr ||
2596 oper == Operator.ExclusiveOr){
2597 type = l;
2598 return this;
2603 // Pointer comparison
2605 if (l.IsPointer && r.IsPointer){
2606 if (oper == Operator.Equality || oper == Operator.Inequality ||
2607 oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2608 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2609 type = TypeManager.bool_type;
2610 return this;
2615 // This will leave left or right set to null if there is an error
2617 bool check_user_conv = is_user_defined (l) && is_user_defined (r);
2618 DoNumericPromotions (ec, l, r, check_user_conv);
2619 if (left == null || right == null){
2620 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2621 return null;
2625 // reload our cached types if required
2627 l = left.Type;
2628 r = right.Type;
2630 if (oper == Operator.BitwiseAnd ||
2631 oper == Operator.BitwiseOr ||
2632 oper == Operator.ExclusiveOr){
2633 if (l == r){
2634 if (((l == TypeManager.int32_type) ||
2635 (l == TypeManager.uint32_type) ||
2636 (l == TypeManager.short_type) ||
2637 (l == TypeManager.ushort_type) ||
2638 (l == TypeManager.int64_type) ||
2639 (l == TypeManager.uint64_type))){
2640 type = l;
2641 } else {
2642 Error_OperatorCannotBeApplied ();
2643 return null;
2645 } else {
2646 Error_OperatorCannotBeApplied ();
2647 return null;
2651 if (oper == Operator.Equality ||
2652 oper == Operator.Inequality ||
2653 oper == Operator.LessThanOrEqual ||
2654 oper == Operator.LessThan ||
2655 oper == Operator.GreaterThanOrEqual ||
2656 oper == Operator.GreaterThan){
2657 type = TypeManager.bool_type;
2660 return this;
2663 public override Expression DoResolve (EmitContext ec)
2665 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2666 left = ((ParenthesizedExpression) left).Expr;
2667 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2668 if (left == null)
2669 return null;
2671 if (left.eclass == ExprClass.Type) {
2672 Error (75, "Casting a negative value needs to have the value in parentheses.");
2673 return null;
2675 } else
2676 left = left.Resolve (ec);
2677 right = right.Resolve (ec);
2679 if (left == null || right == null)
2680 return null;
2682 eclass = ExprClass.Value;
2684 Constant rc = right as Constant;
2685 Constant lc = left as Constant;
2687 if (rc != null & lc != null){
2688 Expression e = ConstantFold.BinaryFold (
2689 ec, oper, lc, rc, loc);
2690 if (e != null)
2691 return e;
2694 return ResolveOperator (ec);
2697 /// <remarks>
2698 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2699 /// context of a conditional bool expression. This function will return
2700 /// false if it is was possible to use EmitBranchable, or true if it was.
2702 /// The expression's code is generated, and we will generate a branch to `target'
2703 /// if the resulting expression value is equal to isTrue
2704 /// </remarks>
2705 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2707 ILGenerator ig = ec.ig;
2710 // This is more complicated than it looks, but its just to avoid
2711 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2712 // but on top of that we want for == and != to use a special path
2713 // if we are comparing against null
2715 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2716 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2719 // put the constant on the rhs, for simplicity
2721 if (left is Constant) {
2722 Expression swap = right;
2723 right = left;
2724 left = swap;
2727 if (((Constant) right).IsZeroInteger) {
2728 left.Emit (ec);
2729 if (my_on_true)
2730 ig.Emit (OpCodes.Brtrue, target);
2731 else
2732 ig.Emit (OpCodes.Brfalse, target);
2734 return;
2735 } else if (right is BoolConstant) {
2736 left.Emit (ec);
2737 if (my_on_true != ((BoolConstant) right).Value)
2738 ig.Emit (OpCodes.Brtrue, target);
2739 else
2740 ig.Emit (OpCodes.Brfalse, target);
2742 return;
2745 } else if (oper == Operator.LogicalAnd) {
2747 if (onTrue) {
2748 Label tests_end = ig.DefineLabel ();
2750 left.EmitBranchable (ec, tests_end, false);
2751 right.EmitBranchable (ec, target, true);
2752 ig.MarkLabel (tests_end);
2753 } else {
2754 left.EmitBranchable (ec, target, false);
2755 right.EmitBranchable (ec, target, false);
2758 return;
2760 } else if (oper == Operator.LogicalOr){
2761 if (onTrue) {
2762 left.EmitBranchable (ec, target, true);
2763 right.EmitBranchable (ec, target, true);
2765 } else {
2766 Label tests_end = ig.DefineLabel ();
2767 left.EmitBranchable (ec, tests_end, true);
2768 right.EmitBranchable (ec, target, false);
2769 ig.MarkLabel (tests_end);
2772 return;
2774 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2775 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2776 oper == Operator.Equality || oper == Operator.Inequality)) {
2777 base.EmitBranchable (ec, target, onTrue);
2778 return;
2781 left.Emit (ec);
2782 right.Emit (ec);
2784 Type t = left.Type;
2785 bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2787 switch (oper){
2788 case Operator.Equality:
2789 if (onTrue)
2790 ig.Emit (OpCodes.Beq, target);
2791 else
2792 ig.Emit (OpCodes.Bne_Un, target);
2793 break;
2795 case Operator.Inequality:
2796 if (onTrue)
2797 ig.Emit (OpCodes.Bne_Un, target);
2798 else
2799 ig.Emit (OpCodes.Beq, target);
2800 break;
2802 case Operator.LessThan:
2803 if (onTrue)
2804 if (isUnsigned)
2805 ig.Emit (OpCodes.Blt_Un, target);
2806 else
2807 ig.Emit (OpCodes.Blt, target);
2808 else
2809 if (isUnsigned)
2810 ig.Emit (OpCodes.Bge_Un, target);
2811 else
2812 ig.Emit (OpCodes.Bge, target);
2813 break;
2815 case Operator.GreaterThan:
2816 if (onTrue)
2817 if (isUnsigned)
2818 ig.Emit (OpCodes.Bgt_Un, target);
2819 else
2820 ig.Emit (OpCodes.Bgt, target);
2821 else
2822 if (isUnsigned)
2823 ig.Emit (OpCodes.Ble_Un, target);
2824 else
2825 ig.Emit (OpCodes.Ble, target);
2826 break;
2828 case Operator.LessThanOrEqual:
2829 if (onTrue)
2830 if (isUnsigned)
2831 ig.Emit (OpCodes.Ble_Un, target);
2832 else
2833 ig.Emit (OpCodes.Ble, target);
2834 else
2835 if (isUnsigned)
2836 ig.Emit (OpCodes.Bgt_Un, target);
2837 else
2838 ig.Emit (OpCodes.Bgt, target);
2839 break;
2842 case Operator.GreaterThanOrEqual:
2843 if (onTrue)
2844 if (isUnsigned)
2845 ig.Emit (OpCodes.Bge_Un, target);
2846 else
2847 ig.Emit (OpCodes.Bge, target);
2848 else
2849 if (isUnsigned)
2850 ig.Emit (OpCodes.Blt_Un, target);
2851 else
2852 ig.Emit (OpCodes.Blt, target);
2853 break;
2854 default:
2855 Console.WriteLine (oper);
2856 throw new Exception ("what is THAT");
2860 public override void Emit (EmitContext ec)
2862 ILGenerator ig = ec.ig;
2863 Type l = left.Type;
2864 OpCode opcode;
2867 // Handle short-circuit operators differently
2868 // than the rest
2870 if (oper == Operator.LogicalAnd) {
2871 Label load_zero = ig.DefineLabel ();
2872 Label end = ig.DefineLabel ();
2874 left.EmitBranchable (ec, load_zero, false);
2875 right.Emit (ec);
2876 ig.Emit (OpCodes.Br, end);
2878 ig.MarkLabel (load_zero);
2879 ig.Emit (OpCodes.Ldc_I4_0);
2880 ig.MarkLabel (end);
2881 return;
2882 } else if (oper == Operator.LogicalOr) {
2883 Label load_one = ig.DefineLabel ();
2884 Label end = ig.DefineLabel ();
2886 left.EmitBranchable (ec, load_one, true);
2887 right.Emit (ec);
2888 ig.Emit (OpCodes.Br, end);
2890 ig.MarkLabel (load_one);
2891 ig.Emit (OpCodes.Ldc_I4_1);
2892 ig.MarkLabel (end);
2893 return;
2896 left.Emit (ec);
2897 right.Emit (ec);
2899 bool isUnsigned = is_unsigned (left.Type);
2901 switch (oper){
2902 case Operator.Multiply:
2903 if (ec.CheckState){
2904 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2905 opcode = OpCodes.Mul_Ovf;
2906 else if (isUnsigned)
2907 opcode = OpCodes.Mul_Ovf_Un;
2908 else
2909 opcode = OpCodes.Mul;
2910 } else
2911 opcode = OpCodes.Mul;
2913 break;
2915 case Operator.Division:
2916 if (isUnsigned)
2917 opcode = OpCodes.Div_Un;
2918 else
2919 opcode = OpCodes.Div;
2920 break;
2922 case Operator.Modulus:
2923 if (isUnsigned)
2924 opcode = OpCodes.Rem_Un;
2925 else
2926 opcode = OpCodes.Rem;
2927 break;
2929 case Operator.Addition:
2930 if (ec.CheckState){
2931 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2932 opcode = OpCodes.Add_Ovf;
2933 else if (isUnsigned)
2934 opcode = OpCodes.Add_Ovf_Un;
2935 else
2936 opcode = OpCodes.Add;
2937 } else
2938 opcode = OpCodes.Add;
2939 break;
2941 case Operator.Subtraction:
2942 if (ec.CheckState){
2943 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2944 opcode = OpCodes.Sub_Ovf;
2945 else if (isUnsigned)
2946 opcode = OpCodes.Sub_Ovf_Un;
2947 else
2948 opcode = OpCodes.Sub;
2949 } else
2950 opcode = OpCodes.Sub;
2951 break;
2953 case Operator.RightShift:
2954 if (isUnsigned)
2955 opcode = OpCodes.Shr_Un;
2956 else
2957 opcode = OpCodes.Shr;
2958 break;
2960 case Operator.LeftShift:
2961 opcode = OpCodes.Shl;
2962 break;
2964 case Operator.Equality:
2965 opcode = OpCodes.Ceq;
2966 break;
2968 case Operator.Inequality:
2969 ig.Emit (OpCodes.Ceq);
2970 ig.Emit (OpCodes.Ldc_I4_0);
2972 opcode = OpCodes.Ceq;
2973 break;
2975 case Operator.LessThan:
2976 if (isUnsigned)
2977 opcode = OpCodes.Clt_Un;
2978 else
2979 opcode = OpCodes.Clt;
2980 break;
2982 case Operator.GreaterThan:
2983 if (isUnsigned)
2984 opcode = OpCodes.Cgt_Un;
2985 else
2986 opcode = OpCodes.Cgt;
2987 break;
2989 case Operator.LessThanOrEqual:
2990 Type lt = left.Type;
2992 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
2993 ig.Emit (OpCodes.Cgt_Un);
2994 else
2995 ig.Emit (OpCodes.Cgt);
2996 ig.Emit (OpCodes.Ldc_I4_0);
2998 opcode = OpCodes.Ceq;
2999 break;
3001 case Operator.GreaterThanOrEqual:
3002 Type le = left.Type;
3004 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
3005 ig.Emit (OpCodes.Clt_Un);
3006 else
3007 ig.Emit (OpCodes.Clt);
3009 ig.Emit (OpCodes.Ldc_I4_0);
3011 opcode = OpCodes.Ceq;
3012 break;
3014 case Operator.BitwiseOr:
3015 opcode = OpCodes.Or;
3016 break;
3018 case Operator.BitwiseAnd:
3019 opcode = OpCodes.And;
3020 break;
3022 case Operator.ExclusiveOr:
3023 opcode = OpCodes.Xor;
3024 break;
3026 default:
3027 throw new Exception ("This should not happen: Operator = "
3028 + oper.ToString ());
3031 ig.Emit (opcode);
3036 // Object created by Binary when the binary operator uses an method instead of being
3037 // a binary operation that maps to a CIL binary operation.
3039 public class BinaryMethod : Expression {
3040 public MethodBase method;
3041 public ArrayList Arguments;
3043 public BinaryMethod (Type t, MethodBase m, ArrayList args)
3045 method = m;
3046 Arguments = args;
3047 type = t;
3048 eclass = ExprClass.Value;
3051 public override Expression DoResolve (EmitContext ec)
3053 return this;
3056 public override void Emit (EmitContext ec)
3058 ILGenerator ig = ec.ig;
3060 if (Arguments != null)
3061 Invocation.EmitArguments (ec, method, Arguments, false, null);
3063 if (method is MethodInfo)
3064 ig.Emit (OpCodes.Call, (MethodInfo) method);
3065 else
3066 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3071 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3072 // b, c, d... may be strings or objects.
3074 public class StringConcat : Expression {
3075 ArrayList operands;
3076 bool invalid = false;
3077 bool emit_conv_done = false;
3079 // Are we also concating objects?
3081 bool is_strings_only = true;
3083 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3085 this.loc = loc;
3086 type = TypeManager.string_type;
3087 eclass = ExprClass.Value;
3089 operands = new ArrayList (2);
3090 Append (ec, left);
3091 Append (ec, right);
3094 public override Expression DoResolve (EmitContext ec)
3096 if (invalid)
3097 return null;
3099 return this;
3102 public void Append (EmitContext ec, Expression operand)
3105 // Constant folding
3107 if (operand is StringConstant && operands.Count != 0) {
3108 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
3109 if (last_operand != null) {
3110 operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value);
3111 return;
3116 // Conversion to object
3118 if (operand.Type != TypeManager.string_type) {
3119 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
3121 if (no == null) {
3122 Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
3123 invalid = true;
3125 operand = no;
3128 operands.Add (operand);
3131 public override void Emit (EmitContext ec)
3133 MethodInfo concat_method = null;
3136 // Do conversion to arguments; check for strings only
3139 // This can get called multiple times, so we have to deal with that.
3140 if (!emit_conv_done) {
3141 emit_conv_done = true;
3142 for (int i = 0; i < operands.Count; i ++) {
3143 Expression e = (Expression) operands [i];
3144 is_strings_only &= e.Type == TypeManager.string_type;
3147 for (int i = 0; i < operands.Count; i ++) {
3148 Expression e = (Expression) operands [i];
3150 if (! is_strings_only && e.Type == TypeManager.string_type) {
3151 // need to make sure this is an object, because the EmitParams
3152 // method might look at the type of this expression, see it is a
3153 // string and emit a string [] when we want an object [];
3155 e = new EmptyCast (e, TypeManager.object_type);
3157 operands [i] = new Argument (e, Argument.AType.Expression);
3162 // Find the right method
3164 switch (operands.Count) {
3165 case 1:
3167 // This should not be possible, because simple constant folding
3168 // is taken care of in the Binary code.
3170 throw new Exception ("how did you get here?");
3172 case 2:
3173 concat_method = is_strings_only ?
3174 TypeManager.string_concat_string_string :
3175 TypeManager.string_concat_object_object ;
3176 break;
3177 case 3:
3178 concat_method = is_strings_only ?
3179 TypeManager.string_concat_string_string_string :
3180 TypeManager.string_concat_object_object_object ;
3181 break;
3182 case 4:
3184 // There is not a 4 param overlaod for object (the one that there is
3185 // is actually a varargs methods, and is only in corlib because it was
3186 // introduced there before.).
3188 if (!is_strings_only)
3189 goto default;
3191 concat_method = TypeManager.string_concat_string_string_string_string;
3192 break;
3193 default:
3194 concat_method = is_strings_only ?
3195 TypeManager.string_concat_string_dot_dot_dot :
3196 TypeManager.string_concat_object_dot_dot_dot ;
3197 break;
3200 Invocation.EmitArguments (ec, concat_method, operands, false, null);
3201 ec.ig.Emit (OpCodes.Call, concat_method);
3206 // Object created with +/= on delegates
3208 public class BinaryDelegate : Expression {
3209 MethodInfo method;
3210 ArrayList args;
3212 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3214 method = mi;
3215 this.args = args;
3216 type = t;
3217 eclass = ExprClass.Value;
3220 public override Expression DoResolve (EmitContext ec)
3222 return this;
3225 public override void Emit (EmitContext ec)
3227 ILGenerator ig = ec.ig;
3229 Invocation.EmitArguments (ec, method, args, false, null);
3231 ig.Emit (OpCodes.Call, (MethodInfo) method);
3232 ig.Emit (OpCodes.Castclass, type);
3235 public Expression Right {
3236 get {
3237 Argument arg = (Argument) args [1];
3238 return arg.Expr;
3242 public bool IsAddition {
3243 get {
3244 return method == TypeManager.delegate_combine_delegate_delegate;
3250 // User-defined conditional logical operator
3251 public class ConditionalLogicalOperator : Expression {
3252 Expression left, right;
3253 bool is_and;
3255 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3257 type = t;
3258 eclass = ExprClass.Value;
3259 this.loc = loc;
3260 this.left = left;
3261 this.right = right;
3262 this.is_and = is_and;
3265 protected void Error19 ()
3267 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", type, type);
3270 protected void Error218 ()
3272 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3273 "declarations of operator true and operator false");
3276 Expression op_true, op_false, op;
3277 LocalTemporary left_temp;
3279 public override Expression DoResolve (EmitContext ec)
3281 MethodInfo method;
3282 Expression operator_group;
3284 operator_group = MethodLookup (ec, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
3285 if (operator_group == null) {
3286 Error19 ();
3287 return null;
3290 left_temp = new LocalTemporary (ec, type);
3292 ArrayList arguments = new ArrayList ();
3293 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3294 arguments.Add (new Argument (right, Argument.AType.Expression));
3295 method = Invocation.OverloadResolve (
3296 ec, (MethodGroupExpr) operator_group, arguments, false, loc)
3297 as MethodInfo;
3298 if ((method == null) || (method.ReturnType != type)) {
3299 Error19 ();
3300 return null;
3303 op = new StaticCallExpr (method, arguments, loc);
3305 op_true = GetOperatorTrue (ec, left_temp, loc);
3306 op_false = GetOperatorFalse (ec, left_temp, loc);
3307 if ((op_true == null) || (op_false == null)) {
3308 Error218 ();
3309 return null;
3312 return this;
3315 public override void Emit (EmitContext ec)
3317 ILGenerator ig = ec.ig;
3318 Label false_target = ig.DefineLabel ();
3319 Label end_target = ig.DefineLabel ();
3321 left.Emit (ec);
3322 left_temp.Store (ec);
3324 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3325 left_temp.Emit (ec);
3326 ig.Emit (OpCodes.Br, end_target);
3327 ig.MarkLabel (false_target);
3328 op.Emit (ec);
3329 ig.MarkLabel (end_target);
3333 public class PointerArithmetic : Expression {
3334 Expression left, right;
3335 bool is_add;
3338 // We assume that `l' is always a pointer
3340 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3342 type = t;
3343 this.loc = loc;
3344 left = l;
3345 right = r;
3346 is_add = is_addition;
3349 public override Expression DoResolve (EmitContext ec)
3351 eclass = ExprClass.Variable;
3353 if (left.Type == TypeManager.void_ptr_type) {
3354 Error (242, "The operation in question is undefined on void pointers");
3355 return null;
3358 return this;
3361 public override void Emit (EmitContext ec)
3363 Type op_type = left.Type;
3364 ILGenerator ig = ec.ig;
3365 Type element = TypeManager.GetElementType (op_type);
3366 int size = GetTypeSize (element);
3367 Type rtype = right.Type;
3369 if (rtype.IsPointer){
3371 // handle (pointer - pointer)
3373 left.Emit (ec);
3374 right.Emit (ec);
3375 ig.Emit (OpCodes.Sub);
3377 if (size != 1){
3378 if (size == 0)
3379 ig.Emit (OpCodes.Sizeof, element);
3380 else
3381 IntLiteral.EmitInt (ig, size);
3382 ig.Emit (OpCodes.Div);
3384 ig.Emit (OpCodes.Conv_I8);
3385 } else {
3387 // handle + and - on (pointer op int)
3389 left.Emit (ec);
3390 ig.Emit (OpCodes.Conv_I);
3391 right.Emit (ec);
3392 if (size != 1){
3393 if (size == 0)
3394 ig.Emit (OpCodes.Sizeof, element);
3395 else
3396 IntLiteral.EmitInt (ig, size);
3397 if (rtype == TypeManager.int64_type)
3398 ig.Emit (OpCodes.Conv_I8);
3399 else if (rtype == TypeManager.uint64_type)
3400 ig.Emit (OpCodes.Conv_U8);
3401 ig.Emit (OpCodes.Mul);
3404 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3405 ig.Emit (OpCodes.Conv_I);
3407 if (is_add)
3408 ig.Emit (OpCodes.Add);
3409 else
3410 ig.Emit (OpCodes.Sub);
3415 /// <summary>
3416 /// Implements the ternary conditional operator (?:)
3417 /// </summary>
3418 public class Conditional : Expression {
3419 Expression expr, trueExpr, falseExpr;
3421 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3423 this.expr = expr;
3424 this.trueExpr = trueExpr;
3425 this.falseExpr = falseExpr;
3426 this.loc = l;
3429 public Expression Expr {
3430 get {
3431 return expr;
3435 public Expression TrueExpr {
3436 get {
3437 return trueExpr;
3441 public Expression FalseExpr {
3442 get {
3443 return falseExpr;
3447 public override Expression DoResolve (EmitContext ec)
3449 expr = expr.Resolve (ec);
3451 if (expr == null)
3452 return null;
3454 if (expr.Type != TypeManager.bool_type){
3455 expr = Expression.ResolveBoolean (
3456 ec, expr, loc);
3458 if (expr == null)
3459 return null;
3462 trueExpr = trueExpr.Resolve (ec);
3463 falseExpr = falseExpr.Resolve (ec);
3465 if (trueExpr == null || falseExpr == null)
3466 return null;
3468 if ((trueExpr is NullLiteral) && (falseExpr is NullLiteral))
3469 return trueExpr;
3471 eclass = ExprClass.Value;
3472 if (trueExpr.Type == falseExpr.Type)
3473 type = trueExpr.Type;
3474 else {
3475 Expression conv;
3476 Type true_type = trueExpr.Type;
3477 Type false_type = falseExpr.Type;
3480 // First, if an implicit conversion exists from trueExpr
3481 // to falseExpr, then the result type is of type falseExpr.Type
3483 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3484 if (conv != null){
3486 // Check if both can convert implicitl to each other's type
3488 if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3489 Error (172,
3490 "Can not compute type of conditional expression " +
3491 "as `" + TypeManager.CSharpName (trueExpr.Type) +
3492 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3493 "' convert implicitly to each other");
3494 return null;
3496 type = false_type;
3497 trueExpr = conv;
3498 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3499 type = true_type;
3500 falseExpr = conv;
3501 } else {
3502 Error (173, "The type of the conditional expression can " +
3503 "not be computed because there is no implicit conversion" +
3504 " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
3505 " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
3506 return null;
3510 if (expr is BoolConstant){
3511 BoolConstant bc = (BoolConstant) expr;
3513 if (bc.Value)
3514 return trueExpr;
3515 else
3516 return falseExpr;
3519 return this;
3522 public override void Emit (EmitContext ec)
3524 ILGenerator ig = ec.ig;
3525 Label false_target = ig.DefineLabel ();
3526 Label end_target = ig.DefineLabel ();
3528 expr.EmitBranchable (ec, false_target, false);
3529 trueExpr.Emit (ec);
3530 ig.Emit (OpCodes.Br, end_target);
3531 ig.MarkLabel (false_target);
3532 falseExpr.Emit (ec);
3533 ig.MarkLabel (end_target);
3538 /// <summary>
3539 /// Local variables
3540 /// </summary>
3541 public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3542 public readonly string Name;
3543 public readonly Block Block;
3544 public LocalInfo local_info;
3545 bool is_readonly;
3546 bool prepared;
3547 LocalTemporary temp;
3549 public LocalVariableReference (Block block, string name, Location l)
3551 Block = block;
3552 Name = name;
3553 loc = l;
3554 eclass = ExprClass.Variable;
3558 // Setting `is_readonly' to false will allow you to create a writable
3559 // reference to a read-only variable. This is used by foreach and using.
3561 public LocalVariableReference (Block block, string name, Location l,
3562 LocalInfo local_info, bool is_readonly)
3563 : this (block, name, l)
3565 this.local_info = local_info;
3566 this.is_readonly = is_readonly;
3569 public VariableInfo VariableInfo {
3570 get {
3571 return local_info.VariableInfo;
3575 public bool IsReadOnly {
3576 get {
3577 return is_readonly;
3581 protected Expression DoResolveBase (EmitContext ec, Expression lvalue_right_side)
3583 if (local_info == null) {
3584 local_info = Block.GetLocalInfo (Name);
3585 is_readonly = local_info.ReadOnly;
3588 type = local_info.VariableType;
3590 VariableInfo variable_info = local_info.VariableInfo;
3591 if (lvalue_right_side != null){
3592 if (is_readonly){
3593 Error (1604, "cannot assign to `" + Name + "' because it is readonly");
3594 return null;
3597 if (variable_info != null)
3598 variable_info.SetAssigned (ec);
3601 Expression e = Block.GetConstantExpression (Name);
3602 if (e != null) {
3603 local_info.Used = true;
3604 eclass = ExprClass.Value;
3605 return e.Resolve (ec);
3608 if ((variable_info != null) && !variable_info.IsAssigned (ec, loc))
3609 return null;
3611 if (lvalue_right_side == null)
3612 local_info.Used = true;
3614 if (ec.CurrentAnonymousMethod != null){
3616 // If we are referencing a variable from the external block
3617 // flag it for capturing
3619 if (local_info.Block.Toplevel != ec.CurrentBlock.Toplevel){
3620 ec.CaptureVariable (local_info);
3621 //Console.WriteLine ("Capturing at " + loc);
3625 return this;
3628 public override Expression DoResolve (EmitContext ec)
3630 return DoResolveBase (ec, null);
3633 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3635 Expression ret = DoResolveBase (ec, right_side);
3636 if (ret != null)
3637 CheckObsoleteAttribute (ret.Type);
3639 return ret;
3642 public bool VerifyFixed (bool is_expression)
3644 return !is_expression || local_info.IsFixed;
3647 public override void Emit (EmitContext ec)
3649 ILGenerator ig = ec.ig;
3651 if (local_info.FieldBuilder == null){
3653 // A local variable on the local CLR stack
3655 ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
3656 } else {
3658 // A local variable captured by anonymous methods.
3660 if (!prepared)
3661 ec.EmitCapturedVariableInstance (local_info);
3663 ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder);
3667 public void Emit (EmitContext ec, bool leave_copy)
3669 Emit (ec);
3670 if (leave_copy){
3671 ec.ig.Emit (OpCodes.Dup);
3672 if (local_info.FieldBuilder != null){
3673 temp = new LocalTemporary (ec, Type);
3674 temp.Store (ec);
3679 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3681 ILGenerator ig = ec.ig;
3682 prepared = prepare_for_load;
3684 if (local_info.FieldBuilder == null){
3686 // A local variable on the local CLR stack
3688 if (local_info.LocalBuilder == null)
3689 throw new Exception ("This should not happen: both Field and Local are null");
3691 source.Emit (ec);
3692 if (leave_copy)
3693 ec.ig.Emit (OpCodes.Dup);
3694 ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
3695 } else {
3697 // A local variable captured by anonymous methods or itereators.
3699 ec.EmitCapturedVariableInstance (local_info);
3701 if (prepare_for_load)
3702 ig.Emit (OpCodes.Dup);
3703 source.Emit (ec);
3704 if (leave_copy){
3705 ig.Emit (OpCodes.Dup);
3706 temp = new LocalTemporary (ec, Type);
3707 temp.Store (ec);
3709 ig.Emit (OpCodes.Stfld, local_info.FieldBuilder);
3710 if (temp != null)
3711 temp.Emit (ec);
3715 public void AddressOf (EmitContext ec, AddressOp mode)
3717 ILGenerator ig = ec.ig;
3719 if (local_info.FieldBuilder == null){
3721 // A local variable on the local CLR stack
3723 ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
3724 } else {
3726 // A local variable captured by anonymous methods or iterators
3728 ec.EmitCapturedVariableInstance (local_info);
3729 ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder);
3733 public override string ToString ()
3735 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3739 /// <summary>
3740 /// This represents a reference to a parameter in the intermediate
3741 /// representation.
3742 /// </summary>
3743 public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3744 Parameters pars;
3745 String name;
3746 int idx;
3747 Block block;
3748 VariableInfo vi;
3749 public Parameter.Modifier mod;
3750 public bool is_ref, is_out, prepared;
3752 public bool IsOut {
3753 get {
3754 return is_out;
3758 public bool IsRef {
3759 get {
3760 return is_ref;
3764 LocalTemporary temp;
3766 public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc)
3768 this.pars = pars;
3769 this.block = block;
3770 this.idx = idx;
3771 this.name = name;
3772 this.loc = loc;
3773 eclass = ExprClass.Variable;
3776 public VariableInfo VariableInfo {
3777 get { return vi; }
3780 public bool VerifyFixed (bool is_expression)
3782 return !is_expression || TypeManager.IsValueType (type);
3785 public bool IsAssigned (EmitContext ec, Location loc)
3787 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (vi))
3788 return true;
3790 Report.Error (165, loc,
3791 "Use of unassigned parameter `" + name + "'");
3792 return false;
3795 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3797 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (vi, field_name))
3798 return true;
3800 Report.Error (170, loc,
3801 "Use of possibly unassigned field `" + field_name + "'");
3802 return false;
3805 public void SetAssigned (EmitContext ec)
3807 if (is_out && ec.DoFlowAnalysis)
3808 ec.CurrentBranching.SetAssigned (vi);
3811 public void SetFieldAssigned (EmitContext ec, string field_name)
3813 if (is_out && ec.DoFlowAnalysis)
3814 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
3817 protected void DoResolveBase (EmitContext ec)
3819 type = pars.GetParameterInfo (ec, idx, out mod);
3820 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3821 is_out = (mod & Parameter.Modifier.OUT) != 0;
3822 eclass = ExprClass.Variable;
3824 if (is_out)
3825 vi = block.ParameterMap [idx];
3827 if (ec.CurrentAnonymousMethod != null){
3828 if (is_ref){
3829 Report.Error (1628, Location,
3830 "Can not reference a ref or out parameter in an anonymous method");
3831 return;
3835 // If we are referencing the parameter from the external block
3836 // flag it for capturing
3838 //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name));
3839 if (!block.IsLocalParameter (name)){
3840 ec.CaptureParameter (name, type, idx);
3846 // Notice that for ref/out parameters, the type exposed is not the
3847 // same type exposed externally.
3849 // for "ref int a":
3850 // externally we expose "int&"
3851 // here we expose "int".
3853 // We record this in "is_ref". This means that the type system can treat
3854 // the type as it is expected, but when we generate the code, we generate
3855 // the alternate kind of code.
3857 public override Expression DoResolve (EmitContext ec)
3859 DoResolveBase (ec);
3861 if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3862 return null;
3864 if (ec.RemapToProxy)
3865 return ec.RemapParameter (idx);
3867 return this;
3870 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3872 DoResolveBase (ec);
3874 SetAssigned (ec);
3876 if (ec.RemapToProxy)
3877 return ec.RemapParameterLValue (idx, right_side);
3879 return this;
3882 static public void EmitLdArg (ILGenerator ig, int x)
3884 if (x <= 255){
3885 switch (x){
3886 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3887 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3888 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3889 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3890 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3892 } else
3893 ig.Emit (OpCodes.Ldarg, x);
3897 // This method is used by parameters that are references, that are
3898 // being passed as references: we only want to pass the pointer (that
3899 // is already stored in the parameter, not the address of the pointer,
3900 // and not the value of the variable).
3902 public void EmitLoad (EmitContext ec)
3904 ILGenerator ig = ec.ig;
3905 int arg_idx = idx;
3907 if (!ec.IsStatic)
3908 arg_idx++;
3910 EmitLdArg (ig, arg_idx);
3913 // FIXME: Review for anonymous methods
3917 public override void Emit (EmitContext ec)
3919 if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
3920 ec.EmitParameter (name);
3921 return;
3924 Emit (ec, false);
3927 public void Emit (EmitContext ec, bool leave_copy)
3929 ILGenerator ig = ec.ig;
3930 int arg_idx = idx;
3932 if (!ec.IsStatic)
3933 arg_idx++;
3935 EmitLdArg (ig, arg_idx);
3937 if (is_ref) {
3938 if (prepared)
3939 ec.ig.Emit (OpCodes.Dup);
3942 // If we are a reference, we loaded on the stack a pointer
3943 // Now lets load the real value
3945 LoadFromPtr (ig, type);
3948 if (leave_copy) {
3949 ec.ig.Emit (OpCodes.Dup);
3951 if (is_ref) {
3952 temp = new LocalTemporary (ec, type);
3953 temp.Store (ec);
3958 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3960 if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
3961 ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load);
3962 return;
3965 ILGenerator ig = ec.ig;
3966 int arg_idx = idx;
3968 prepared = prepare_for_load;
3970 if (!ec.IsStatic)
3971 arg_idx++;
3973 if (is_ref && !prepared)
3974 EmitLdArg (ig, arg_idx);
3976 source.Emit (ec);
3978 if (leave_copy)
3979 ec.ig.Emit (OpCodes.Dup);
3981 if (is_ref) {
3982 if (leave_copy) {
3983 temp = new LocalTemporary (ec, type);
3984 temp.Store (ec);
3987 StoreFromPtr (ig, type);
3989 if (temp != null)
3990 temp.Emit (ec);
3991 } else {
3992 if (arg_idx <= 255)
3993 ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
3994 else
3995 ig.Emit (OpCodes.Starg, arg_idx);
3999 public void AddressOf (EmitContext ec, AddressOp mode)
4001 if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4002 ec.EmitAddressOfParameter (name);
4003 return;
4006 int arg_idx = idx;
4008 if (!ec.IsStatic)
4009 arg_idx++;
4011 if (is_ref){
4012 if (arg_idx <= 255)
4013 ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
4014 else
4015 ec.ig.Emit (OpCodes.Ldarg, arg_idx);
4016 } else {
4017 if (arg_idx <= 255)
4018 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
4019 else
4020 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
4026 /// <summary>
4027 /// Used for arguments to New(), Invocation()
4028 /// </summary>
4029 public class Argument {
4030 public enum AType : byte {
4031 Expression,
4032 Ref,
4033 Out,
4034 ArgList
4037 public readonly AType ArgType;
4038 public Expression Expr;
4040 public Argument (Expression expr, AType type)
4042 this.Expr = expr;
4043 this.ArgType = type;
4046 public Argument (Expression expr)
4048 this.Expr = expr;
4049 this.ArgType = AType.Expression;
4052 public Type Type {
4053 get {
4054 if (ArgType == AType.Ref || ArgType == AType.Out)
4055 return TypeManager.GetReferenceType (Expr.Type);
4056 else
4057 return Expr.Type;
4061 public Parameter.Modifier GetParameterModifier ()
4063 switch (ArgType) {
4064 case AType.Out:
4065 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
4067 case AType.Ref:
4068 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
4070 default:
4071 return Parameter.Modifier.NONE;
4075 public static string FullDesc (Argument a)
4077 if (a.ArgType == AType.ArgList)
4078 return "__arglist";
4080 return (a.ArgType == AType.Ref ? "ref " :
4081 (a.ArgType == AType.Out ? "out " : "")) +
4082 TypeManager.CSharpName (a.Expr.Type);
4085 public bool ResolveMethodGroup (EmitContext ec, Location loc)
4087 // FIXME: csc doesn't report any error if you try to use `ref' or
4088 // `out' in a delegate creation expression.
4089 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4090 if (Expr == null)
4091 return false;
4093 return true;
4096 public bool Resolve (EmitContext ec, Location loc)
4098 if (ArgType == AType.Ref) {
4099 Expr = Expr.Resolve (ec);
4100 if (Expr == null)
4101 return false;
4103 if (!ec.IsConstructor) {
4104 FieldExpr fe = Expr as FieldExpr;
4105 if (fe != null && fe.FieldInfo.IsInitOnly) {
4106 if (fe.FieldInfo.IsStatic)
4107 Report.Error (199, loc, "A static readonly field cannot be passed ref or out (except in a static constructor)");
4108 else
4109 Report.Error (192, loc, "A readonly field cannot be passed ref or out (except in a constructor)");
4110 return false;
4113 Expr = Expr.ResolveLValue (ec, Expr);
4114 } else if (ArgType == AType.Out)
4115 Expr = Expr.ResolveLValue (ec, EmptyExpression.Null);
4116 else
4117 Expr = Expr.Resolve (ec);
4119 if (Expr == null)
4120 return false;
4122 if (ArgType == AType.Expression)
4123 return true;
4124 else {
4126 // Catch errors where fields of a MarshalByRefObject are passed as ref or out
4127 // This is only allowed for `this'
4129 FieldExpr fe = Expr as FieldExpr;
4130 if (fe != null && !fe.IsStatic){
4131 Expression instance = fe.InstanceExpression;
4133 if (instance.GetType () != typeof (This)){
4134 if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){
4135 Report.Error (197, loc,
4136 "Can not pass a type that derives from MarshalByRefObject with out or ref");
4137 return false;
4143 if (Expr.eclass != ExprClass.Variable){
4145 // We just probe to match the CSC output
4147 if (Expr.eclass == ExprClass.PropertyAccess ||
4148 Expr.eclass == ExprClass.IndexerAccess){
4149 Report.Error (
4150 206, loc,
4151 "A property or indexer can not be passed as an out or ref " +
4152 "parameter");
4153 } else {
4154 Report.Error (
4155 1510, loc,
4156 "An lvalue is required as an argument to out or ref");
4158 return false;
4161 return true;
4164 public void Emit (EmitContext ec)
4167 // Ref and Out parameters need to have their addresses taken.
4169 // ParameterReferences might already be references, so we want
4170 // to pass just the value
4172 if (ArgType == AType.Ref || ArgType == AType.Out){
4173 AddressOp mode = AddressOp.Store;
4175 if (ArgType == AType.Ref)
4176 mode |= AddressOp.Load;
4178 if (Expr is ParameterReference){
4179 ParameterReference pr = (ParameterReference) Expr;
4181 if (pr.IsRef)
4182 pr.EmitLoad (ec);
4183 else {
4185 pr.AddressOf (ec, mode);
4187 } else {
4188 ((IMemoryLocation)Expr).AddressOf (ec, mode);
4190 } else
4191 Expr.Emit (ec);
4195 /// <summary>
4196 /// Invocation of methods or delegates.
4197 /// </summary>
4198 public class Invocation : ExpressionStatement {
4199 public readonly ArrayList Arguments;
4201 Expression expr;
4202 MethodBase method = null;
4204 static Hashtable method_parameter_cache;
4206 static Invocation ()
4208 method_parameter_cache = new PtrHashtable ();
4212 // arguments is an ArrayList, but we do not want to typecast,
4213 // as it might be null.
4215 // FIXME: only allow expr to be a method invocation or a
4216 // delegate invocation (7.5.5)
4218 public Invocation (Expression expr, ArrayList arguments, Location l)
4220 this.expr = expr;
4221 Arguments = arguments;
4222 loc = l;
4225 public Expression Expr {
4226 get {
4227 return expr;
4231 /// <summary>
4232 /// Returns the Parameters (a ParameterData interface) for the
4233 /// Method `mb'
4234 /// </summary>
4235 public static ParameterData GetParameterData (MethodBase mb)
4237 object pd = method_parameter_cache [mb];
4238 object ip;
4240 if (pd != null)
4241 return (ParameterData) pd;
4244 ip = TypeManager.LookupParametersByBuilder (mb);
4245 if (ip != null){
4246 method_parameter_cache [mb] = ip;
4248 return (ParameterData) ip;
4249 } else {
4250 ReflectionParameters rp = new ReflectionParameters (mb);
4251 method_parameter_cache [mb] = rp;
4253 return (ParameterData) rp;
4257 /// <summary>
4258 /// Determines "better conversion" as specified in 7.4.2.3
4260 /// Returns : p if a->p is better,
4261 /// q if a->q is better,
4262 /// null if neither is better
4263 /// </summary>
4264 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
4266 Type argument_type = a.Type;
4267 Expression argument_expr = a.Expr;
4269 if (argument_type == null)
4270 throw new Exception ("Expression of type " + a.Expr +
4271 " does not resolve its type");
4273 if (p == null || q == null)
4274 throw new InternalErrorException ("BetterConversion Got a null conversion");
4276 if (p == q)
4277 return null;
4279 if (argument_expr is NullLiteral) {
4281 // If the argument is null and one of the types to compare is 'object' and
4282 // the other is a reference type, we prefer the other.
4284 // This follows from the usual rules:
4285 // * There is an implicit conversion from 'null' to type 'object'
4286 // * There is an implicit conversion from 'null' to any reference type
4287 // * There is an implicit conversion from any reference type to type 'object'
4288 // * There is no implicit conversion from type 'object' to other reference types
4289 // => Conversion of 'null' to a reference type is better than conversion to 'object'
4291 // FIXME: This probably isn't necessary, since the type of a NullLiteral is 'System.Null'.
4292 // I think it used to be 'object' and thus needed a special case to avoid the
4293 // immediately following two checks.
4295 if (!p.IsValueType && q == TypeManager.object_type)
4296 return p;
4297 if (!q.IsValueType && p == TypeManager.object_type)
4298 return q;
4301 if (argument_type == p)
4302 return p;
4304 if (argument_type == q)
4305 return q;
4307 Expression p_tmp = new EmptyExpression (p);
4308 Expression q_tmp = new EmptyExpression (q);
4310 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4311 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4313 if (p_to_q && !q_to_p)
4314 return p;
4316 if (q_to_p && !p_to_q)
4317 return q;
4319 if (p == TypeManager.sbyte_type)
4320 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4321 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4322 return p;
4323 if (q == TypeManager.sbyte_type)
4324 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
4325 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4326 return q;
4328 if (p == TypeManager.short_type)
4329 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4330 q == TypeManager.uint64_type)
4331 return p;
4332 if (q == TypeManager.short_type)
4333 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
4334 p == TypeManager.uint64_type)
4335 return q;
4337 if (p == TypeManager.int32_type)
4338 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4339 return p;
4340 if (q == TypeManager.int32_type)
4341 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4342 return q;
4344 if (p == TypeManager.int64_type)
4345 if (q == TypeManager.uint64_type)
4346 return p;
4347 if (q == TypeManager.int64_type)
4348 if (p == TypeManager.uint64_type)
4349 return q;
4351 return null;
4354 /// <summary>
4355 /// Determines "Better function" between candidate
4356 /// and the current best match
4357 /// </summary>
4358 /// <remarks>
4359 /// Returns an integer indicating :
4360 /// false if candidate ain't better
4361 /// true if candidate is better than the current best match
4362 /// </remarks>
4363 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
4364 MethodBase candidate, bool candidate_params,
4365 MethodBase best, bool best_params, Location loc)
4367 ParameterData candidate_pd = GetParameterData (candidate);
4368 ParameterData best_pd = GetParameterData (best);
4370 int cand_count = candidate_pd.Count;
4373 // If there is no best method, than this one
4374 // is better, however, if we already found a
4375 // best method, we cant tell. This happens
4376 // if we have:
4378 // interface IFoo {
4379 // void DoIt ();
4380 // }
4382 // interface IBar {
4383 // void DoIt ();
4384 // }
4386 // interface IFooBar : IFoo, IBar {}
4388 // We cant tell if IFoo.DoIt is better than IBar.DoIt
4390 // However, we have to consider that
4391 // Trim (); is better than Trim (params char[] chars);
4393 if (cand_count == 0 && argument_count == 0)
4394 return !candidate_params && best_params;
4396 if ((candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS) &&
4397 (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.ARGLIST))
4398 if (cand_count != argument_count)
4399 return false;
4401 bool better_at_least_one = false;
4402 for (int j = 0; j < argument_count; ++j) {
4403 Argument a = (Argument) args [j];
4405 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (j));
4406 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (j));
4408 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4409 if (candidate_params)
4410 ct = TypeManager.GetElementType (ct);
4412 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4413 if (best_params)
4414 bt = TypeManager.GetElementType (bt);
4416 Type better = BetterConversion (ec, a, ct, bt, loc);
4418 // for each argument, the conversion to 'ct' should be no worse than
4419 // the conversion to 'bt'.
4420 if (better == bt)
4421 return false;
4423 // for at least one argument, the conversion to 'ct' should be better than
4424 // the conversion to 'bt'.
4425 if (better == ct)
4426 better_at_least_one = true;
4430 // If a method (in the normal form) with the
4431 // same signature as the expanded form of the
4432 // current best params method already exists,
4433 // the expanded form is not applicable so we
4434 // force it to select the candidate
4436 if (!candidate_params && best_params && cand_count == argument_count)
4437 return true;
4439 return better_at_least_one;
4442 public static string FullMethodDesc (MethodBase mb)
4444 string ret_type = "";
4446 if (mb == null)
4447 return "";
4449 if (mb is MethodInfo)
4450 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
4452 StringBuilder sb = new StringBuilder (ret_type);
4453 sb.Append (" ");
4454 sb.Append (mb.ReflectedType.ToString ());
4455 sb.Append (".");
4456 sb.Append (mb.Name);
4458 ParameterData pd = GetParameterData (mb);
4460 int count = pd.Count;
4461 sb.Append (" (");
4463 for (int i = count; i > 0; ) {
4464 i--;
4466 sb.Append (pd.ParameterDesc (count - i - 1));
4467 if (i != 0)
4468 sb.Append (", ");
4471 sb.Append (")");
4472 return sb.ToString ();
4475 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4477 MemberInfo [] miset;
4478 MethodGroupExpr union;
4480 if (mg1 == null) {
4481 if (mg2 == null)
4482 return null;
4483 return (MethodGroupExpr) mg2;
4484 } else {
4485 if (mg2 == null)
4486 return (MethodGroupExpr) mg1;
4489 MethodGroupExpr left_set = null, right_set = null;
4490 int length1 = 0, length2 = 0;
4492 left_set = (MethodGroupExpr) mg1;
4493 length1 = left_set.Methods.Length;
4495 right_set = (MethodGroupExpr) mg2;
4496 length2 = right_set.Methods.Length;
4498 ArrayList common = new ArrayList ();
4500 foreach (MethodBase r in right_set.Methods){
4501 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4502 common.Add (r);
4505 miset = new MemberInfo [length1 + length2 - common.Count];
4506 left_set.Methods.CopyTo (miset, 0);
4508 int k = length1;
4510 foreach (MethodBase r in right_set.Methods) {
4511 if (!common.Contains (r))
4512 miset [k++] = r;
4515 union = new MethodGroupExpr (miset, loc);
4517 return union;
4520 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4521 ArrayList arguments, int arg_count,
4522 ref MethodBase candidate)
4524 return IsParamsMethodApplicable (
4525 ec, me, arguments, arg_count, false, ref candidate) ||
4526 IsParamsMethodApplicable (
4527 ec, me, arguments, arg_count, true, ref candidate);
4532 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4533 ArrayList arguments, int arg_count,
4534 bool do_varargs, ref MethodBase candidate)
4536 return IsParamsMethodApplicable (
4537 ec, arguments, arg_count, candidate, do_varargs);
4540 /// <summary>
4541 /// Determines if the candidate method, if a params method, is applicable
4542 /// in its expanded form to the given set of arguments
4543 /// </summary>
4544 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4545 int arg_count, MethodBase candidate,
4546 bool do_varargs)
4548 ParameterData pd = GetParameterData (candidate);
4550 int pd_count = pd.Count;
4551 if (pd_count == 0)
4552 return false;
4554 int count = pd_count - 1;
4555 if (do_varargs) {
4556 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4557 return false;
4558 if (pd_count != arg_count)
4559 return false;
4560 } else {
4561 if (pd.ParameterModifier (count) != Parameter.Modifier.PARAMS)
4562 return false;
4565 if (count > arg_count)
4566 return false;
4568 if (pd_count == 1 && arg_count == 0)
4569 return true;
4572 // If we have come this far, the case which
4573 // remains is when the number of parameters is
4574 // less than or equal to the argument count.
4576 for (int i = 0; i < count; ++i) {
4578 Argument a = (Argument) arguments [i];
4580 Parameter.Modifier a_mod = a.GetParameterModifier () &
4581 (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4582 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4583 (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4585 if (a_mod == p_mod) {
4587 if (a_mod == Parameter.Modifier.NONE)
4588 if (!Convert.ImplicitConversionExists (ec,
4589 a.Expr,
4590 pd.ParameterType (i)))
4591 return false;
4593 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4594 Type pt = pd.ParameterType (i);
4596 if (!pt.IsByRef)
4597 pt = TypeManager.GetReferenceType (pt);
4599 if (pt != a.Type)
4600 return false;
4602 } else
4603 return false;
4607 if (do_varargs) {
4608 Argument a = (Argument) arguments [count];
4609 if (!(a.Expr is Arglist))
4610 return false;
4612 return true;
4615 Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
4617 for (int i = pd_count - 1; i < arg_count; i++) {
4618 Argument a = (Argument) arguments [i];
4620 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4621 return false;
4624 return true;
4627 static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4628 ArrayList arguments, int arg_count,
4629 ref MethodBase candidate)
4631 return IsApplicable (ec, arguments, arg_count, candidate);
4634 /// <summary>
4635 /// Determines if the candidate method is applicable (section 14.4.2.1)
4636 /// to the given set of arguments
4637 /// </summary>
4638 static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4639 MethodBase candidate)
4641 ParameterData pd = GetParameterData (candidate);
4643 if (arg_count != pd.Count)
4644 return false;
4646 for (int i = arg_count; i > 0; ) {
4647 i--;
4649 Argument a = (Argument) arguments [i];
4651 Parameter.Modifier a_mod = a.GetParameterModifier () &
4652 unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
4653 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4654 unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
4657 if (a_mod == p_mod ||
4658 (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
4659 if (a_mod == Parameter.Modifier.NONE) {
4660 if (!Convert.ImplicitConversionExists (ec,
4661 a.Expr,
4662 pd.ParameterType (i)))
4663 return false;
4666 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4667 Type pt = pd.ParameterType (i);
4669 if (!pt.IsByRef)
4670 pt = TypeManager.GetReferenceType (pt);
4672 if (pt != a.Type)
4673 return false;
4675 } else
4676 return false;
4679 return true;
4682 static private bool IsAncestralType (Type first_type, Type second_type)
4684 return first_type != second_type &&
4685 (second_type.IsSubclassOf (first_type) ||
4686 TypeManager.ImplementsInterface (second_type, first_type));
4689 /// <summary>
4690 /// Find the Applicable Function Members (7.4.2.1)
4692 /// me: Method Group expression with the members to select.
4693 /// it might contain constructors or methods (or anything
4694 /// that maps to a method).
4696 /// Arguments: ArrayList containing resolved Argument objects.
4698 /// loc: The location if we want an error to be reported, or a Null
4699 /// location for "probing" purposes.
4701 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4702 /// that is the best match of me on Arguments.
4704 /// </summary>
4705 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4706 ArrayList Arguments, bool may_fail,
4707 Location loc)
4709 MethodBase method = null;
4710 bool method_params = false;
4711 Type applicable_type = null;
4712 int arg_count = 0;
4713 ArrayList candidates = new ArrayList ();
4716 // Used to keep a map between the candidate
4717 // and whether it is being considered in its
4718 // normal or expanded form
4720 // false is normal form, true is expanded form
4722 Hashtable candidate_to_form = null;
4724 if (Arguments != null)
4725 arg_count = Arguments.Count;
4727 if ((me.Name == "Invoke") &&
4728 TypeManager.IsDelegateType (me.DeclaringType)) {
4729 Error_InvokeOnDelegate (loc);
4730 return null;
4733 MethodBase[] methods = me.Methods;
4736 // First we construct the set of applicable methods
4738 bool is_sorted = true;
4739 for (int i = 0; i < methods.Length; i++){
4740 Type decl_type = methods [i].DeclaringType;
4743 // If we have already found an applicable method
4744 // we eliminate all base types (Section 14.5.5.1)
4746 if ((applicable_type != null) &&
4747 IsAncestralType (decl_type, applicable_type))
4748 continue;
4751 // Check if candidate is applicable (section 14.4.2.1)
4752 // Is candidate applicable in normal form?
4754 bool is_applicable = IsApplicable (
4755 ec, me, Arguments, arg_count, ref methods [i]);
4757 if (!is_applicable &&
4758 (IsParamsMethodApplicable (
4759 ec, me, Arguments, arg_count, ref methods [i]))) {
4760 MethodBase candidate = methods [i];
4761 if (candidate_to_form == null)
4762 candidate_to_form = new PtrHashtable ();
4763 candidate_to_form [candidate] = candidate;
4764 // Candidate is applicable in expanded form
4765 is_applicable = true;
4768 if (!is_applicable)
4769 continue;
4771 candidates.Add (methods [i]);
4773 if (applicable_type == null)
4774 applicable_type = decl_type;
4775 else if (applicable_type != decl_type) {
4776 is_sorted = false;
4777 if (IsAncestralType (applicable_type, decl_type))
4778 applicable_type = decl_type;
4782 int candidate_top = candidates.Count;
4784 if (candidate_top == 0) {
4786 // Okay so we have failed to find anything so we
4787 // return by providing info about the closest match
4789 for (int i = 0; i < methods.Length; ++i) {
4790 MethodBase c = (MethodBase) methods [i];
4791 ParameterData pd = GetParameterData (c);
4793 if (pd.Count != arg_count)
4794 continue;
4796 VerifyArgumentsCompat (ec, Arguments, arg_count,
4797 c, false, null, may_fail, loc);
4798 break;
4801 if (!may_fail) {
4802 string report_name = me.Name;
4803 if (report_name == ".ctor")
4804 report_name = me.DeclaringType.ToString ();
4806 Error_WrongNumArguments (
4807 loc, report_name, arg_count);
4808 return null;
4811 return null;
4814 if (!is_sorted) {
4816 // At this point, applicable_type is _one_ of the most derived types
4817 // in the set of types containing the methods in this MethodGroup.
4818 // Filter the candidates so that they only contain methods from the
4819 // most derived types.
4822 int finalized = 0; // Number of finalized candidates
4824 do {
4825 // Invariant: applicable_type is a most derived type
4827 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4828 // eliminating all it's base types. At the same time, we'll also move
4829 // every unrelated type to the end of the array, and pick the next
4830 // 'applicable_type'.
4832 Type next_applicable_type = null;
4833 int j = finalized; // where to put the next finalized candidate
4834 int k = finalized; // where to put the next undiscarded candidate
4835 for (int i = finalized; i < candidate_top; ++i) {
4836 Type decl_type = ((MethodBase) candidates[i]).DeclaringType;
4838 if (decl_type == applicable_type) {
4839 candidates[k++] = candidates[j];
4840 candidates[j++] = candidates[i];
4841 continue;
4844 if (IsAncestralType (decl_type, applicable_type))
4845 continue;
4847 if (next_applicable_type != null &&
4848 IsAncestralType (decl_type, next_applicable_type))
4849 continue;
4851 candidates[k++] = candidates[i];
4853 if (next_applicable_type == null ||
4854 IsAncestralType (next_applicable_type, decl_type))
4855 next_applicable_type = decl_type;
4858 applicable_type = next_applicable_type;
4859 finalized = j;
4860 candidate_top = k;
4861 } while (applicable_type != null);
4865 // Now we actually find the best method
4868 method = (MethodBase) candidates[0];
4869 method_params = candidate_to_form != null && candidate_to_form.Contains (method);
4870 for (int ix = 1; ix < candidate_top; ix++){
4871 MethodBase candidate = (MethodBase) candidates [ix];
4872 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4874 if (BetterFunction (ec, Arguments, arg_count,
4875 candidate, cand_params,
4876 method, method_params, loc)) {
4877 method = candidate;
4878 method_params = cand_params;
4883 // Now check that there are no ambiguities i.e the selected method
4884 // should be better than all the others
4886 bool ambiguous = false;
4887 for (int ix = 0; ix < candidate_top; ix++){
4888 MethodBase candidate = (MethodBase) candidates [ix];
4890 if (candidate == method)
4891 continue;
4893 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4894 if (!BetterFunction (ec, Arguments, arg_count,
4895 method, method_params,
4896 candidate, cand_params,
4897 loc)) {
4898 Report.SymbolRelatedToPreviousError (candidate);
4899 ambiguous = true;
4903 if (ambiguous) {
4904 Report.SymbolRelatedToPreviousError (method);
4905 Report.Error (121, loc, "Ambiguous call when selecting function due to implicit casts");
4906 return null;
4911 // And now check if the arguments are all
4912 // compatible, perform conversions if
4913 // necessary etc. and return if everything is
4914 // all right
4916 if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method,
4917 method_params, null, may_fail, loc))
4918 return null;
4920 return method;
4923 static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4925 Report.Error (1501, loc,
4926 "No overload for method `" + name + "' takes `" +
4927 arg_count + "' arguments");
4930 static void Error_InvokeOnDelegate (Location loc)
4932 Report.Error (1533, loc,
4933 "Invoke cannot be called directly on a delegate");
4936 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4937 Type delegate_type, string arg_sig, string par_desc)
4939 if (delegate_type == null)
4940 Report.Error (1502, loc,
4941 "The best overloaded match for method '" +
4942 FullMethodDesc (method) +
4943 "' has some invalid arguments");
4944 else
4945 Report.Error (1594, loc,
4946 "Delegate '" + delegate_type.ToString () +
4947 "' has some invalid arguments.");
4948 Report.Error (1503, loc,
4949 String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
4950 idx, arg_sig, par_desc));
4953 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4954 int arg_count, MethodBase method,
4955 bool chose_params_expanded,
4956 Type delegate_type, bool may_fail,
4957 Location loc)
4959 ParameterData pd = GetParameterData (method);
4960 int pd_count = pd.Count;
4962 for (int j = 0; j < arg_count; j++) {
4963 Argument a = (Argument) Arguments [j];
4964 Expression a_expr = a.Expr;
4965 Type parameter_type = pd.ParameterType (j);
4966 Parameter.Modifier pm = pd.ParameterModifier (j);
4968 if (pm == Parameter.Modifier.PARAMS){
4969 if ((pm & ~Parameter.Modifier.PARAMS) != a.GetParameterModifier ()) {
4970 if (!may_fail)
4971 Error_InvalidArguments (
4972 loc, j, method, delegate_type,
4973 Argument.FullDesc (a), pd.ParameterDesc (j));
4974 return false;
4977 if (chose_params_expanded)
4978 parameter_type = TypeManager.GetElementType (parameter_type);
4979 } else if (pm == Parameter.Modifier.ARGLIST){
4980 continue;
4981 } else {
4983 // Check modifiers
4985 if (pd.ParameterModifier (j) != a.GetParameterModifier ()){
4986 if (!may_fail)
4987 Error_InvalidArguments (
4988 loc, j, method, delegate_type,
4989 Argument.FullDesc (a), pd.ParameterDesc (j));
4990 return false;
4995 // Check Type
4997 if (!a.Type.Equals (parameter_type)){
4998 Expression conv;
5000 conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
5002 if (conv == null) {
5003 if (!may_fail)
5004 Error_InvalidArguments (
5005 loc, j, method, delegate_type,
5006 Argument.FullDesc (a), pd.ParameterDesc (j));
5007 return false;
5011 // Update the argument with the implicit conversion
5013 if (a_expr != conv)
5014 a.Expr = conv;
5017 if (parameter_type.IsPointer){
5018 if (!ec.InUnsafe){
5019 UnsafeError (loc);
5020 return false;
5024 Parameter.Modifier a_mod = a.GetParameterModifier () &
5025 unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5026 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
5027 unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5029 if (a_mod != p_mod &&
5030 pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
5031 if (!may_fail) {
5032 Report.Error (1502, loc,
5033 "The best overloaded match for method '" + FullMethodDesc (method)+
5034 "' has some invalid arguments");
5035 Report.Error (1503, loc,
5036 "Argument " + (j+1) +
5037 ": Cannot convert from '" + Argument.FullDesc (a)
5038 + "' to '" + pd.ParameterDesc (j) + "'");
5041 return false;
5045 return true;
5048 public override Expression DoResolve (EmitContext ec)
5051 // First, resolve the expression that is used to
5052 // trigger the invocation
5054 expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5055 if (expr == null)
5056 return null;
5058 if (!(expr is MethodGroupExpr)) {
5059 Type expr_type = expr.Type;
5061 if (expr_type != null){
5062 bool IsDelegate = TypeManager.IsDelegateType (expr_type);
5063 if (IsDelegate)
5064 return (new DelegateInvocation (
5065 this.expr, Arguments, loc)).Resolve (ec);
5069 if (!(expr is MethodGroupExpr)){
5070 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
5071 return null;
5075 // Next, evaluate all the expressions in the argument list
5077 if (Arguments != null){
5078 foreach (Argument a in Arguments){
5079 if (!a.Resolve (ec, loc))
5080 return null;
5084 MethodGroupExpr mg = (MethodGroupExpr) expr;
5085 method = OverloadResolve (ec, mg, Arguments, false, loc);
5087 if (method == null)
5088 return null;
5090 MethodInfo mi = method as MethodInfo;
5091 if (mi != null) {
5092 type = TypeManager.TypeToCoreType (mi.ReturnType);
5093 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null)) {
5094 SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
5095 return null;
5098 Expression iexpr = mg.InstanceExpression;
5099 if (mi.IsStatic && (iexpr != null) && !(iexpr is This)) {
5100 if (mg.IdenticalTypeName)
5101 mg.InstanceExpression = null;
5102 else {
5103 MemberAccess.error176 (loc, mi.Name);
5104 return null;
5109 if (type.IsPointer){
5110 if (!ec.InUnsafe){
5111 UnsafeError (loc);
5112 return null;
5117 // Only base will allow this invocation to happen.
5119 if (mg.IsBase && method.IsAbstract){
5120 Report.Error (205, loc, "Cannot call an abstract base member: " +
5121 FullMethodDesc (method));
5122 return null;
5125 if (method.Name == "Finalize" && Arguments == null) {
5126 if (mg.IsBase)
5127 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5128 else
5129 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5130 return null;
5133 if ((method.Attributes & MethodAttributes.SpecialName) != 0) {
5134 if (TypeManager.LookupDeclSpace (method.DeclaringType) != null || TypeManager.IsSpecialMethod (method)) {
5135 Report.Error (571, loc, TypeManager.CSharpSignature (method) + ": can not call operator or accessor");
5136 return null;
5140 eclass = ExprClass.Value;
5141 return this;
5144 // <summary>
5145 // Emits the list of arguments as an array
5146 // </summary>
5147 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
5149 ILGenerator ig = ec.ig;
5150 int count = arguments.Count - idx;
5151 Argument a = (Argument) arguments [idx];
5152 Type t = a.Expr.Type;
5154 IntConstant.EmitInt (ig, count);
5155 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5157 int top = arguments.Count;
5158 for (int j = idx; j < top; j++){
5159 a = (Argument) arguments [j];
5161 ig.Emit (OpCodes.Dup);
5162 IntConstant.EmitInt (ig, j - idx);
5164 bool is_stobj;
5165 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj);
5166 if (is_stobj)
5167 ig.Emit (OpCodes.Ldelema, t);
5169 a.Emit (ec);
5171 if (is_stobj)
5172 ig.Emit (OpCodes.Stobj, t);
5173 else
5174 ig.Emit (op);
5178 /// <summary>
5179 /// Emits a list of resolved Arguments that are in the arguments
5180 /// ArrayList.
5181 ///
5182 /// The MethodBase argument might be null if the
5183 /// emission of the arguments is known not to contain
5184 /// a `params' field (for example in constructors or other routines
5185 /// that keep their arguments in this structure)
5186 ///
5187 /// if `dup_args' is true, a copy of the arguments will be left
5188 /// on the stack. If `dup_args' is true, you can specify `this_arg'
5189 /// which will be duplicated before any other args. Only EmitCall
5190 /// should be using this interface.
5191 /// </summary>
5192 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
5194 ParameterData pd;
5195 if (mb != null)
5196 pd = GetParameterData (mb);
5197 else
5198 pd = null;
5200 LocalTemporary [] temps = null;
5202 if (dup_args)
5203 temps = new LocalTemporary [arguments.Count];
5206 // If we are calling a params method with no arguments, special case it
5208 if (arguments == null){
5209 if (pd != null && pd.Count > 0 &&
5210 pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
5211 ILGenerator ig = ec.ig;
5213 IntConstant.EmitInt (ig, 0);
5214 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0)));
5217 return;
5220 int top = arguments.Count;
5222 for (int i = 0; i < top; i++){
5223 Argument a = (Argument) arguments [i];
5225 if (pd != null){
5226 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5228 // Special case if we are passing the same data as the
5229 // params argument, do not put it in an array.
5231 if (pd.ParameterType (i) == a.Type)
5232 a.Emit (ec);
5233 else
5234 EmitParams (ec, i, arguments);
5235 return;
5239 a.Emit (ec);
5240 if (dup_args) {
5241 ec.ig.Emit (OpCodes.Dup);
5242 (temps [i] = new LocalTemporary (ec, a.Type)).Store (ec);
5246 if (dup_args) {
5247 if (this_arg != null)
5248 this_arg.Emit (ec);
5250 for (int i = 0; i < top; i ++)
5251 temps [i].Emit (ec);
5254 if (pd != null && pd.Count > top &&
5255 pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
5256 ILGenerator ig = ec.ig;
5258 IntConstant.EmitInt (ig, 0);
5259 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
5263 static Type[] GetVarargsTypes (EmitContext ec, MethodBase mb,
5264 ArrayList arguments)
5266 ParameterData pd = GetParameterData (mb);
5268 if (arguments == null)
5269 return new Type [0];
5271 Argument a = (Argument) arguments [pd.Count - 1];
5272 Arglist list = (Arglist) a.Expr;
5274 return list.ArgumentTypes;
5277 /// <summary>
5278 /// This checks the ConditionalAttribute on the method
5279 /// </summary>
5280 static bool IsMethodExcluded (MethodBase method, EmitContext ec)
5282 if (method.IsConstructor)
5283 return false;
5285 IMethodData md = TypeManager.GetMethod (method);
5286 if (md != null)
5287 return md.IsExcluded (ec);
5289 // For some methods (generated by delegate class) GetMethod returns null
5290 // because they are not included in builder_to_method table
5291 if (method.DeclaringType is TypeBuilder)
5292 return false;
5294 return AttributeTester.IsConditionalMethodExcluded (method);
5297 /// <remarks>
5298 /// is_base tells whether we want to force the use of the `call'
5299 /// opcode instead of using callvirt. Call is required to call
5300 /// a specific method, while callvirt will always use the most
5301 /// recent method in the vtable.
5303 /// is_static tells whether this is an invocation on a static method
5305 /// instance_expr is an expression that represents the instance
5306 /// it must be non-null if is_static is false.
5308 /// method is the method to invoke.
5310 /// Arguments is the list of arguments to pass to the method or constructor.
5311 /// </remarks>
5312 public static void EmitCall (EmitContext ec, bool is_base,
5313 bool is_static, Expression instance_expr,
5314 MethodBase method, ArrayList Arguments, Location loc)
5316 EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
5319 // `dup_args' leaves an extra copy of the arguments on the stack
5320 // `omit_args' does not leave any arguments at all.
5321 // So, basically, you could make one call with `dup_args' set to true,
5322 // and then another with `omit_args' set to true, and the two calls
5323 // would have the same set of arguments. However, each argument would
5324 // only have been evaluated once.
5325 public static void EmitCall (EmitContext ec, bool is_base,
5326 bool is_static, Expression instance_expr,
5327 MethodBase method, ArrayList Arguments, Location loc,
5328 bool dup_args, bool omit_args)
5330 ILGenerator ig = ec.ig;
5331 bool struct_call = false;
5332 bool this_call = false;
5333 LocalTemporary this_arg = null;
5335 Type decl_type = method.DeclaringType;
5337 if (!RootContext.StdLib) {
5338 // Replace any calls to the system's System.Array type with calls to
5339 // the newly created one.
5340 if (method == TypeManager.system_int_array_get_length)
5341 method = TypeManager.int_array_get_length;
5342 else if (method == TypeManager.system_int_array_get_rank)
5343 method = TypeManager.int_array_get_rank;
5344 else if (method == TypeManager.system_object_array_clone)
5345 method = TypeManager.object_array_clone;
5346 else if (method == TypeManager.system_int_array_get_length_int)
5347 method = TypeManager.int_array_get_length_int;
5348 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5349 method = TypeManager.int_array_get_lower_bound_int;
5350 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5351 method = TypeManager.int_array_get_upper_bound_int;
5352 else if (method == TypeManager.system_void_array_copyto_array_int)
5353 method = TypeManager.void_array_copyto_array_int;
5356 if (ec.TestObsoleteMethodUsage) {
5358 // This checks ObsoleteAttribute on the method and on the declaring type
5360 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
5361 if (oa != null)
5362 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
5365 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5366 if (oa != null) {
5367 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5371 if (IsMethodExcluded (method, ec))
5372 return;
5374 if (!is_static){
5375 this_call = instance_expr == null;
5376 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5377 struct_call = true;
5380 // If this is ourselves, push "this"
5382 if (!omit_args) {
5383 Type t = null;
5384 if (this_call) {
5385 ig.Emit (OpCodes.Ldarg_0);
5386 t = decl_type;
5387 } else {
5389 // Push the instance expression
5391 if (instance_expr.Type.IsValueType) {
5393 // Special case: calls to a function declared in a
5394 // reference-type with a value-type argument need
5395 // to have their value boxed.
5396 if (decl_type.IsValueType) {
5398 // If the expression implements IMemoryLocation, then
5399 // we can optimize and use AddressOf on the
5400 // return.
5402 // If not we have to use some temporary storage for
5403 // it.
5404 if (instance_expr is IMemoryLocation) {
5405 ((IMemoryLocation)instance_expr).
5406 AddressOf (ec, AddressOp.LoadStore);
5407 } else {
5408 LocalTemporary temp = new LocalTemporary (ec, instance_expr.Type);
5409 instance_expr.Emit (ec);
5410 temp.Store (ec);
5411 temp.AddressOf (ec, AddressOp.Load);
5414 // avoid the overhead of doing this all the time.
5415 if (dup_args)
5416 t = TypeManager.GetReferenceType (instance_expr.Type);
5417 } else {
5418 instance_expr.Emit (ec);
5419 ig.Emit (OpCodes.Box, instance_expr.Type);
5420 t = TypeManager.object_type;
5422 } else {
5423 instance_expr.Emit (ec);
5424 t = instance_expr.Type;
5428 if (dup_args) {
5429 this_arg = new LocalTemporary (ec, t);
5430 ig.Emit (OpCodes.Dup);
5431 this_arg.Store (ec);
5436 if (!omit_args)
5437 EmitArguments (ec, method, Arguments, dup_args, this_arg);
5439 OpCode call_op;
5440 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5441 call_op = OpCodes.Call;
5442 else
5443 call_op = OpCodes.Callvirt;
5445 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5446 Type[] varargs_types = GetVarargsTypes (ec, method, Arguments);
5447 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5448 return;
5452 // If you have:
5453 // this.DoFoo ();
5454 // and DoFoo is not virtual, you can omit the callvirt,
5455 // because you don't need the null checking behavior.
5457 if (method is MethodInfo)
5458 ig.Emit (call_op, (MethodInfo) method);
5459 else
5460 ig.Emit (call_op, (ConstructorInfo) method);
5463 public override void Emit (EmitContext ec)
5465 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5467 EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5470 public override void EmitStatement (EmitContext ec)
5472 Emit (ec);
5475 // Pop the return value if there is one
5477 if (method is MethodInfo){
5478 Type ret = ((MethodInfo)method).ReturnType;
5479 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5480 ec.ig.Emit (OpCodes.Pop);
5485 public class InvocationOrCast : ExpressionStatement
5487 Expression expr;
5488 Expression argument;
5490 public InvocationOrCast (Expression expr, Expression argument, Location loc)
5492 this.expr = expr;
5493 this.argument = argument;
5494 this.loc = loc;
5497 public override Expression DoResolve (EmitContext ec)
5500 // First try to resolve it as a cast.
5502 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5503 if (te != null) {
5504 Cast cast = new Cast (te, argument, loc);
5505 return cast.Resolve (ec);
5509 // This can either be a type or a delegate invocation.
5510 // Let's just resolve it and see what we'll get.
5512 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5513 if (expr == null)
5514 return null;
5517 // Ok, so it's a Cast.
5519 if (expr.eclass == ExprClass.Type) {
5520 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5521 return cast.Resolve (ec);
5525 // It's a delegate invocation.
5527 if (!TypeManager.IsDelegateType (expr.Type)) {
5528 Error (149, "Method name expected");
5529 return null;
5532 ArrayList args = new ArrayList ();
5533 args.Add (new Argument (argument, Argument.AType.Expression));
5534 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5535 return invocation.Resolve (ec);
5538 void error201 ()
5540 Error (201, "Only assignment, call, increment, decrement and new object " +
5541 "expressions can be used as a statement");
5544 public override ExpressionStatement ResolveStatement (EmitContext ec)
5547 // First try to resolve it as a cast.
5549 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5550 if (te != null) {
5551 error201 ();
5552 return null;
5556 // This can either be a type or a delegate invocation.
5557 // Let's just resolve it and see what we'll get.
5559 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5560 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5561 error201 ();
5562 return null;
5566 // It's a delegate invocation.
5568 if (!TypeManager.IsDelegateType (expr.Type)) {
5569 Error (149, "Method name expected");
5570 return null;
5573 ArrayList args = new ArrayList ();
5574 args.Add (new Argument (argument, Argument.AType.Expression));
5575 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5576 return invocation.ResolveStatement (ec);
5579 public override void Emit (EmitContext ec)
5581 throw new Exception ("Cannot happen");
5584 public override void EmitStatement (EmitContext ec)
5586 throw new Exception ("Cannot happen");
5591 // This class is used to "disable" the code generation for the
5592 // temporary variable when initializing value types.
5594 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5595 public void AddressOf (EmitContext ec, AddressOp Mode)
5597 // nothing
5601 /// <summary>
5602 /// Implements the new expression
5603 /// </summary>
5604 public class New : ExpressionStatement, IMemoryLocation {
5605 public readonly ArrayList Arguments;
5608 // During bootstrap, it contains the RequestedType,
5609 // but if `type' is not null, it *might* contain a NewDelegate
5610 // (because of field multi-initialization)
5612 public Expression RequestedType;
5614 MethodBase method = null;
5617 // If set, the new expression is for a value_target, and
5618 // we will not leave anything on the stack.
5620 Expression value_target;
5621 bool value_target_set = false;
5623 public New (Expression requested_type, ArrayList arguments, Location l)
5625 RequestedType = requested_type;
5626 Arguments = arguments;
5627 loc = l;
5630 public bool SetValueTypeVariable (Expression value)
5632 value_target = value;
5633 value_target_set = true;
5634 if (!(value_target is IMemoryLocation)){
5635 Error_UnexpectedKind ("variable", loc);
5636 return false;
5638 return true;
5642 // This function is used to disable the following code sequence for
5643 // value type initialization:
5645 // AddressOf (temporary)
5646 // Construct/Init
5647 // LoadTemporary
5649 // Instead the provide will have provided us with the address on the
5650 // stack to store the results.
5652 static Expression MyEmptyExpression;
5654 public void DisableTemporaryValueType ()
5656 if (MyEmptyExpression == null)
5657 MyEmptyExpression = new EmptyAddressOf ();
5660 // To enable this, look into:
5661 // test-34 and test-89 and self bootstrapping.
5663 // For instance, we can avoid a copy by using `newobj'
5664 // instead of Call + Push-temp on value types.
5665 // value_target = MyEmptyExpression;
5668 public override Expression DoResolve (EmitContext ec)
5671 // The New DoResolve might be called twice when initializing field
5672 // expressions (see EmitFieldInitializers, the call to
5673 // GetInitializerExpression will perform a resolve on the expression,
5674 // and later the assign will trigger another resolution
5676 // This leads to bugs (#37014)
5678 if (type != null){
5679 if (RequestedType is NewDelegate)
5680 return RequestedType;
5681 return this;
5684 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5685 if (texpr == null)
5686 return null;
5688 type = texpr.ResolveType (ec);
5690 CheckObsoleteAttribute (type);
5692 bool IsDelegate = TypeManager.IsDelegateType (type);
5694 if (IsDelegate){
5695 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5696 if (RequestedType != null)
5697 if (!(RequestedType is NewDelegate))
5698 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5699 return RequestedType;
5702 if (type.IsAbstract && type.IsSealed) {
5703 Report.Error (712, loc, "Cannot create an instance of the static class '{0}'", TypeManager.CSharpName (type));
5704 return null;
5707 if (type.IsInterface || type.IsAbstract){
5708 Error (144, "It is not possible to create instances of interfaces or abstract classes");
5709 return null;
5712 bool is_struct = type.IsValueType;
5713 eclass = ExprClass.Value;
5716 // SRE returns a match for .ctor () on structs (the object constructor),
5717 // so we have to manually ignore it.
5719 if (is_struct && Arguments == null)
5720 return this;
5722 Expression ml;
5723 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5724 ml = MemberLookupFinal (ec, type, type, ".ctor",
5725 MemberTypes.Constructor,
5726 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5728 if (ml == null)
5729 return null;
5731 if (! (ml is MethodGroupExpr)){
5732 if (!is_struct){
5733 ml.Error_UnexpectedKind ("method group", loc);
5734 return null;
5738 if (ml != null) {
5739 if (Arguments != null){
5740 foreach (Argument a in Arguments){
5741 if (!a.Resolve (ec, loc))
5742 return null;
5746 method = Invocation.OverloadResolve (
5747 ec, (MethodGroupExpr) ml, Arguments, false, loc);
5751 if (method == null) {
5752 if (!is_struct || Arguments.Count > 0) {
5753 Error (1501, String.Format (
5754 "New invocation: Can not find a constructor in `{0}' for this argument list",
5755 TypeManager.CSharpName (type)));
5756 return null;
5760 return this;
5764 // This DoEmit can be invoked in two contexts:
5765 // * As a mechanism that will leave a value on the stack (new object)
5766 // * As one that wont (init struct)
5768 // You can control whether a value is required on the stack by passing
5769 // need_value_on_stack. The code *might* leave a value on the stack
5770 // so it must be popped manually
5772 // If we are dealing with a ValueType, we have a few
5773 // situations to deal with:
5775 // * The target is a ValueType, and we have been provided
5776 // the instance (this is easy, we are being assigned).
5778 // * The target of New is being passed as an argument,
5779 // to a boxing operation or a function that takes a
5780 // ValueType.
5782 // In this case, we need to create a temporary variable
5783 // that is the argument of New.
5785 // Returns whether a value is left on the stack
5787 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5789 bool is_value_type = type.IsValueType;
5790 ILGenerator ig = ec.ig;
5792 if (is_value_type){
5793 IMemoryLocation ml;
5795 // Allow DoEmit() to be called multiple times.
5796 // We need to create a new LocalTemporary each time since
5797 // you can't share LocalBuilders among ILGeneators.
5798 if (!value_target_set)
5799 value_target = new LocalTemporary (ec, type);
5801 ml = (IMemoryLocation) value_target;
5802 ml.AddressOf (ec, AddressOp.Store);
5805 if (method != null)
5806 Invocation.EmitArguments (ec, method, Arguments, false, null);
5808 if (is_value_type){
5809 if (method == null)
5810 ig.Emit (OpCodes.Initobj, type);
5811 else
5812 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5813 if (need_value_on_stack){
5814 value_target.Emit (ec);
5815 return true;
5817 return false;
5818 } else {
5819 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5820 return true;
5824 public override void Emit (EmitContext ec)
5826 DoEmit (ec, true);
5829 public override void EmitStatement (EmitContext ec)
5831 if (DoEmit (ec, false))
5832 ec.ig.Emit (OpCodes.Pop);
5835 public void AddressOf (EmitContext ec, AddressOp Mode)
5837 if (!type.IsValueType){
5839 // We throw an exception. So far, I believe we only need to support
5840 // value types:
5841 // foreach (int j in new StructType ())
5842 // see bug 42390
5844 throw new Exception ("AddressOf should not be used for classes");
5847 if (!value_target_set)
5848 value_target = new LocalTemporary (ec, type);
5850 IMemoryLocation ml = (IMemoryLocation) value_target;
5851 ml.AddressOf (ec, AddressOp.Store);
5852 if (method != null)
5853 Invocation.EmitArguments (ec, method, Arguments, false, null);
5855 if (method == null)
5856 ec.ig.Emit (OpCodes.Initobj, type);
5857 else
5858 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5860 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5864 /// <summary>
5865 /// 14.5.10.2: Represents an array creation expression.
5866 /// </summary>
5868 /// <remarks>
5869 /// There are two possible scenarios here: one is an array creation
5870 /// expression that specifies the dimensions and optionally the
5871 /// initialization data and the other which does not need dimensions
5872 /// specified but where initialization data is mandatory.
5873 /// </remarks>
5874 public class ArrayCreation : Expression {
5875 Expression requested_base_type;
5876 ArrayList initializers;
5879 // The list of Argument types.
5880 // This is used to construct the `newarray' or constructor signature
5882 ArrayList arguments;
5885 // Method used to create the array object.
5887 MethodBase new_method = null;
5889 Type array_element_type;
5890 Type underlying_type;
5891 bool is_one_dimensional = false;
5892 bool is_builtin_type = false;
5893 bool expect_initializers = false;
5894 int num_arguments = 0;
5895 int dimensions = 0;
5896 string rank;
5898 ArrayList array_data;
5900 Hashtable bounds;
5903 // The number of array initializers that we can handle
5904 // via the InitializeArray method - through EmitStaticInitializers
5906 int num_automatic_initializers;
5908 const int max_automatic_initializers = 6;
5910 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5912 this.requested_base_type = requested_base_type;
5913 this.initializers = initializers;
5914 this.rank = rank;
5915 loc = l;
5917 arguments = new ArrayList ();
5919 foreach (Expression e in exprs) {
5920 arguments.Add (new Argument (e, Argument.AType.Expression));
5921 num_arguments++;
5925 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5927 this.requested_base_type = requested_base_type;
5928 this.initializers = initializers;
5929 this.rank = rank;
5930 loc = l;
5932 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5934 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5936 //dimensions = tmp.Length - 1;
5937 expect_initializers = true;
5940 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5942 StringBuilder sb = new StringBuilder (rank);
5944 sb.Append ("[");
5945 for (int i = 1; i < idx_count; i++)
5946 sb.Append (",");
5948 sb.Append ("]");
5950 return new ComposedCast (base_type, sb.ToString (), loc);
5953 void Error_IncorrectArrayInitializer ()
5955 Error (178, "Incorrectly structured array initializer");
5958 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5960 if (specified_dims) {
5961 Argument a = (Argument) arguments [idx];
5963 if (!a.Resolve (ec, loc))
5964 return false;
5966 if (!(a.Expr is Constant)) {
5967 Error (150, "A constant value is expected");
5968 return false;
5971 int value = (int) ((Constant) a.Expr).GetValue ();
5973 if (value != probe.Count) {
5974 Error_IncorrectArrayInitializer ();
5975 return false;
5978 bounds [idx] = value;
5981 int child_bounds = -1;
5982 foreach (object o in probe) {
5983 if (o is ArrayList) {
5984 int current_bounds = ((ArrayList) o).Count;
5986 if (child_bounds == -1)
5987 child_bounds = current_bounds;
5989 else if (child_bounds != current_bounds){
5990 Error_IncorrectArrayInitializer ();
5991 return false;
5993 if (specified_dims && (idx + 1 >= arguments.Count)){
5994 Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
5995 return false;
5998 bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
5999 if (!ret)
6000 return false;
6001 } else {
6002 if (child_bounds != -1){
6003 Error_IncorrectArrayInitializer ();
6004 return false;
6007 Expression tmp = (Expression) o;
6008 tmp = tmp.Resolve (ec);
6009 if (tmp == null)
6010 return false;
6012 // Console.WriteLine ("I got: " + tmp);
6013 // Handle initialization from vars, fields etc.
6015 Expression conv = Convert.ImplicitConversionRequired (
6016 ec, tmp, underlying_type, loc);
6018 if (conv == null)
6019 return false;
6021 if (conv is StringConstant || conv is DecimalConstant || conv is NullCast) {
6022 // These are subclasses of Constant that can appear as elements of an
6023 // array that cannot be statically initialized (with num_automatic_initializers
6024 // > max_automatic_initializers), so num_automatic_initializers should be left as zero.
6025 array_data.Add (conv);
6026 } else if (conv is Constant) {
6027 // These are the types of Constant that can appear in arrays that can be
6028 // statically allocated.
6029 array_data.Add (conv);
6030 num_automatic_initializers++;
6031 } else
6032 array_data.Add (conv);
6036 return true;
6039 public void UpdateIndices (EmitContext ec)
6041 int i = 0;
6042 for (ArrayList probe = initializers; probe != null;) {
6043 if (probe.Count > 0 && probe [0] is ArrayList) {
6044 Expression e = new IntConstant (probe.Count);
6045 arguments.Add (new Argument (e, Argument.AType.Expression));
6047 bounds [i++] = probe.Count;
6049 probe = (ArrayList) probe [0];
6051 } else {
6052 Expression e = new IntConstant (probe.Count);
6053 arguments.Add (new Argument (e, Argument.AType.Expression));
6055 bounds [i++] = probe.Count;
6056 probe = null;
6062 public bool ValidateInitializers (EmitContext ec, Type array_type)
6064 if (initializers == null) {
6065 if (expect_initializers)
6066 return false;
6067 else
6068 return true;
6071 if (underlying_type == null)
6072 return false;
6075 // We use this to store all the date values in the order in which we
6076 // will need to store them in the byte blob later
6078 array_data = new ArrayList ();
6079 bounds = new Hashtable ();
6081 bool ret;
6083 if (arguments != null) {
6084 ret = CheckIndices (ec, initializers, 0, true);
6085 return ret;
6086 } else {
6087 arguments = new ArrayList ();
6089 ret = CheckIndices (ec, initializers, 0, false);
6091 if (!ret)
6092 return false;
6094 UpdateIndices (ec);
6096 if (arguments.Count != dimensions) {
6097 Error_IncorrectArrayInitializer ();
6098 return false;
6101 return ret;
6106 // Converts `source' to an int, uint, long or ulong.
6108 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
6110 Expression target;
6112 bool old_checked = ec.CheckState;
6113 ec.CheckState = true;
6115 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
6116 if (target == null){
6117 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
6118 if (target == null){
6119 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
6120 if (target == null){
6121 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
6122 if (target == null)
6123 Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type);
6127 ec.CheckState = old_checked;
6130 // Only positive constants are allowed at compile time
6132 if (target is Constant){
6133 if (target is IntConstant){
6134 if (((IntConstant) target).Value < 0){
6135 Expression.Error_NegativeArrayIndex (loc);
6136 return null;
6140 if (target is LongConstant){
6141 if (((LongConstant) target).Value < 0){
6142 Expression.Error_NegativeArrayIndex (loc);
6143 return null;
6149 return target;
6153 // Creates the type of the array
6155 bool LookupType (EmitContext ec)
6157 StringBuilder array_qualifier = new StringBuilder (rank);
6160 // `In the first form allocates an array instace of the type that results
6161 // from deleting each of the individual expression from the expression list'
6163 if (num_arguments > 0) {
6164 array_qualifier.Append ("[");
6165 for (int i = num_arguments-1; i > 0; i--)
6166 array_qualifier.Append (",");
6167 array_qualifier.Append ("]");
6171 // Lookup the type
6173 TypeExpr array_type_expr;
6174 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6175 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6176 if (array_type_expr == null)
6177 return false;
6179 type = array_type_expr.ResolveType (ec);
6181 if (!type.IsArray) {
6182 Error (622, "Can only use array initializer expressions to assign to array types. Try using a new expression instead.");
6183 return false;
6185 underlying_type = TypeManager.GetElementType (type);
6186 dimensions = type.GetArrayRank ();
6188 return true;
6191 public override Expression DoResolve (EmitContext ec)
6193 int arg_count;
6195 if (!LookupType (ec))
6196 return null;
6199 // First step is to validate the initializers and fill
6200 // in any missing bits
6202 if (!ValidateInitializers (ec, type))
6203 return null;
6205 if (arguments == null)
6206 arg_count = 0;
6207 else {
6208 arg_count = arguments.Count;
6209 foreach (Argument a in arguments){
6210 if (!a.Resolve (ec, loc))
6211 return null;
6213 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6214 if (real_arg == null)
6215 return null;
6217 a.Expr = real_arg;
6221 array_element_type = TypeManager.GetElementType (type);
6223 if (array_element_type.IsAbstract && array_element_type.IsSealed) {
6224 Report.Error (719, loc, "'{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
6225 return null;
6228 if (arg_count == 1) {
6229 is_one_dimensional = true;
6230 eclass = ExprClass.Value;
6231 return this;
6234 is_builtin_type = TypeManager.IsBuiltinType (type);
6236 if (is_builtin_type) {
6237 Expression ml;
6239 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
6240 AllBindingFlags, loc);
6242 if (!(ml is MethodGroupExpr)) {
6243 ml.Error_UnexpectedKind ("method group", loc);
6244 return null;
6247 if (ml == null) {
6248 Error (-6, "New invocation: Can not find a constructor for " +
6249 "this argument list");
6250 return null;
6253 new_method = Invocation.OverloadResolve (
6254 ec, (MethodGroupExpr) ml, arguments, false, loc);
6256 if (new_method == null) {
6257 Error (-6, "New invocation: Can not find a constructor for " +
6258 "this argument list");
6259 return null;
6262 eclass = ExprClass.Value;
6263 return this;
6264 } else {
6265 ModuleBuilder mb = CodeGen.Module.Builder;
6266 ArrayList args = new ArrayList ();
6268 if (arguments != null) {
6269 for (int i = 0; i < arg_count; i++)
6270 args.Add (TypeManager.int32_type);
6273 Type [] arg_types = null;
6275 if (args.Count > 0)
6276 arg_types = new Type [args.Count];
6278 args.CopyTo (arg_types, 0);
6280 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6281 arg_types);
6283 if (new_method == null) {
6284 Error (-6, "New invocation: Can not find a constructor for " +
6285 "this argument list");
6286 return null;
6289 eclass = ExprClass.Value;
6290 return this;
6294 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
6296 int factor;
6297 byte [] data;
6298 byte [] element;
6299 int count = array_data.Count;
6301 if (underlying_type.IsEnum)
6302 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6304 factor = GetTypeSize (underlying_type);
6305 if (factor == 0)
6306 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6308 data = new byte [(count * factor + 4) & ~3];
6309 int idx = 0;
6311 for (int i = 0; i < count; ++i) {
6312 object v = array_data [i];
6314 if (v is EnumConstant)
6315 v = ((EnumConstant) v).Child;
6317 if (v is Constant && !(v is StringConstant))
6318 v = ((Constant) v).GetValue ();
6319 else {
6320 idx += factor;
6321 continue;
6324 if (underlying_type == TypeManager.int64_type){
6325 if (!(v is Expression)){
6326 long val = (long) v;
6328 for (int j = 0; j < factor; ++j) {
6329 data [idx + j] = (byte) (val & 0xFF);
6330 val = (val >> 8);
6333 } else if (underlying_type == TypeManager.uint64_type){
6334 if (!(v is Expression)){
6335 ulong val = (ulong) v;
6337 for (int j = 0; j < factor; ++j) {
6338 data [idx + j] = (byte) (val & 0xFF);
6339 val = (val >> 8);
6342 } else if (underlying_type == TypeManager.float_type) {
6343 if (!(v is Expression)){
6344 element = BitConverter.GetBytes ((float) v);
6346 for (int j = 0; j < factor; ++j)
6347 data [idx + j] = element [j];
6349 } else if (underlying_type == TypeManager.double_type) {
6350 if (!(v is Expression)){
6351 element = BitConverter.GetBytes ((double) v);
6353 for (int j = 0; j < factor; ++j)
6354 data [idx + j] = element [j];
6356 } else if (underlying_type == TypeManager.char_type){
6357 if (!(v is Expression)){
6358 int val = (int) ((char) v);
6360 data [idx] = (byte) (val & 0xff);
6361 data [idx+1] = (byte) (val >> 8);
6363 } else if (underlying_type == TypeManager.short_type){
6364 if (!(v is Expression)){
6365 int val = (int) ((short) v);
6367 data [idx] = (byte) (val & 0xff);
6368 data [idx+1] = (byte) (val >> 8);
6370 } else if (underlying_type == TypeManager.ushort_type){
6371 if (!(v is Expression)){
6372 int val = (int) ((ushort) v);
6374 data [idx] = (byte) (val & 0xff);
6375 data [idx+1] = (byte) (val >> 8);
6377 } else if (underlying_type == TypeManager.int32_type) {
6378 if (!(v is Expression)){
6379 int val = (int) v;
6381 data [idx] = (byte) (val & 0xff);
6382 data [idx+1] = (byte) ((val >> 8) & 0xff);
6383 data [idx+2] = (byte) ((val >> 16) & 0xff);
6384 data [idx+3] = (byte) (val >> 24);
6386 } else if (underlying_type == TypeManager.uint32_type) {
6387 if (!(v is Expression)){
6388 uint val = (uint) v;
6390 data [idx] = (byte) (val & 0xff);
6391 data [idx+1] = (byte) ((val >> 8) & 0xff);
6392 data [idx+2] = (byte) ((val >> 16) & 0xff);
6393 data [idx+3] = (byte) (val >> 24);
6395 } else if (underlying_type == TypeManager.sbyte_type) {
6396 if (!(v is Expression)){
6397 sbyte val = (sbyte) v;
6398 data [idx] = (byte) val;
6400 } else if (underlying_type == TypeManager.byte_type) {
6401 if (!(v is Expression)){
6402 byte val = (byte) v;
6403 data [idx] = (byte) val;
6405 } else if (underlying_type == TypeManager.bool_type) {
6406 if (!(v is Expression)){
6407 bool val = (bool) v;
6408 data [idx] = (byte) (val ? 1 : 0);
6410 } else if (underlying_type == TypeManager.decimal_type){
6411 if (!(v is Expression)){
6412 int [] bits = Decimal.GetBits ((decimal) v);
6413 int p = idx;
6415 // FIXME: For some reason, this doesn't work on the MS runtime.
6416 int [] nbits = new int [4];
6417 nbits [0] = bits [3];
6418 nbits [1] = bits [2];
6419 nbits [2] = bits [0];
6420 nbits [3] = bits [1];
6422 for (int j = 0; j < 4; j++){
6423 data [p++] = (byte) (nbits [j] & 0xff);
6424 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6425 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6426 data [p++] = (byte) (nbits [j] >> 24);
6429 } else
6430 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6432 idx += factor;
6435 return data;
6439 // Emits the initializers for the array
6441 void EmitStaticInitializers (EmitContext ec)
6444 // First, the static data
6446 FieldBuilder fb;
6447 ILGenerator ig = ec.ig;
6449 byte [] data = MakeByteBlob (array_data, underlying_type, loc);
6451 fb = RootContext.MakeStaticData (data);
6453 ig.Emit (OpCodes.Dup);
6454 ig.Emit (OpCodes.Ldtoken, fb);
6455 ig.Emit (OpCodes.Call,
6456 TypeManager.void_initializearray_array_fieldhandle);
6460 // Emits pieces of the array that can not be computed at compile
6461 // time (variables and string locations).
6463 // This always expect the top value on the stack to be the array
6465 void EmitDynamicInitializers (EmitContext ec)
6467 ILGenerator ig = ec.ig;
6468 int dims = bounds.Count;
6469 int [] current_pos = new int [dims];
6470 int top = array_data.Count;
6472 MethodInfo set = null;
6474 if (dims != 1){
6475 Type [] args;
6476 ModuleBuilder mb = null;
6477 mb = CodeGen.Module.Builder;
6478 args = new Type [dims + 1];
6480 int j;
6481 for (j = 0; j < dims; j++)
6482 args [j] = TypeManager.int32_type;
6484 args [j] = array_element_type;
6486 set = mb.GetArrayMethod (
6487 type, "Set",
6488 CallingConventions.HasThis | CallingConventions.Standard,
6489 TypeManager.void_type, args);
6492 for (int i = 0; i < top; i++){
6494 Expression e = null;
6496 if (array_data [i] is Expression)
6497 e = (Expression) array_data [i];
6499 if (e != null) {
6501 // Basically we do this for string literals and
6502 // other non-literal expressions
6504 if (e is EnumConstant){
6505 e = ((EnumConstant) e).Child;
6508 if (e is StringConstant || e is DecimalConstant || !(e is Constant) ||
6509 num_automatic_initializers <= max_automatic_initializers) {
6510 Type etype = e.Type;
6512 ig.Emit (OpCodes.Dup);
6514 for (int idx = 0; idx < dims; idx++)
6515 IntConstant.EmitInt (ig, current_pos [idx]);
6518 // If we are dealing with a struct, get the
6519 // address of it, so we can store it.
6521 if ((dims == 1) &&
6522 etype.IsSubclassOf (TypeManager.value_type) &&
6523 (!TypeManager.IsBuiltinOrEnum (etype) ||
6524 etype == TypeManager.decimal_type)) {
6525 if (e is New){
6526 New n = (New) e;
6529 // Let new know that we are providing
6530 // the address where to store the results
6532 n.DisableTemporaryValueType ();
6535 ig.Emit (OpCodes.Ldelema, etype);
6538 e.Emit (ec);
6540 if (dims == 1) {
6541 bool is_stobj;
6542 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj);
6543 if (is_stobj)
6544 ig.Emit (OpCodes.Stobj, etype);
6545 else
6546 ig.Emit (op);
6547 } else
6548 ig.Emit (OpCodes.Call, set);
6554 // Advance counter
6556 for (int j = dims - 1; j >= 0; j--){
6557 current_pos [j]++;
6558 if (current_pos [j] < (int) bounds [j])
6559 break;
6560 current_pos [j] = 0;
6565 void EmitArrayArguments (EmitContext ec)
6567 ILGenerator ig = ec.ig;
6569 foreach (Argument a in arguments) {
6570 Type atype = a.Type;
6571 a.Emit (ec);
6573 if (atype == TypeManager.uint64_type)
6574 ig.Emit (OpCodes.Conv_Ovf_U4);
6575 else if (atype == TypeManager.int64_type)
6576 ig.Emit (OpCodes.Conv_Ovf_I4);
6580 public override void Emit (EmitContext ec)
6582 ILGenerator ig = ec.ig;
6584 EmitArrayArguments (ec);
6585 if (is_one_dimensional)
6586 ig.Emit (OpCodes.Newarr, array_element_type);
6587 else {
6588 if (is_builtin_type)
6589 ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6590 else
6591 ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6594 if (initializers != null){
6596 // FIXME: Set this variable correctly.
6598 bool dynamic_initializers = true;
6600 // This will never be true for array types that cannot be statically
6601 // initialized. num_automatic_initializers will always be zero. See
6602 // CheckIndices.
6603 if (num_automatic_initializers > max_automatic_initializers)
6604 EmitStaticInitializers (ec);
6606 if (dynamic_initializers)
6607 EmitDynamicInitializers (ec);
6611 public object EncodeAsAttribute ()
6613 if (!is_one_dimensional){
6614 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6615 return null;
6618 if (array_data == null){
6619 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6620 return null;
6623 object [] ret = new object [array_data.Count];
6624 int i = 0;
6625 foreach (Expression e in array_data){
6626 object v;
6628 if (e is NullLiteral)
6629 v = null;
6630 else {
6631 if (!Attribute.GetAttributeArgumentExpression (e, Location, array_element_type, out v))
6632 return null;
6634 ret [i++] = v;
6636 return ret;
6640 /// <summary>
6641 /// Represents the `this' construct
6642 /// </summary>
6643 public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
6645 Block block;
6646 VariableInfo variable_info;
6648 public This (Block block, Location loc)
6650 this.loc = loc;
6651 this.block = block;
6654 public This (Location loc)
6656 this.loc = loc;
6659 public VariableInfo VariableInfo {
6660 get { return variable_info; }
6663 public bool VerifyFixed (bool is_expression)
6665 if ((variable_info == null) || (variable_info.LocalInfo == null))
6666 return false;
6667 else
6668 return variable_info.LocalInfo.IsFixed;
6671 public bool ResolveBase (EmitContext ec)
6673 eclass = ExprClass.Variable;
6674 type = ec.ContainerType;
6676 if (ec.IsStatic) {
6677 Error (26, "Keyword this not valid in static code");
6678 return false;
6681 if ((block != null) && (block.ThisVariable != null))
6682 variable_info = block.ThisVariable.VariableInfo;
6684 return true;
6687 public override Expression DoResolve (EmitContext ec)
6689 if (!ResolveBase (ec))
6690 return null;
6692 if ((variable_info != null) && !variable_info.IsAssigned (ec)) {
6693 Error (188, "The this object cannot be used before all " +
6694 "of its fields are assigned to");
6695 variable_info.SetAssigned (ec);
6696 return this;
6699 if (ec.IsFieldInitializer) {
6700 Error (27, "Keyword `this' can't be used outside a constructor, " +
6701 "a method or a property.");
6702 return null;
6705 return this;
6708 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6710 if (!ResolveBase (ec))
6711 return null;
6713 if (variable_info != null)
6714 variable_info.SetAssigned (ec);
6716 if (ec.TypeContainer is Class){
6717 Error (1604, "Cannot assign to `this'");
6718 return null;
6721 return this;
6724 public void Emit (EmitContext ec, bool leave_copy)
6726 Emit (ec);
6727 if (leave_copy)
6728 ec.ig.Emit (OpCodes.Dup);
6731 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
6733 ILGenerator ig = ec.ig;
6735 if (ec.TypeContainer is Struct){
6736 ec.EmitThis ();
6737 source.Emit (ec);
6738 if (leave_copy)
6739 ec.ig.Emit (OpCodes.Dup);
6740 ig.Emit (OpCodes.Stobj, type);
6741 } else {
6742 throw new Exception ("how did you get here");
6746 public override void Emit (EmitContext ec)
6748 ILGenerator ig = ec.ig;
6750 ec.EmitThis ();
6751 if (ec.TypeContainer is Struct)
6752 ig.Emit (OpCodes.Ldobj, type);
6755 public void AddressOf (EmitContext ec, AddressOp mode)
6757 ec.EmitThis ();
6759 // FIMXE
6760 // FIGURE OUT WHY LDARG_S does not work
6762 // consider: struct X { int val; int P { set { val = value; }}}
6764 // Yes, this looks very bad. Look at `NOTAS' for
6765 // an explanation.
6766 // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6770 /// <summary>
6771 /// Represents the `__arglist' construct
6772 /// </summary>
6773 public class ArglistAccess : Expression
6775 public ArglistAccess (Location loc)
6777 this.loc = loc;
6780 public bool ResolveBase (EmitContext ec)
6782 eclass = ExprClass.Variable;
6783 type = TypeManager.runtime_argument_handle_type;
6784 return true;
6787 public override Expression DoResolve (EmitContext ec)
6789 if (!ResolveBase (ec))
6790 return null;
6792 if (ec.IsFieldInitializer || !ec.CurrentBlock.HasVarargs) {
6793 Error (190, "The __arglist construct is valid only within " +
6794 "a variable argument method.");
6795 return null;
6798 return this;
6801 public override void Emit (EmitContext ec)
6803 ec.ig.Emit (OpCodes.Arglist);
6807 /// <summary>
6808 /// Represents the `__arglist (....)' construct
6809 /// </summary>
6810 public class Arglist : Expression
6812 public readonly Argument[] Arguments;
6814 public Arglist (Argument[] args, Location l)
6816 Arguments = args;
6817 loc = l;
6820 public Type[] ArgumentTypes {
6821 get {
6822 Type[] retval = new Type [Arguments.Length];
6823 for (int i = 0; i < Arguments.Length; i++)
6824 retval [i] = Arguments [i].Type;
6825 return retval;
6829 public override Expression DoResolve (EmitContext ec)
6831 eclass = ExprClass.Variable;
6832 type = TypeManager.runtime_argument_handle_type;
6834 foreach (Argument arg in Arguments) {
6835 if (!arg.Resolve (ec, loc))
6836 return null;
6839 return this;
6842 public override void Emit (EmitContext ec)
6844 foreach (Argument arg in Arguments)
6845 arg.Emit (ec);
6850 // This produces the value that renders an instance, used by the iterators code
6852 public class ProxyInstance : Expression, IMemoryLocation {
6853 public override Expression DoResolve (EmitContext ec)
6855 eclass = ExprClass.Variable;
6856 type = ec.ContainerType;
6857 return this;
6860 public override void Emit (EmitContext ec)
6862 ec.ig.Emit (OpCodes.Ldarg_0);
6866 public void AddressOf (EmitContext ec, AddressOp mode)
6868 ec.ig.Emit (OpCodes.Ldarg_0);
6872 /// <summary>
6873 /// Implements the typeof operator
6874 /// </summary>
6875 public class TypeOf : Expression {
6876 public Expression QueriedType;
6877 protected Type typearg;
6879 public TypeOf (Expression queried_type, Location l)
6881 QueriedType = queried_type;
6882 loc = l;
6885 public override Expression DoResolve (EmitContext ec)
6887 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6888 if (texpr == null)
6889 return null;
6891 typearg = texpr.ResolveType (ec);
6893 if (typearg == TypeManager.void_type) {
6894 Error (673, "System.Void cannot be used from C# - " +
6895 "use typeof (void) to get the void type object");
6896 return null;
6899 if (typearg.IsPointer && !ec.InUnsafe){
6900 UnsafeError (loc);
6901 return null;
6903 CheckObsoleteAttribute (typearg);
6905 type = TypeManager.type_type;
6906 eclass = ExprClass.Type;
6907 return this;
6910 public override void Emit (EmitContext ec)
6912 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6913 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6916 public Type TypeArg {
6917 get { return typearg; }
6921 /// <summary>
6922 /// Implements the `typeof (void)' operator
6923 /// </summary>
6924 public class TypeOfVoid : TypeOf {
6925 public TypeOfVoid (Location l) : base (null, l)
6927 loc = l;
6930 public override Expression DoResolve (EmitContext ec)
6932 type = TypeManager.type_type;
6933 typearg = TypeManager.void_type;
6934 eclass = ExprClass.Type;
6935 return this;
6939 /// <summary>
6940 /// Implements the sizeof expression
6941 /// </summary>
6942 public class SizeOf : Expression {
6943 public Expression QueriedType;
6944 Type type_queried;
6946 public SizeOf (Expression queried_type, Location l)
6948 this.QueriedType = queried_type;
6949 loc = l;
6952 public override Expression DoResolve (EmitContext ec)
6954 if (!ec.InUnsafe) {
6955 Report.Error (
6956 233, loc, "Sizeof may only be used in an unsafe context " +
6957 "(consider using System.Runtime.InteropServices.Marshal.SizeOf");
6958 return null;
6961 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6962 if (texpr == null)
6963 return null;
6965 type_queried = texpr.ResolveType (ec);
6967 CheckObsoleteAttribute (type_queried);
6969 if (!TypeManager.IsUnmanagedType (type_queried)){
6970 Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
6971 return null;
6974 type = TypeManager.int32_type;
6975 eclass = ExprClass.Value;
6976 return this;
6979 public override void Emit (EmitContext ec)
6981 int size = GetTypeSize (type_queried);
6983 if (size == 0)
6984 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6985 else
6986 IntConstant.EmitInt (ec.ig, size);
6990 /// <summary>
6991 /// Implements the member access expression
6992 /// </summary>
6993 public class MemberAccess : Expression {
6994 public readonly string Identifier;
6995 Expression expr;
6997 public MemberAccess (Expression expr, string id, Location l)
6999 this.expr = expr;
7000 Identifier = id;
7001 loc = l;
7004 public Expression Expr {
7005 get {
7006 return expr;
7010 public static void error176 (Location loc, string name)
7012 Report.Error (176, loc, "Static member `" +
7013 name + "' cannot be accessed " +
7014 "with an instance reference, qualify with a " +
7015 "type name instead");
7018 public static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Expression left, Location loc)
7020 SimpleName sn = left_original as SimpleName;
7021 if (sn == null || left == null || left.Type.Name != sn.Name)
7022 return false;
7024 return RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc) != null;
7027 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
7028 Expression left, Location loc,
7029 Expression left_original)
7031 bool left_is_type, left_is_explicit;
7033 // If `left' is null, then we're called from SimpleNameResolve and this is
7034 // a member in the currently defining class.
7035 if (left == null) {
7036 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
7037 left_is_explicit = false;
7039 // Implicitly default to `this' unless we're static.
7040 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
7041 left = ec.GetThis (loc);
7042 } else {
7043 left_is_type = left is TypeExpr;
7044 left_is_explicit = true;
7047 if (member_lookup is FieldExpr){
7048 FieldExpr fe = (FieldExpr) member_lookup;
7049 FieldInfo fi = fe.FieldInfo;
7050 Type decl_type = fi.DeclaringType;
7052 if (fi is FieldBuilder) {
7053 Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
7055 if (c != null) {
7056 object o;
7057 if (!c.LookupConstantValue (out o))
7058 return null;
7060 object real_value = ((Constant) c.Expr).GetValue ();
7062 return Constantify (real_value, fi.FieldType);
7066 if (fi.IsLiteral) {
7067 Type t = fi.FieldType;
7069 object o;
7071 if (fi is FieldBuilder)
7072 o = TypeManager.GetValue ((FieldBuilder) fi);
7073 else
7074 o = fi.GetValue (fi);
7076 if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
7077 if (left_is_explicit && !left_is_type &&
7078 !IdenticalNameAndTypeName (ec, left_original, member_lookup, loc)) {
7079 error176 (loc, fe.FieldInfo.Name);
7080 return null;
7083 Expression enum_member = MemberLookup (
7084 ec, decl_type, "value__", MemberTypes.Field,
7085 AllBindingFlags, loc);
7087 Enum en = TypeManager.LookupEnum (decl_type);
7089 Constant c;
7090 if (en != null)
7091 c = Constantify (o, en.UnderlyingType);
7092 else
7093 c = Constantify (o, enum_member.Type);
7095 return new EnumConstant (c, decl_type);
7098 Expression exp = Constantify (o, t);
7100 if (left_is_explicit && !left_is_type) {
7101 error176 (loc, fe.FieldInfo.Name);
7102 return null;
7105 return exp;
7108 if (fi.FieldType.IsPointer && !ec.InUnsafe){
7109 UnsafeError (loc);
7110 return null;
7114 if (member_lookup is EventExpr) {
7115 EventExpr ee = (EventExpr) member_lookup;
7118 // If the event is local to this class, we transform ourselves into
7119 // a FieldExpr
7122 if (ee.EventInfo.DeclaringType == ec.ContainerType ||
7123 TypeManager.IsNestedChildOf(ec.ContainerType, ee.EventInfo.DeclaringType)) {
7124 MemberInfo mi = GetFieldFromEvent (ee);
7126 if (mi == null) {
7128 // If this happens, then we have an event with its own
7129 // accessors and private field etc so there's no need
7130 // to transform ourselves.
7132 ee.InstanceExpression = left;
7133 return ee;
7136 Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
7138 if (ml == null) {
7139 Report.Error (-200, loc, "Internal error!!");
7140 return null;
7143 if (!left_is_explicit)
7144 left = null;
7146 ee.InstanceExpression = left;
7148 return ResolveMemberAccess (ec, ml, left, loc, left_original);
7152 if (member_lookup is IMemberExpr) {
7153 IMemberExpr me = (IMemberExpr) member_lookup;
7154 MethodGroupExpr mg = me as MethodGroupExpr;
7156 if (left_is_type){
7157 if ((mg != null) && left_is_explicit && left.Type.IsInterface)
7158 mg.IsExplicitImpl = left_is_explicit;
7160 if (!me.IsStatic){
7161 if ((ec.IsFieldInitializer || ec.IsStatic) &&
7162 IdenticalNameAndTypeName (ec, left_original, member_lookup, loc))
7163 return member_lookup;
7165 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
7166 return null;
7169 } else {
7170 if (!me.IsInstance) {
7171 if (IdenticalNameAndTypeName (ec, left_original, left, loc))
7172 return member_lookup;
7174 if (left_is_explicit) {
7175 error176 (loc, me.Name);
7176 return null;
7181 // Since we can not check for instance objects in SimpleName,
7182 // becaue of the rule that allows types and variables to share
7183 // the name (as long as they can be de-ambiguated later, see
7184 // IdenticalNameAndTypeName), we have to check whether left
7185 // is an instance variable in a static context
7187 // However, if the left-hand value is explicitly given, then
7188 // it is already our instance expression, so we aren't in
7189 // static context.
7192 if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
7193 IMemberExpr mexp = (IMemberExpr) left;
7195 if (!mexp.IsStatic){
7196 SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
7197 return null;
7201 if ((mg != null) && IdenticalNameAndTypeName (ec, left_original, left, loc))
7202 mg.IdenticalTypeName = true;
7204 me.InstanceExpression = left;
7207 return member_lookup;
7210 Console.WriteLine ("Left is: " + left);
7211 Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
7212 Environment.Exit (1);
7213 return null;
7216 public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
7218 if (type != null)
7219 throw new Exception ();
7222 // Resolve the expression with flow analysis turned off, we'll do the definite
7223 // assignment checks later. This is because we don't know yet what the expression
7224 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7225 // definite assignment check on the actual field and not on the whole struct.
7228 Expression original = expr;
7229 expr = expr.Resolve (ec, flags | ResolveFlags.Intermediate | ResolveFlags.DisableFlowAnalysis);
7230 if (expr == null)
7231 return null;
7233 if (expr is SimpleName){
7234 SimpleName child_expr = (SimpleName) expr;
7236 Expression new_expr = new SimpleName (child_expr.Name, Identifier, loc);
7238 return new_expr.Resolve (ec, flags);
7242 // TODO: I mailed Ravi about this, and apparently we can get rid
7243 // of this and put it in the right place.
7245 // Handle enums here when they are in transit.
7246 // Note that we cannot afford to hit MemberLookup in this case because
7247 // it will fail to find any members at all
7250 Type expr_type = expr.Type;
7251 if (expr is TypeExpr){
7252 if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
7253 Report.Error (122, loc, "'{0}' is inaccessible due to its protection level", expr_type);
7254 return null;
7257 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
7258 Enum en = TypeManager.LookupEnum (expr_type);
7260 if (en != null) {
7261 object value = en.LookupEnumValue (ec, Identifier, loc);
7263 if (value != null){
7264 MemberCore mc = en.GetDefinition (Identifier);
7265 ObsoleteAttribute oa = mc.GetObsoleteAttribute (en);
7266 if (oa != null) {
7267 AttributeTester.Report_ObsoleteMessage (oa, mc.GetSignatureForError (), Location);
7269 oa = en.GetObsoleteAttribute (en);
7270 if (oa != null) {
7271 AttributeTester.Report_ObsoleteMessage (oa, en.GetSignatureForError (), Location);
7274 Constant c = Constantify (value, en.UnderlyingType);
7275 return new EnumConstant (c, expr_type);
7277 } else {
7278 CheckObsoleteAttribute (expr_type);
7280 FieldInfo fi = expr_type.GetField (Identifier);
7281 if (fi != null) {
7282 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
7283 if (oa != null)
7284 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), Location);
7290 if (expr_type.IsPointer){
7291 Error (23, "The `.' operator can not be applied to pointer operands (" +
7292 TypeManager.CSharpName (expr_type) + ")");
7293 return null;
7296 Expression member_lookup;
7297 member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
7298 if (member_lookup == null)
7299 return null;
7301 if (member_lookup is TypeExpr) {
7302 if (!(expr is TypeExpr) && !(expr is SimpleName)) {
7303 Error (572, "Can't reference type `" + Identifier + "' through an expression; try `" +
7304 member_lookup.Type + "' instead");
7305 return null;
7308 return member_lookup;
7311 member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
7312 if (member_lookup == null)
7313 return null;
7315 // The following DoResolve/DoResolveLValue will do the definite assignment
7316 // check.
7318 if (right_side != null)
7319 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
7320 else
7321 member_lookup = member_lookup.DoResolve (ec);
7323 return member_lookup;
7326 public override Expression DoResolve (EmitContext ec)
7328 return DoResolve (ec, null, ResolveFlags.VariableOrValue |
7329 ResolveFlags.SimpleName | ResolveFlags.Type);
7332 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7334 return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
7335 ResolveFlags.SimpleName | ResolveFlags.Type);
7338 public override Expression ResolveAsTypeStep (EmitContext ec)
7340 string fname = null;
7341 MemberAccess full_expr = this;
7342 while (full_expr != null) {
7343 if (fname != null)
7344 fname = String.Concat (full_expr.Identifier, ".", fname);
7345 else
7346 fname = full_expr.Identifier;
7348 if (full_expr.Expr is SimpleName) {
7349 string full_name = String.Concat (((SimpleName) full_expr.Expr).Name, ".", fname);
7350 Type fully_qualified = ec.DeclSpace.FindType (loc, full_name);
7351 if (fully_qualified != null)
7352 return new TypeExpression (fully_qualified, loc);
7355 full_expr = full_expr.Expr as MemberAccess;
7358 Expression new_expr = expr.ResolveAsTypeStep (ec);
7360 if (new_expr == null)
7361 return null;
7363 if (new_expr is SimpleName){
7364 SimpleName child_expr = (SimpleName) new_expr;
7366 new_expr = new SimpleName (child_expr.Name, Identifier, loc);
7368 return new_expr.ResolveAsTypeStep (ec);
7371 Type expr_type = new_expr.Type;
7373 if (expr_type.IsPointer){
7374 Error (23, "The `.' operator can not be applied to pointer operands (" +
7375 TypeManager.CSharpName (expr_type) + ")");
7376 return null;
7379 Expression member_lookup;
7380 member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
7381 if (member_lookup == null)
7382 return null;
7384 if (member_lookup is TypeExpr){
7385 member_lookup.Resolve (ec, ResolveFlags.Type);
7386 return member_lookup;
7389 return null;
7392 public override void Emit (EmitContext ec)
7394 throw new Exception ("Should not happen");
7397 public override string ToString ()
7399 return expr + "." + Identifier;
7403 /// <summary>
7404 /// Implements checked expressions
7405 /// </summary>
7406 public class CheckedExpr : Expression {
7408 public Expression Expr;
7410 public CheckedExpr (Expression e, Location l)
7412 Expr = e;
7413 loc = l;
7416 public override Expression DoResolve (EmitContext ec)
7418 bool last_check = ec.CheckState;
7419 bool last_const_check = ec.ConstantCheckState;
7421 ec.CheckState = true;
7422 ec.ConstantCheckState = true;
7423 Expr = Expr.Resolve (ec);
7424 ec.CheckState = last_check;
7425 ec.ConstantCheckState = last_const_check;
7427 if (Expr == null)
7428 return null;
7430 if (Expr is Constant)
7431 return Expr;
7433 eclass = Expr.eclass;
7434 type = Expr.Type;
7435 return this;
7438 public override void Emit (EmitContext ec)
7440 bool last_check = ec.CheckState;
7441 bool last_const_check = ec.ConstantCheckState;
7443 ec.CheckState = true;
7444 ec.ConstantCheckState = true;
7445 Expr.Emit (ec);
7446 ec.CheckState = last_check;
7447 ec.ConstantCheckState = last_const_check;
7452 /// <summary>
7453 /// Implements the unchecked expression
7454 /// </summary>
7455 public class UnCheckedExpr : Expression {
7457 public Expression Expr;
7459 public UnCheckedExpr (Expression e, Location l)
7461 Expr = e;
7462 loc = l;
7465 public override Expression DoResolve (EmitContext ec)
7467 bool last_check = ec.CheckState;
7468 bool last_const_check = ec.ConstantCheckState;
7470 ec.CheckState = false;
7471 ec.ConstantCheckState = false;
7472 Expr = Expr.Resolve (ec);
7473 ec.CheckState = last_check;
7474 ec.ConstantCheckState = last_const_check;
7476 if (Expr == null)
7477 return null;
7479 if (Expr is Constant)
7480 return Expr;
7482 eclass = Expr.eclass;
7483 type = Expr.Type;
7484 return this;
7487 public override void Emit (EmitContext ec)
7489 bool last_check = ec.CheckState;
7490 bool last_const_check = ec.ConstantCheckState;
7492 ec.CheckState = false;
7493 ec.ConstantCheckState = false;
7494 Expr.Emit (ec);
7495 ec.CheckState = last_check;
7496 ec.ConstantCheckState = last_const_check;
7501 /// <summary>
7502 /// An Element Access expression.
7504 /// During semantic analysis these are transformed into
7505 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7506 /// </summary>
7507 public class ElementAccess : Expression {
7508 public ArrayList Arguments;
7509 public Expression Expr;
7511 public ElementAccess (Expression e, ArrayList e_list, Location l)
7513 Expr = e;
7515 loc = l;
7517 if (e_list == null)
7518 return;
7520 Arguments = new ArrayList ();
7521 foreach (Expression tmp in e_list)
7522 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7526 bool CommonResolve (EmitContext ec)
7528 Expr = Expr.Resolve (ec);
7530 if (Expr == null)
7531 return false;
7533 if (Arguments == null)
7534 return false;
7536 foreach (Argument a in Arguments){
7537 if (!a.Resolve (ec, loc))
7538 return false;
7541 return true;
7544 Expression MakePointerAccess (EmitContext ec)
7546 Type t = Expr.Type;
7548 if (t == TypeManager.void_ptr_type){
7549 Error (242, "The array index operation is not valid for void pointers");
7550 return null;
7552 if (Arguments.Count != 1){
7553 Error (196, "A pointer must be indexed by a single value");
7554 return null;
7556 Expression p;
7558 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7559 if (p == null)
7560 return null;
7561 return new Indirection (p, loc).Resolve (ec);
7564 public override Expression DoResolve (EmitContext ec)
7566 if (!CommonResolve (ec))
7567 return null;
7570 // We perform some simple tests, and then to "split" the emit and store
7571 // code we create an instance of a different class, and return that.
7573 // I am experimenting with this pattern.
7575 Type t = Expr.Type;
7577 if (t == TypeManager.array_type){
7578 Report.Error (21, loc, "Cannot use indexer on System.Array");
7579 return null;
7582 if (t.IsArray)
7583 return (new ArrayAccess (this, loc)).Resolve (ec);
7584 else if (t.IsPointer)
7585 return MakePointerAccess (ec);
7586 else
7587 return (new IndexerAccess (this, loc)).Resolve (ec);
7590 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7592 if (!CommonResolve (ec))
7593 return null;
7595 Type t = Expr.Type;
7596 if (t.IsArray)
7597 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
7598 else if (t.IsPointer)
7599 return MakePointerAccess (ec);
7600 else
7601 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
7604 public override void Emit (EmitContext ec)
7606 throw new Exception ("Should never be reached");
7610 /// <summary>
7611 /// Implements array access
7612 /// </summary>
7613 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7615 // Points to our "data" repository
7617 ElementAccess ea;
7619 LocalTemporary temp;
7620 bool prepared;
7622 public ArrayAccess (ElementAccess ea_data, Location l)
7624 ea = ea_data;
7625 eclass = ExprClass.Variable;
7626 loc = l;
7629 public override Expression DoResolve (EmitContext ec)
7631 #if false
7632 ExprClass eclass = ea.Expr.eclass;
7634 // As long as the type is valid
7635 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7636 eclass == ExprClass.Value)) {
7637 ea.Expr.Error_UnexpectedKind ("variable or value");
7638 return null;
7640 #endif
7642 Type t = ea.Expr.Type;
7643 if (t.GetArrayRank () != ea.Arguments.Count){
7644 ea.Error (22,
7645 "Incorrect number of indexes for array " +
7646 " expected: " + t.GetArrayRank () + " got: " +
7647 ea.Arguments.Count);
7648 return null;
7651 type = TypeManager.GetElementType (t);
7652 if (type.IsPointer && !ec.InUnsafe){
7653 UnsafeError (ea.Location);
7654 return null;
7657 foreach (Argument a in ea.Arguments){
7658 Type argtype = a.Type;
7660 if (argtype == TypeManager.int32_type ||
7661 argtype == TypeManager.uint32_type ||
7662 argtype == TypeManager.int64_type ||
7663 argtype == TypeManager.uint64_type) {
7664 Constant c = a.Expr as Constant;
7665 if (c != null && c.IsNegative) {
7666 Report.Warning (251, 2, a.Expr.Location, "Indexing an array with a negative index (array indices always start at zero)");
7668 continue;
7672 // Mhm. This is strage, because the Argument.Type is not the same as
7673 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7675 // Wonder if I will run into trouble for this.
7677 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7678 if (a.Expr == null)
7679 return null;
7682 eclass = ExprClass.Variable;
7684 return this;
7687 /// <summary>
7688 /// Emits the right opcode to load an object of Type `t'
7689 /// from an array of T
7690 /// </summary>
7691 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7693 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7694 ig.Emit (OpCodes.Ldelem_U1);
7695 else if (type == TypeManager.sbyte_type)
7696 ig.Emit (OpCodes.Ldelem_I1);
7697 else if (type == TypeManager.short_type)
7698 ig.Emit (OpCodes.Ldelem_I2);
7699 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7700 ig.Emit (OpCodes.Ldelem_U2);
7701 else if (type == TypeManager.int32_type)
7702 ig.Emit (OpCodes.Ldelem_I4);
7703 else if (type == TypeManager.uint32_type)
7704 ig.Emit (OpCodes.Ldelem_U4);
7705 else if (type == TypeManager.uint64_type)
7706 ig.Emit (OpCodes.Ldelem_I8);
7707 else if (type == TypeManager.int64_type)
7708 ig.Emit (OpCodes.Ldelem_I8);
7709 else if (type == TypeManager.float_type)
7710 ig.Emit (OpCodes.Ldelem_R4);
7711 else if (type == TypeManager.double_type)
7712 ig.Emit (OpCodes.Ldelem_R8);
7713 else if (type == TypeManager.intptr_type)
7714 ig.Emit (OpCodes.Ldelem_I);
7715 else if (TypeManager.IsEnumType (type)){
7716 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7717 } else if (type.IsValueType){
7718 ig.Emit (OpCodes.Ldelema, type);
7719 ig.Emit (OpCodes.Ldobj, type);
7720 } else
7721 ig.Emit (OpCodes.Ldelem_Ref);
7724 /// <summary>
7725 /// Returns the right opcode to store an object of Type `t'
7726 /// from an array of T.
7727 /// </summary>
7728 static public OpCode GetStoreOpcode (Type t, out bool is_stobj)
7730 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7731 is_stobj = false;
7732 t = TypeManager.TypeToCoreType (t);
7733 if (TypeManager.IsEnumType (t))
7734 t = TypeManager.EnumToUnderlying (t);
7735 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7736 t == TypeManager.bool_type)
7737 return OpCodes.Stelem_I1;
7738 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7739 t == TypeManager.char_type)
7740 return OpCodes.Stelem_I2;
7741 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7742 return OpCodes.Stelem_I4;
7743 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7744 return OpCodes.Stelem_I8;
7745 else if (t == TypeManager.float_type)
7746 return OpCodes.Stelem_R4;
7747 else if (t == TypeManager.double_type)
7748 return OpCodes.Stelem_R8;
7749 else if (t == TypeManager.intptr_type) {
7750 is_stobj = true;
7751 return OpCodes.Stobj;
7752 } else if (t.IsValueType) {
7753 is_stobj = true;
7754 return OpCodes.Stobj;
7755 } else
7756 return OpCodes.Stelem_Ref;
7759 MethodInfo FetchGetMethod ()
7761 ModuleBuilder mb = CodeGen.Module.Builder;
7762 int arg_count = ea.Arguments.Count;
7763 Type [] args = new Type [arg_count];
7764 MethodInfo get;
7766 for (int i = 0; i < arg_count; i++){
7767 //args [i++] = a.Type;
7768 args [i] = TypeManager.int32_type;
7771 get = mb.GetArrayMethod (
7772 ea.Expr.Type, "Get",
7773 CallingConventions.HasThis |
7774 CallingConventions.Standard,
7775 type, args);
7776 return get;
7780 MethodInfo FetchAddressMethod ()
7782 ModuleBuilder mb = CodeGen.Module.Builder;
7783 int arg_count = ea.Arguments.Count;
7784 Type [] args = new Type [arg_count];
7785 MethodInfo address;
7786 Type ret_type;
7788 ret_type = TypeManager.GetReferenceType (type);
7790 for (int i = 0; i < arg_count; i++){
7791 //args [i++] = a.Type;
7792 args [i] = TypeManager.int32_type;
7795 address = mb.GetArrayMethod (
7796 ea.Expr.Type, "Address",
7797 CallingConventions.HasThis |
7798 CallingConventions.Standard,
7799 ret_type, args);
7801 return address;
7805 // Load the array arguments into the stack.
7807 // If we have been requested to cache the values (cached_locations array
7808 // initialized), then load the arguments the first time and store them
7809 // in locals. otherwise load from local variables.
7811 void LoadArrayAndArguments (EmitContext ec)
7813 ILGenerator ig = ec.ig;
7815 ea.Expr.Emit (ec);
7816 foreach (Argument a in ea.Arguments){
7817 Type argtype = a.Expr.Type;
7819 a.Expr.Emit (ec);
7821 if (argtype == TypeManager.int64_type)
7822 ig.Emit (OpCodes.Conv_Ovf_I);
7823 else if (argtype == TypeManager.uint64_type)
7824 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7828 public void Emit (EmitContext ec, bool leave_copy)
7830 int rank = ea.Expr.Type.GetArrayRank ();
7831 ILGenerator ig = ec.ig;
7833 if (!prepared) {
7834 LoadArrayAndArguments (ec);
7836 if (rank == 1)
7837 EmitLoadOpcode (ig, type);
7838 else {
7839 MethodInfo method;
7841 method = FetchGetMethod ();
7842 ig.Emit (OpCodes.Call, method);
7844 } else
7845 LoadFromPtr (ec.ig, this.type);
7847 if (leave_copy) {
7848 ec.ig.Emit (OpCodes.Dup);
7849 temp = new LocalTemporary (ec, this.type);
7850 temp.Store (ec);
7854 public override void Emit (EmitContext ec)
7856 Emit (ec, false);
7859 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7861 int rank = ea.Expr.Type.GetArrayRank ();
7862 ILGenerator ig = ec.ig;
7863 Type t = source.Type;
7864 prepared = prepare_for_load;
7866 if (prepare_for_load) {
7867 AddressOf (ec, AddressOp.LoadStore);
7868 ec.ig.Emit (OpCodes.Dup);
7869 source.Emit (ec);
7870 if (leave_copy) {
7871 ec.ig.Emit (OpCodes.Dup);
7872 temp = new LocalTemporary (ec, this.type);
7873 temp.Store (ec);
7875 StoreFromPtr (ec.ig, t);
7877 if (temp != null)
7878 temp.Emit (ec);
7880 return;
7883 LoadArrayAndArguments (ec);
7885 if (rank == 1) {
7886 bool is_stobj;
7887 OpCode op = GetStoreOpcode (t, out is_stobj);
7889 // The stobj opcode used by value types will need
7890 // an address on the stack, not really an array/array
7891 // pair
7893 if (is_stobj)
7894 ig.Emit (OpCodes.Ldelema, t);
7896 source.Emit (ec);
7897 if (leave_copy) {
7898 ec.ig.Emit (OpCodes.Dup);
7899 temp = new LocalTemporary (ec, this.type);
7900 temp.Store (ec);
7903 if (is_stobj)
7904 ig.Emit (OpCodes.Stobj, t);
7905 else
7906 ig.Emit (op);
7907 } else {
7908 ModuleBuilder mb = CodeGen.Module.Builder;
7909 int arg_count = ea.Arguments.Count;
7910 Type [] args = new Type [arg_count + 1];
7911 MethodInfo set;
7913 source.Emit (ec);
7914 if (leave_copy) {
7915 ec.ig.Emit (OpCodes.Dup);
7916 temp = new LocalTemporary (ec, this.type);
7917 temp.Store (ec);
7920 for (int i = 0; i < arg_count; i++){
7921 //args [i++] = a.Type;
7922 args [i] = TypeManager.int32_type;
7925 args [arg_count] = type;
7927 set = mb.GetArrayMethod (
7928 ea.Expr.Type, "Set",
7929 CallingConventions.HasThis |
7930 CallingConventions.Standard,
7931 TypeManager.void_type, args);
7933 ig.Emit (OpCodes.Call, set);
7936 if (temp != null)
7937 temp.Emit (ec);
7940 public void AddressOf (EmitContext ec, AddressOp mode)
7942 int rank = ea.Expr.Type.GetArrayRank ();
7943 ILGenerator ig = ec.ig;
7945 LoadArrayAndArguments (ec);
7947 if (rank == 1){
7948 ig.Emit (OpCodes.Ldelema, type);
7949 } else {
7950 MethodInfo address = FetchAddressMethod ();
7951 ig.Emit (OpCodes.Call, address);
7957 class Indexers {
7958 public ArrayList Properties;
7959 static Hashtable map;
7961 public struct Indexer {
7962 public readonly Type Type;
7963 public readonly MethodInfo Getter, Setter;
7965 public Indexer (Type type, MethodInfo get, MethodInfo set)
7967 this.Type = type;
7968 this.Getter = get;
7969 this.Setter = set;
7973 static Indexers ()
7975 map = new Hashtable ();
7978 Indexers ()
7980 Properties = new ArrayList ();
7983 void Append (MemberInfo [] mi)
7985 foreach (PropertyInfo property in mi){
7986 MethodInfo get, set;
7988 get = property.GetGetMethod (true);
7989 set = property.GetSetMethod (true);
7990 Properties.Add (new Indexer (property.PropertyType, get, set));
7994 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7996 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7998 MemberInfo [] mi = TypeManager.MemberLookup (
7999 caller_type, caller_type, lookup_type, MemberTypes.Property,
8000 BindingFlags.Public | BindingFlags.Instance |
8001 BindingFlags.DeclaredOnly, p_name, null);
8003 if (mi == null || mi.Length == 0)
8004 return null;
8006 return mi;
8009 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc)
8011 Indexers ix = (Indexers) map [lookup_type];
8013 if (ix != null)
8014 return ix;
8016 Type copy = lookup_type;
8017 while (copy != TypeManager.object_type && copy != null){
8018 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy);
8020 if (mi != null){
8021 if (ix == null)
8022 ix = new Indexers ();
8024 ix.Append (mi);
8027 copy = copy.BaseType;
8030 if (!lookup_type.IsInterface)
8031 return ix;
8033 TypeExpr [] ifaces = TypeManager.GetInterfaces (lookup_type);
8034 if (ifaces != null) {
8035 foreach (TypeExpr iface in ifaces) {
8036 Type itype = iface.Type;
8037 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype);
8038 if (mi != null){
8039 if (ix == null)
8040 ix = new Indexers ();
8042 ix.Append (mi);
8047 return ix;
8051 /// <summary>
8052 /// Expressions that represent an indexer call.
8053 /// </summary>
8054 public class IndexerAccess : Expression, IAssignMethod {
8056 // Points to our "data" repository
8058 MethodInfo get, set;
8059 ArrayList set_arguments;
8060 bool is_base_indexer;
8062 protected Type indexer_type;
8063 protected Type current_type;
8064 protected Expression instance_expr;
8065 protected ArrayList arguments;
8067 public IndexerAccess (ElementAccess ea, Location loc)
8068 : this (ea.Expr, false, loc)
8070 this.arguments = ea.Arguments;
8073 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8074 Location loc)
8076 this.instance_expr = instance_expr;
8077 this.is_base_indexer = is_base_indexer;
8078 this.eclass = ExprClass.Value;
8079 this.loc = loc;
8082 protected virtual bool CommonResolve (EmitContext ec)
8084 indexer_type = instance_expr.Type;
8085 current_type = ec.ContainerType;
8087 return true;
8090 public override Expression DoResolve (EmitContext ec)
8092 ArrayList AllGetters = new ArrayList();
8093 if (!CommonResolve (ec))
8094 return null;
8097 // Step 1: Query for all `Item' *properties*. Notice
8098 // that the actual methods are pointed from here.
8100 // This is a group of properties, piles of them.
8102 bool found_any = false, found_any_getters = false;
8103 Type lookup_type = indexer_type;
8105 Indexers ilist;
8106 ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
8107 if (ilist != null) {
8108 found_any = true;
8109 if (ilist.Properties != null) {
8110 foreach (Indexers.Indexer ix in ilist.Properties) {
8111 if (ix.Getter != null)
8112 AllGetters.Add(ix.Getter);
8117 if (AllGetters.Count > 0) {
8118 found_any_getters = true;
8119 get = (MethodInfo) Invocation.OverloadResolve (
8120 ec, new MethodGroupExpr (AllGetters, loc),
8121 arguments, false, loc);
8124 if (!found_any) {
8125 Report.Error (21, loc,
8126 "Type `" + TypeManager.CSharpName (indexer_type) +
8127 "' does not have any indexers defined");
8128 return null;
8131 if (!found_any_getters) {
8132 Error (154, "indexer can not be used in this context, because " +
8133 "it lacks a `get' accessor");
8134 return null;
8137 if (get == null) {
8138 Error (1501, "No Overload for method `this' takes `" +
8139 arguments.Count + "' arguments");
8140 return null;
8144 // Only base will allow this invocation to happen.
8146 if (get.IsAbstract && this is BaseIndexerAccess){
8147 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get));
8148 return null;
8151 type = get.ReturnType;
8152 if (type.IsPointer && !ec.InUnsafe){
8153 UnsafeError (loc);
8154 return null;
8157 eclass = ExprClass.IndexerAccess;
8158 return this;
8161 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8163 ArrayList AllSetters = new ArrayList();
8164 if (!CommonResolve (ec))
8165 return null;
8167 bool found_any = false, found_any_setters = false;
8169 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
8170 if (ilist != null) {
8171 found_any = true;
8172 if (ilist.Properties != null) {
8173 foreach (Indexers.Indexer ix in ilist.Properties) {
8174 if (ix.Setter != null)
8175 AllSetters.Add(ix.Setter);
8179 if (AllSetters.Count > 0) {
8180 found_any_setters = true;
8181 set_arguments = (ArrayList) arguments.Clone ();
8182 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8183 set = (MethodInfo) Invocation.OverloadResolve (
8184 ec, new MethodGroupExpr (AllSetters, loc),
8185 set_arguments, false, loc);
8188 if (!found_any) {
8189 Report.Error (21, loc,
8190 "Type `" + TypeManager.CSharpName (indexer_type) +
8191 "' does not have any indexers defined");
8192 return null;
8195 if (!found_any_setters) {
8196 Error (154, "indexer can not be used in this context, because " +
8197 "it lacks a `set' accessor");
8198 return null;
8201 if (set == null) {
8202 Error (1501, "No Overload for method `this' takes `" +
8203 arguments.Count + "' arguments");
8204 return null;
8208 // Only base will allow this invocation to happen.
8210 if (set.IsAbstract && this is BaseIndexerAccess){
8211 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set));
8212 return null;
8216 // Now look for the actual match in the list of indexers to set our "return" type
8218 type = TypeManager.void_type; // default value
8219 foreach (Indexers.Indexer ix in ilist.Properties){
8220 if (ix.Setter == set){
8221 type = ix.Type;
8222 break;
8226 eclass = ExprClass.IndexerAccess;
8227 return this;
8230 bool prepared = false;
8231 LocalTemporary temp;
8233 public void Emit (EmitContext ec, bool leave_copy)
8235 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
8236 if (leave_copy) {
8237 ec.ig.Emit (OpCodes.Dup);
8238 temp = new LocalTemporary (ec, Type);
8239 temp.Store (ec);
8244 // source is ignored, because we already have a copy of it from the
8245 // LValue resolution and we have already constructed a pre-cached
8246 // version of the arguments (ea.set_arguments);
8248 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8250 prepared = prepare_for_load;
8251 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
8253 if (prepared) {
8254 source.Emit (ec);
8255 if (leave_copy) {
8256 ec.ig.Emit (OpCodes.Dup);
8257 temp = new LocalTemporary (ec, Type);
8258 temp.Store (ec);
8260 } else if (leave_copy) {
8261 temp = new LocalTemporary (ec, Type);
8262 source.Emit (ec);
8263 temp.Store (ec);
8264 a.Expr = temp;
8267 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
8269 if (temp != null)
8270 temp.Emit (ec);
8274 public override void Emit (EmitContext ec)
8276 Emit (ec, false);
8280 /// <summary>
8281 /// The base operator for method names
8282 /// </summary>
8283 public class BaseAccess : Expression {
8284 string member;
8286 public BaseAccess (string member, Location l)
8288 this.member = member;
8289 loc = l;
8292 public override Expression DoResolve (EmitContext ec)
8294 Expression c = CommonResolve (ec);
8296 if (c == null)
8297 return null;
8300 // MethodGroups use this opportunity to flag an error on lacking ()
8302 if (!(c is MethodGroupExpr))
8303 return c.Resolve (ec);
8304 return c;
8307 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8309 Expression c = CommonResolve (ec);
8311 if (c == null)
8312 return null;
8315 // MethodGroups use this opportunity to flag an error on lacking ()
8317 if (! (c is MethodGroupExpr))
8318 return c.DoResolveLValue (ec, right_side);
8320 return c;
8323 Expression CommonResolve (EmitContext ec)
8325 Expression member_lookup;
8326 Type current_type = ec.ContainerType;
8327 Type base_type = current_type.BaseType;
8328 Expression e;
8330 if (ec.IsStatic){
8331 Error (1511, "Keyword base is not allowed in static method");
8332 return null;
8335 if (ec.IsFieldInitializer){
8336 Error (1512, "Keyword base is not available in the current context");
8337 return null;
8340 member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type, member,
8341 AllMemberTypes, AllBindingFlags, loc);
8342 if (member_lookup == null) {
8343 MemberLookupFailed (ec, base_type, base_type, member, null, loc);
8344 return null;
8347 Expression left;
8349 if (ec.IsStatic)
8350 left = new TypeExpression (base_type, loc);
8351 else
8352 left = ec.GetThis (loc);
8354 e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
8356 if (e is PropertyExpr){
8357 PropertyExpr pe = (PropertyExpr) e;
8359 pe.IsBase = true;
8362 if (e is MethodGroupExpr)
8363 ((MethodGroupExpr) e).IsBase = true;
8365 return e;
8368 public override void Emit (EmitContext ec)
8370 throw new Exception ("Should never be called");
8374 /// <summary>
8375 /// The base indexer operator
8376 /// </summary>
8377 public class BaseIndexerAccess : IndexerAccess {
8378 public BaseIndexerAccess (ArrayList args, Location loc)
8379 : base (null, true, loc)
8381 arguments = new ArrayList ();
8382 foreach (Expression tmp in args)
8383 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8386 protected override bool CommonResolve (EmitContext ec)
8388 instance_expr = ec.GetThis (loc);
8390 current_type = ec.ContainerType.BaseType;
8391 indexer_type = current_type;
8393 foreach (Argument a in arguments){
8394 if (!a.Resolve (ec, loc))
8395 return false;
8398 return true;
8402 /// <summary>
8403 /// This class exists solely to pass the Type around and to be a dummy
8404 /// that can be passed to the conversion functions (this is used by
8405 /// foreach implementation to typecast the object return value from
8406 /// get_Current into the proper type. All code has been generated and
8407 /// we only care about the side effect conversions to be performed
8409 /// This is also now used as a placeholder where a no-action expression
8410 /// is needed (the `New' class).
8411 /// </summary>
8412 public class EmptyExpression : Expression {
8413 public static readonly EmptyExpression Null = new EmptyExpression ();
8415 // TODO: should be protected
8416 public EmptyExpression ()
8418 type = TypeManager.object_type;
8419 eclass = ExprClass.Value;
8420 loc = Location.Null;
8423 public EmptyExpression (Type t)
8425 type = t;
8426 eclass = ExprClass.Value;
8427 loc = Location.Null;
8430 public override Expression DoResolve (EmitContext ec)
8432 return this;
8435 public override void Emit (EmitContext ec)
8437 // nothing, as we only exist to not do anything.
8441 // This is just because we might want to reuse this bad boy
8442 // instead of creating gazillions of EmptyExpressions.
8443 // (CanImplicitConversion uses it)
8445 public void SetType (Type t)
8447 type = t;
8451 public class UserCast : Expression {
8452 MethodBase method;
8453 Expression source;
8455 public UserCast (MethodInfo method, Expression source, Location l)
8457 this.method = method;
8458 this.source = source;
8459 type = method.ReturnType;
8460 eclass = ExprClass.Value;
8461 loc = l;
8464 public override Expression DoResolve (EmitContext ec)
8467 // We are born fully resolved
8469 return this;
8472 public override void Emit (EmitContext ec)
8474 ILGenerator ig = ec.ig;
8476 source.Emit (ec);
8478 if (method is MethodInfo)
8479 ig.Emit (OpCodes.Call, (MethodInfo) method);
8480 else
8481 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8486 // <summary>
8487 // This class is used to "construct" the type during a typecast
8488 // operation. Since the Type.GetType class in .NET can parse
8489 // the type specification, we just use this to construct the type
8490 // one bit at a time.
8491 // </summary>
8492 public class ComposedCast : TypeExpr {
8493 Expression left;
8494 string dim;
8496 public ComposedCast (Expression left, string dim, Location l)
8498 this.left = left;
8499 this.dim = dim;
8500 loc = l;
8503 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
8505 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8506 if (lexpr == null)
8507 return null;
8509 Type ltype = lexpr.ResolveType (ec);
8511 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8512 Report.Error (1547, Location,
8513 "Keyword 'void' cannot be used in this context");
8514 return null;
8518 // ltype.Fullname is already fully qualified, so we can skip
8519 // a lot of probes, and go directly to TypeManager.LookupType
8521 string cname = ltype.FullName + dim;
8522 type = TypeManager.LookupTypeDirect (cname);
8523 if (type == null){
8525 // For arrays of enumerations we are having a problem
8526 // with the direct lookup. Need to investigate.
8528 // For now, fall back to the full lookup in that case.
8530 type = RootContext.LookupType (
8531 ec.DeclSpace, cname, false, loc);
8533 if (type == null)
8534 return null;
8537 if (!ec.InUnsafe && type.IsPointer){
8538 UnsafeError (loc);
8539 return null;
8542 eclass = ExprClass.Type;
8543 return this;
8546 public override string Name {
8547 get {
8548 return left + dim;
8554 // This class is used to represent the address of an array, used
8555 // only by the Fixed statement, this is like the C "&a [0]" construct.
8557 public class ArrayPtr : Expression {
8558 Expression array;
8560 public ArrayPtr (Expression array, Location l)
8562 Type array_type = TypeManager.GetElementType (array.Type);
8564 this.array = array;
8566 type = TypeManager.GetPointerType (array_type);
8567 eclass = ExprClass.Value;
8568 loc = l;
8571 public override void Emit (EmitContext ec)
8573 ILGenerator ig = ec.ig;
8575 array.Emit (ec);
8576 IntLiteral.EmitInt (ig, 0);
8577 ig.Emit (OpCodes.Ldelema, TypeManager.GetElementType (array.Type));
8580 public override Expression DoResolve (EmitContext ec)
8583 // We are born fully resolved
8585 return this;
8590 // Used by the fixed statement
8592 public class StringPtr : Expression {
8593 LocalBuilder b;
8595 public StringPtr (LocalBuilder b, Location l)
8597 this.b = b;
8598 eclass = ExprClass.Value;
8599 type = TypeManager.char_ptr_type;
8600 loc = l;
8603 public override Expression DoResolve (EmitContext ec)
8605 // This should never be invoked, we are born in fully
8606 // initialized state.
8608 return this;
8611 public override void Emit (EmitContext ec)
8613 ILGenerator ig = ec.ig;
8615 ig.Emit (OpCodes.Ldloc, b);
8616 ig.Emit (OpCodes.Conv_I);
8617 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8618 ig.Emit (OpCodes.Add);
8623 // Implements the `stackalloc' keyword
8625 public class StackAlloc : Expression {
8626 Type otype;
8627 Expression t;
8628 Expression count;
8630 public StackAlloc (Expression type, Expression count, Location l)
8632 t = type;
8633 this.count = count;
8634 loc = l;
8637 public override Expression DoResolve (EmitContext ec)
8639 count = count.Resolve (ec);
8640 if (count == null)
8641 return null;
8643 if (count.Type != TypeManager.int32_type){
8644 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8645 if (count == null)
8646 return null;
8649 Constant c = count as Constant;
8650 if (c != null && c.IsNegative) {
8651 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8652 return null;
8655 if (ec.CurrentBranching.InCatch () ||
8656 ec.CurrentBranching.InFinally (true)) {
8657 Error (255,
8658 "stackalloc can not be used in a catch or finally block");
8659 return null;
8662 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8663 if (texpr == null)
8664 return null;
8666 otype = texpr.ResolveType (ec);
8668 if (!TypeManager.VerifyUnManaged (otype, loc))
8669 return null;
8671 type = TypeManager.GetPointerType (otype);
8672 eclass = ExprClass.Value;
8674 return this;
8677 public override void Emit (EmitContext ec)
8679 int size = GetTypeSize (otype);
8680 ILGenerator ig = ec.ig;
8682 if (size == 0)
8683 ig.Emit (OpCodes.Sizeof, otype);
8684 else
8685 IntConstant.EmitInt (ig, size);
8686 count.Emit (ec);
8687 ig.Emit (OpCodes.Mul);
8688 ig.Emit (OpCodes.Localloc);