2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001, 2002, 2003 Ximian, Inc.
8 // (C) 2003, 2004 Novell, Inc.
12 namespace Mono
.CSharp
{
14 using System
.Collections
;
15 using System
.Reflection
;
16 using System
.Reflection
.Emit
;
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
24 public class StaticCallExpr
: ExpressionStatement
{
28 public StaticCallExpr (MethodInfo m
, ArrayList a
, Location l
)
34 eclass
= ExprClass
.Value
;
38 public override Expression
DoResolve (EmitContext ec
)
41 // We are born fully resolved
46 public override void Emit (EmitContext ec
)
49 Invocation
.EmitArguments (ec
, mi
, args
, false, null);
51 ec
.ig
.Emit (OpCodes
.Call
, mi
);
55 static public StaticCallExpr
MakeSimpleCall (EmitContext ec
, MethodGroupExpr mg
,
56 Expression e
, Location loc
)
61 args
= new ArrayList (1);
62 Argument a
= new Argument (e
, Argument
.AType
.Expression
);
64 // We need to resolve the arguments before sending them in !
65 if (!a
.Resolve (ec
, loc
))
69 method
= Invocation
.OverloadResolve (
70 ec
, (MethodGroupExpr
) mg
, args
, false, loc
);
75 return new StaticCallExpr ((MethodInfo
) method
, args
, loc
);
78 public override void EmitStatement (EmitContext ec
)
81 if (TypeManager
.TypeToCoreType (type
) != TypeManager
.void_type
)
82 ec
.ig
.Emit (OpCodes
.Pop
);
85 public MethodInfo Method
{
90 public class ParenthesizedExpression
: Expression
92 public Expression Expr
;
94 public ParenthesizedExpression (Expression expr
, Location loc
)
100 public override Expression
DoResolve (EmitContext ec
)
102 Expr
= Expr
.Resolve (ec
);
106 public override void Emit (EmitContext ec
)
108 throw new Exception ("Should not happen");
113 /// Unary expressions.
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.
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
)
138 /// Returns a stringified representation of the Operator
140 static public string OperName (Operator oper
)
143 case Operator
.UnaryPlus
:
145 case Operator
.UnaryNegation
:
147 case Operator
.LogicalNot
:
149 case Operator
.OnesComplement
:
151 case Operator
.AddressOf
:
153 case Operator
.Indirection
:
157 return oper
.ToString ();
160 public static readonly string [] oper_names
;
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
)
177 23, "Operator " + OperName (Oper
) +
178 " cannot be applied to operand of type `" +
179 TypeManager
.CSharpName (t
) + "'");
183 /// The result has been already resolved:
185 /// FIXME: a minus constant -128 sbyte cant be turned into a
188 static Expression
TryReduceNegative (Constant expr
)
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);
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
);
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
229 bool Reduce (EmitContext ec
, Constant e
, out Expression result
)
231 Type expr_type
= e
.Type
;
234 case Operator
.UnaryPlus
:
238 case Operator
.UnaryNegation
:
239 result
= TryReduceNegative (e
);
242 case Operator
.LogicalNot
:
243 if (expr_type
!= TypeManager
.bool_type
) {
249 BoolConstant b
= (BoolConstant
) e
;
250 result
= new BoolConstant (!(b
.Value
));
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
)))){
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
)){
281 expr_type
= result
.Type
;
282 e
= (Constant
) result
;
285 if (e
is EnumConstant
){
286 EnumConstant enum_constant
= (EnumConstant
) e
;
289 if (Reduce (ec
, enum_constant
.Child
, out reduced
)){
290 result
= new EnumConstant ((Constant
) reduced
, enum_constant
.Type
);
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
);
313 case Operator
.AddressOf
:
317 case Operator
.Indirection
:
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
334 op_name
= oper_names
[(int) Oper
];
336 mg
= MemberLookup (ec
, expr_type
, op_name
, MemberTypes
.Method
, AllBindingFlags
, loc
);
339 Expression e
= StaticCallExpr
.MakeSimpleCall (
340 ec
, (MethodGroupExpr
) mg
, Expr
, loc
);
350 // Only perform numeric promotions on:
353 if (expr_type
== null)
357 // Step 2: Default operations on CLI native types.
360 // Attempt to use a constant folding operation.
361 if (Expr
is Constant
){
364 if (Reduce (ec
, (Constant
) Expr
, out result
))
369 case Operator
.LogicalNot
:
370 if (expr_type
!= TypeManager
.bool_type
) {
371 Expr
= ResolveBoolean (ec
, Expr
, loc
);
378 type
= TypeManager
.bool_type
;
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
)))){
389 e
= Convert
.ImplicitConversion (ec
, Expr
, TypeManager
.int32_type
, loc
);
391 type
= TypeManager
.int32_type
;
394 e
= Convert
.ImplicitConversion (ec
, Expr
, TypeManager
.uint32_type
, loc
);
396 type
= TypeManager
.uint32_type
;
399 e
= Convert
.ImplicitConversion (ec
, Expr
, TypeManager
.int64_type
, loc
);
401 type
= TypeManager
.int64_type
;
404 e
= Convert
.ImplicitConversion (ec
, Expr
, TypeManager
.uint64_type
, loc
);
406 type
= TypeManager
.uint64_type
;
415 case Operator
.AddressOf
:
416 if (Expr
.eclass
!= ExprClass
.Variable
){
417 Error (211, "Cannot take the address of non-variables");
426 if (!TypeManager
.VerifyUnManaged (Expr
.Type
, loc
)){
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");
437 if (ec
.InFixedInitializer
&& ((variable
!= null) && variable
.VerifyFixed (false))) {
438 Error (213, "You can not fix an already fixed expression");
442 // According to the specs, a variable is considered definitely assigned if you take
444 if ((variable
!= null) && (variable
.VariableInfo
!= null))
445 variable
.VariableInfo
.SetAssigned (ec
);
447 type
= TypeManager
.GetPointerType (Expr
.Type
);
450 case Operator
.Indirection
:
456 if (!expr_type
.IsPointer
){
457 Error (193, "The * or -> operator can only be applied to pointers");
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.
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
488 Unary unary
= (Unary
) Expr
;
490 if (unary
.Oper
== Operator
.UnaryNegation
)
495 // perform numeric promotions to int,
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
);
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.
526 if (expr_type
== TypeManager
.float_type
){
531 expr
= Convert
.ImplicitConversion (ec
, Expr
, TypeManager
.int32_type
, loc
);
538 expr
= Convert
.ImplicitConversion (ec
, Expr
, TypeManager
.int64_type
, loc
);
545 expr
= Convert
.ImplicitConversion (ec
, Expr
, TypeManager
.double_type
, loc
);
556 Error (187, "No such operator '" + OperName (Oper
) + "' defined for type '" +
557 TypeManager
.CSharpName (expr_type
) + "'");
561 public override Expression
DoResolve (EmitContext ec
)
563 if (Oper
== Operator
.AddressOf
)
564 Expr
= Expr
.ResolveLValue (ec
, new EmptyExpression ());
566 Expr
= Expr
.Resolve (ec
);
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");
585 public override void Emit (EmitContext ec
)
587 ILGenerator ig
= ec
.ig
;
590 case Operator
.UnaryPlus
:
591 throw new Exception ("This should be caught by Resolve");
593 case Operator
.UnaryNegation
:
595 ig
.Emit (OpCodes
.Ldc_I4_0
);
596 if (type
== TypeManager
.int64_type
)
597 ig
.Emit (OpCodes
.Conv_U8
);
599 ig
.Emit (OpCodes
.Sub_Ovf
);
602 ig
.Emit (OpCodes
.Neg
);
607 case Operator
.LogicalNot
:
609 ig
.Emit (OpCodes
.Ldc_I4_0
);
610 ig
.Emit (OpCodes
.Ceq
);
613 case Operator
.OnesComplement
:
615 ig
.Emit (OpCodes
.Not
);
618 case Operator
.AddressOf
:
619 ((IMemoryLocation
)Expr
).AddressOf (ec
, AddressOp
.LoadStore
);
623 throw new Exception ("This should not happen: Operator = "
628 public override void EmitBranchable (EmitContext ec
, Label target
, bool onTrue
)
630 if (Oper
== Operator
.LogicalNot
)
631 Expr
.EmitBranchable (ec
, target
, !onTrue
);
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
{
650 LocalTemporary temporary
;
653 public Indirection (Expression expr
, Location l
)
656 this.type
= TypeManager
.GetElementType (expr
.Type
);
657 eclass
= ExprClass
.Variable
;
661 void LoadExprValue (EmitContext ec
)
665 public override void Emit (EmitContext ec
)
670 LoadFromPtr (ec
.ig
, Type
);
673 public void Emit (EmitContext ec
, bool 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
;
689 if (prepare_for_load
)
690 ec
.ig
.Emit (OpCodes
.Dup
);
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)
705 public void AddressOf (EmitContext ec
, AddressOp Mode
)
710 public override Expression
DoResolve (EmitContext ec
)
713 // Born fully resolved
718 public override string ToString ()
720 return "*(" + expr
+ ")";
725 /// Unary Mutator expressions (pre and post ++ and --)
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)
738 public class UnaryMutator
: ExpressionStatement
{
740 public enum Mode
: byte {
747 PreDecrement
= IsDecrement
,
748 PostIncrement
= IsPost
,
749 PostDecrement
= IsPost
| IsDecrement
753 bool is_expr
= false;
754 bool recurse
= false;
759 // This is expensive for the simplest case.
761 StaticCallExpr method
;
763 public UnaryMutator (Mode m
, Expression e
, Location l
)
770 static string OperName (Mode mode
)
772 return (mode
== Mode
.PreIncrement
|| mode
== Mode
.PostIncrement
) ?
776 void Error23 (Type t
)
779 23, "Operator " + OperName (mode
) +
780 " cannot be applied to operand of type `" +
781 TypeManager
.CSharpName (t
) + "'");
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)
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
817 if (mode
== Mode
.PreIncrement
|| mode
== Mode
.PostIncrement
)
818 op_name
= "op_Increment";
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
);
829 method
= StaticCallExpr
.MakeSimpleCall (
830 ec
, (MethodGroupExpr
) mg
, expr
, loc
);
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
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
){
850 } else if (expr
.eclass
== ExprClass
.IndexerAccess
){
851 IndexerAccess ia
= (IndexerAccess
) expr
;
853 expr
= ia
.ResolveLValue (ec
, this);
858 } else if (expr
.eclass
== ExprClass
.PropertyAccess
){
859 PropertyExpr pe
= (PropertyExpr
) expr
;
861 if (pe
.VerifyAssignable ())
866 expr
.Error_UnexpectedKind ("variable, indexer or property access", loc
);
870 Error (187, "No such operator '" + OperName (mode
) + "' defined for type '" +
871 TypeManager
.CSharpName (expr_type
) + "'");
875 public override Expression
DoResolve (EmitContext ec
)
877 expr
= expr
.Resolve (ec
);
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
);
913 ig
.Emit (OpCodes
.Sizeof
, t
);
915 IntConstant
.EmitInt (ig
, n
);
917 ig
.Emit (OpCodes
.Ldc_I4_1
);
920 // Now emit the operation
923 if (t
== TypeManager
.int32_type
||
924 t
== TypeManager
.int64_type
){
925 if ((mode
& Mode
.IsDecrement
) != 0)
926 ig
.Emit (OpCodes
.Sub_Ovf
);
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
);
934 ig
.Emit (OpCodes
.Add_Ovf_Un
);
936 if ((mode
& Mode
.IsDecrement
) != 0)
937 ig
.Emit (OpCodes
.Sub_Ovf
);
939 ig
.Emit (OpCodes
.Add_Ovf
);
942 if ((mode
& Mode
.IsDecrement
) != 0)
943 ig
.Emit (OpCodes
.Sub
);
945 ig
.Emit (OpCodes
.Add
);
948 if (t
== TypeManager
.sbyte_type
){
950 ig
.Emit (OpCodes
.Conv_Ovf_I1
);
952 ig
.Emit (OpCodes
.Conv_I1
);
953 } else if (t
== TypeManager
.byte_type
){
955 ig
.Emit (OpCodes
.Conv_Ovf_U1
);
957 ig
.Emit (OpCodes
.Conv_U1
);
958 } else if (t
== TypeManager
.short_type
){
960 ig
.Emit (OpCodes
.Conv_Ovf_I2
);
962 ig
.Emit (OpCodes
.Conv_I2
);
963 } else if (t
== TypeManager
.ushort_type
|| t
== TypeManager
.char_type
){
965 ig
.Emit (OpCodes
.Conv_Ovf_U2
);
967 ig
.Emit (OpCodes
.Conv_U2
);
972 void EmitCode (EmitContext ec
, bool is_expr
)
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
988 ((IAssignMethod
) expr
).Emit (ec
, is_expr
&& (mode
== Mode
.PostIncrement
|| mode
== Mode
.PostDecrement
));
990 LoadOneAndEmitOp (ec
, expr
.Type
);
992 ec
.ig
.Emit (OpCodes
.Call
, method
.Method
);
1000 public override void EmitStatement (EmitContext ec
)
1002 EmitCode (ec
, false);
1007 /// Base class for the `Is' and `As' classes.
1011 /// FIXME: Split this in two, and we get to save the `Operator' Oper
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
;
1026 public Expression Expr
{
1032 public override Expression
DoResolve (EmitContext ec
)
1034 TypeExpr texpr
= ProbeType
.ResolveAsTypeTerminal (ec
, false);
1037 probe_type
= texpr
.ResolveType (ec
);
1039 CheckObsoleteAttribute (probe_type
);
1041 expr
= expr
.Resolve (ec
);
1045 if (expr
.Type
.IsPointer
) {
1046 Report
.Error (244, loc
, "\"is\" or \"as\" are not valid on pointer types");
1054 /// Implementation of the `is' operator.
1056 public class Is
: Probe
{
1057 public Is (Expression expr
, Expression probe_type
, Location l
)
1058 : base (expr
, probe_type
, l
)
1063 AlwaysTrue
, AlwaysNull
, AlwaysFalse
, LeaveOnStack
, Probe
1068 public override void Emit (EmitContext ec
)
1070 ILGenerator ig
= ec
.ig
;
1075 case Action
.AlwaysFalse
:
1076 ig
.Emit (OpCodes
.Pop
);
1077 IntConstant
.EmitInt (ig
, 0);
1079 case Action
.AlwaysTrue
:
1080 ig
.Emit (OpCodes
.Pop
);
1081 IntConstant
.EmitInt (ig
, 1);
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
);
1091 ig
.Emit (OpCodes
.Isinst
, probe_type
);
1092 ig
.Emit (OpCodes
.Ldnull
);
1093 ig
.Emit (OpCodes
.Cgt_Un
);
1096 throw new Exception ("never reached");
1099 public override void EmitBranchable (EmitContext ec
, Label target
, bool onTrue
)
1101 ILGenerator ig
= ec
.ig
;
1104 case Action
.AlwaysFalse
:
1106 ig
.Emit (OpCodes
.Br
, target
);
1109 case Action
.AlwaysTrue
:
1111 ig
.Emit (OpCodes
.Br
, target
);
1114 case Action
.LeaveOnStack
:
1115 // the `e != null' rule.
1117 ig
.Emit (onTrue
? OpCodes
.Brtrue
: OpCodes
.Brfalse
, target
);
1121 ig
.Emit (OpCodes
.Isinst
, probe_type
);
1122 ig
.Emit (onTrue
? OpCodes
.Brtrue
: OpCodes
.Brfalse
, target
);
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))
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
);
1149 if (etype
.IsValueType
)
1150 action
= Action
.AlwaysTrue
;
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
;
1162 action
= Action
.Probe
;
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
));
1180 /// Implementation of the `as' operator.
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
;
1197 ig
.Emit (OpCodes
.Isinst
, probe_type
);
1200 static void Error_CannotConvertType (Type source
, Type target
, Location loc
)
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
);
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)");
1226 e
= Convert
.ImplicitConversion (ec
, expr
, probe_type
, loc
);
1233 if (Convert
.ExplicitReferenceConversionExists (etype
, probe_type
)){
1238 Error_CannotConvertType (etype
, probe_type
, loc
);
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.
1249 public class Cast
: Expression
{
1250 Expression target_type
;
1253 public Cast (Expression cast_type
, Expression expr
, Location loc
)
1255 this.target_type
= cast_type
;
1260 public Expression TargetType
{
1266 public Expression Expr
{
1275 bool CheckRange (EmitContext ec
, long value, Type type
, long min
, long max
)
1277 if (!ec
.ConstantCheckState
)
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)");
1290 bool CheckRange (EmitContext ec
, ulong value, Type type
, ulong max
)
1292 if (!ec
.ConstantCheckState
)
1296 Error (221, "Constant value `" + value + "' cannot be converted " +
1297 "to a `" + TypeManager
.CSharpName (type
) + "' (use `unchecked' " +
1298 "syntax to override)");
1305 bool CheckUnsigned (EmitContext ec
, long value, Type type
)
1307 if (!ec
.ConstantCheckState
)
1311 Error (221, "Constant value `" + value + "' cannot be converted " +
1312 "to a `" + TypeManager
.CSharpName (type
) + "' (use `unchecked' " +
1313 "syntax to override)");
1321 /// Attempts to do a compile-time folding of a constant cast.
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
))
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
))
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
))
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
))
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
))
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
))
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
))
1403 return new ByteConstant ((byte) v
);
1405 if (target_type
== TypeManager
.sbyte_type
) {
1406 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1408 return new SByteConstant ((sbyte) v
);
1410 if (target_type
== TypeManager
.ushort_type
) {
1411 if (!CheckUnsigned (ec
, v
, target_type
))
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
))
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
))
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
))
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
))
1447 return new ByteConstant ((byte) v
);
1449 if (target_type
== TypeManager
.sbyte_type
) {
1450 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1452 return new SByteConstant ((sbyte) v
);
1454 if (target_type
== TypeManager
.short_type
) {
1455 if (!CheckRange (ec
, v
, target_type
, Int16
.MinValue
, Int16
.MaxValue
))
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
))
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
))
1485 return new ByteConstant ((byte) v
);
1487 if (target_type
== TypeManager
.sbyte_type
) {
1488 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1490 return new SByteConstant ((sbyte) v
);
1492 if (target_type
== TypeManager
.short_type
) {
1493 if (!CheckRange (ec
, v
, target_type
, Int16
.MinValue
, Int16
.MaxValue
))
1495 return new ShortConstant ((short) v
);
1497 if (target_type
== TypeManager
.ushort_type
) {
1498 if (!CheckRange (ec
, v
, target_type
, UInt16
.MinValue
, UInt16
.MaxValue
))
1500 return new UShortConstant ((ushort) v
);
1502 if (target_type
== TypeManager
.uint32_type
) {
1503 if (!CheckRange (ec
, v
, target_type
, Int32
.MinValue
, Int32
.MaxValue
))
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
))
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
))
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
))
1532 return new ByteConstant ((byte) v
);
1534 if (target_type
== TypeManager
.sbyte_type
) {
1535 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1537 return new SByteConstant ((sbyte) v
);
1539 if (target_type
== TypeManager
.short_type
) {
1540 if (!CheckRange (ec
, v
, target_type
, Int16
.MinValue
, Int16
.MaxValue
))
1542 return new ShortConstant ((short) v
);
1544 if (target_type
== TypeManager
.ushort_type
) {
1545 if (!CheckRange (ec
, v
, target_type
, UInt16
.MinValue
, UInt16
.MaxValue
))
1547 return new UShortConstant ((ushort) v
);
1549 if (target_type
== TypeManager
.int32_type
) {
1550 if (!CheckRange (ec
, v
, target_type
, Int32
.MinValue
, Int32
.MaxValue
))
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
))
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
))
1576 return new ByteConstant ((byte) v
);
1578 if (target_type
== TypeManager
.sbyte_type
) {
1579 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1581 return new SByteConstant ((sbyte) v
);
1583 if (target_type
== TypeManager
.short_type
) {
1584 if (!CheckRange (ec
, v
, target_type
, Int16
.MinValue
, Int16
.MaxValue
))
1586 return new ShortConstant ((short) v
);
1588 if (target_type
== TypeManager
.ushort_type
) {
1589 if (!CheckRange (ec
, v
, target_type
, UInt16
.MinValue
, UInt16
.MaxValue
))
1591 return new UShortConstant ((ushort) v
);
1593 if (target_type
== TypeManager
.int32_type
) {
1594 if (!CheckRange (ec
, v
, target_type
, Int32
.MinValue
, Int32
.MaxValue
))
1596 return new IntConstant ((int) v
);
1598 if (target_type
== TypeManager
.uint32_type
) {
1599 if (!CheckRange (ec
, v
, target_type
, UInt32
.MinValue
, UInt32
.MaxValue
))
1601 return new UIntConstant ((uint) v
);
1603 if (target_type
== TypeManager
.uint64_type
) {
1604 if (!CheckUnsigned (ec
, v
, target_type
))
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
))
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
))
1626 return new ByteConstant ((byte) v
);
1628 if (target_type
== TypeManager
.sbyte_type
) {
1629 if (!CheckRange (ec
, v
, target_type
, (ulong) SByte
.MaxValue
))
1631 return new SByteConstant ((sbyte) v
);
1633 if (target_type
== TypeManager
.short_type
) {
1634 if (!CheckRange (ec
, v
, target_type
, (ulong) Int16
.MaxValue
))
1636 return new ShortConstant ((short) v
);
1638 if (target_type
== TypeManager
.ushort_type
) {
1639 if (!CheckRange (ec
, v
, target_type
, UInt16
.MaxValue
))
1641 return new UShortConstant ((ushort) v
);
1643 if (target_type
== TypeManager
.int32_type
) {
1644 if (!CheckRange (ec
, v
, target_type
, Int32
.MaxValue
))
1646 return new IntConstant ((int) v
);
1648 if (target_type
== TypeManager
.uint32_type
) {
1649 if (!CheckRange (ec
, v
, target_type
, UInt32
.MaxValue
))
1651 return new UIntConstant ((uint) v
);
1653 if (target_type
== TypeManager
.int64_type
) {
1654 if (!CheckRange (ec
, v
, target_type
, (ulong) Int64
.MaxValue
))
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
))
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
))
1729 return new ByteConstant ((byte) v
);
1731 if (target_type
== TypeManager
.sbyte_type
) {
1732 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1734 return new SByteConstant ((sbyte) v
);
1736 if (target_type
== TypeManager
.short_type
) {
1737 if (!CheckRange (ec
, v
, target_type
, Int16
.MinValue
, Int16
.MaxValue
))
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
))
1756 return new CharConstant ((char) v
);
1758 if (target_type
== TypeManager
.decimal_type
)
1759 return new DecimalConstant ((decimal) v
);
1765 public override Expression
DoResolve (EmitContext ec
)
1767 expr
= expr
.Resolve (ec
);
1771 TypeExpr target
= target_type
.ResolveAsTypeTerminal (ec
, false);
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
));
1784 eclass
= ExprClass
.Value
;
1786 if (expr
is Constant
){
1787 Expression e
= TryReduce (ec
, type
);
1793 if (type
.IsPointer
&& !ec
.InUnsafe
) {
1797 expr
= Convert
.ExplicitConversion (ec
, expr
, type
, loc
);
1801 public override void Emit (EmitContext ec
)
1804 // This one will never happen
1806 throw new Exception ("Should not happen");
1811 /// Binary operators
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
,
1829 Expression left
, right
;
1831 // This must be kept in sync with Operator!!!
1832 public static readonly string [] oper_names
;
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
)
1866 public Operator Oper
{
1875 public Expression Left
{
1884 public Expression Right
{
1895 /// Returns a stringified representation of the Operator
1897 static string OperName (Operator oper
)
1900 case Operator
.Multiply
:
1902 case Operator
.Division
:
1904 case Operator
.Modulus
:
1906 case Operator
.Addition
:
1908 case Operator
.Subtraction
:
1910 case Operator
.LeftShift
:
1912 case Operator
.RightShift
:
1914 case Operator
.LessThan
:
1916 case Operator
.GreaterThan
:
1918 case Operator
.LessThanOrEqual
:
1920 case Operator
.GreaterThanOrEqual
:
1922 case Operator
.Equality
:
1924 case Operator
.Inequality
:
1926 case Operator
.BitwiseAnd
:
1928 case Operator
.BitwiseOr
:
1930 case Operator
.ExclusiveOr
:
1932 case Operator
.LogicalOr
:
1934 case Operator
.LogicalAnd
:
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
)
1952 return Convert
.ImplicitConversion (ec
, expr
, target_type
, loc
);
1955 public static void Error_OperatorAmbiguous (Location loc
, Operator oper
, Type l
, Type r
)
1958 34, loc
, "Operator `" + OperName (oper
)
1959 + "' is ambiguous on operands of type `"
1960 + TypeManager
.CSharpName (l
) + "' "
1961 + "and `" + TypeManager
.CSharpName (r
)
1965 bool IsOfType (EmitContext ec
, Type l
, Type r
, Type t
, bool check_user_conversions
)
1967 if ((l
== t
) || (r
== t
))
1970 if (!check_user_conversions
)
1973 if (Convert
.ImplicitUserConversionExists (ec
, l
, t
))
1975 else if (Convert
.ImplicitUserConversionExists (ec
, r
, t
))
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
)){
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
);
2029 } else if (right
is LongConstant
){
2030 long ll
= ((LongConstant
) right
).Value
;
2033 right
= new ULongConstant ((ulong) ll
);
2035 e
= Convert
.ImplicitNumericConversion (ec
, right
, l
, loc
);
2042 if (left
is IntConstant
){
2043 e
= Convert
.TryImplicitIntConversion (r
, (IntConstant
) left
);
2046 } else if (left
is LongConstant
){
2047 long ll
= ((LongConstant
) left
).Value
;
2050 left
= new ULongConstant ((ulong) ll
);
2052 e
= Convert
.ImplicitNumericConversion (ec
, left
, r
, loc
);
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
);
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
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).
2088 if (l
== TypeManager
.uint32_type
){
2089 if (right
is IntConstant
){
2090 IntConstant ic
= (IntConstant
) right
;
2094 right
= new UIntConstant ((uint) val
);
2101 } else if (r
== TypeManager
.uint32_type
){
2102 if (left
is IntConstant
){
2103 IntConstant ic
= (IntConstant
) left
;
2107 left
= new UIntConstant ((uint) val
);
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
;
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
;
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
))
2176 Expression
Make32or64 (EmitContext ec
, Expression e
)
2180 if (t
== TypeManager
.int32_type
|| t
== TypeManager
.uint32_type
||
2181 t
== TypeManager
.int64_type
|| t
== TypeManager
.uint64_type
)
2183 Expression ee
= Convert
.ImplicitConversion (ec
, e
, TypeManager
.int32_type
, loc
);
2186 ee
= Convert
.ImplicitConversion (ec
, e
, TypeManager
.uint32_type
, loc
);
2189 ee
= Convert
.ImplicitConversion (ec
, e
, TypeManager
.int64_type
, loc
);
2192 ee
= Convert
.ImplicitConversion (ec
, e
, TypeManager
.uint64_type
, loc
);
2198 Expression
CheckShiftArguments (EmitContext ec
)
2202 e
= ForceConversion (ec
, right
, TypeManager
.int32_type
);
2204 Error_OperatorCannotBeApplied ();
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)){
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
);
2220 right
= new Binary (Binary
.Operator
.BitwiseAnd
, right
, new IntLiteral (63), loc
);
2221 right
= right
.DoResolve (ec
);
2226 Error_OperatorCannotBeApplied ();
2230 Expression
ResolveOperator (EmitContext ec
)
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
;
2247 if (l
== TypeManager
.intptr_type
&& r
== TypeManager
.intptr_type
) {
2248 Type
= TypeManager
.bool_type
;
2255 // Do not perform operator overload resolution when both sides are
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
);
2269 right_expr
= MemberLookup (
2270 ec
, r
, op
, MemberTypes
.Method
, AllBindingFlags
, loc
);
2271 union
= Invocation
.MakeUnionSet (left_expr
, right_expr
, loc
);
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 ();
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
2318 type
= TypeManager
.string_type
;
2319 ((StringConcat
) left
).Append (ec
, right
);
2320 return left
.Resolve (ec
);
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
;
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 ();
2351 type
= TypeManager
.bool_type
;
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
;
2371 if (l
.IsSubclassOf (r
) || r
.IsSubclassOf (l
))
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 ();
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
2397 // One of them is a valuetype, but the other one is not.
2399 if (!l
.IsValueType
|| !r
.IsValueType
) {
2400 Error_OperatorCannotBeApplied ();
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
);
2421 if (r
.IsSubclassOf (TypeManager
.delegate_type
)){
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
;
2432 method
= TypeManager
.delegate_remove_delegate_delegate
;
2435 Error_OperatorCannotBeApplied ();
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)
2464 if (r
.IsPointer
&& oper
== Operator
.Subtraction
){
2466 return new PointerArithmetic (
2467 false, left
, right
, TypeManager
.int64_type
,
2470 Expression t
= Make32or64 (ec
, right
);
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
);
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
);
2489 // U operator - (E e, E f)
2491 if (oper
== Operator
.Subtraction
){
2493 type
= TypeManager
.EnumToUnderlying (l
);
2496 Error_OperatorCannotBeApplied ();
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
);
2521 Error_OperatorCannotBeApplied ();
2530 temp
= Convert
.ImplicitConversion (ec
, right
, l
, loc
);
2534 Error_OperatorCannotBeApplied ();
2538 temp
= Convert
.ImplicitConversion (ec
, left
, r
, loc
);
2543 Error_OperatorCannotBeApplied ();
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 ();
2555 type
= TypeManager
.bool_type
;
2559 if (oper
== Operator
.BitwiseAnd
||
2560 oper
== Operator
.BitwiseOr
||
2561 oper
== Operator
.ExclusiveOr
){
2565 Error_OperatorCannotBeApplied ();
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
;
2579 Error_OperatorCannotBeApplied ();
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
){
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
;
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
);
2625 // reload our cached types if required
2630 if (oper
== Operator
.BitwiseAnd
||
2631 oper
== Operator
.BitwiseOr
||
2632 oper
== Operator
.ExclusiveOr
){
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
))){
2642 Error_OperatorCannotBeApplied ();
2646 Error_OperatorCannotBeApplied ();
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
;
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
);
2671 if (left
.eclass
== ExprClass
.Type
) {
2672 Error (75, "Casting a negative value needs to have the value in parentheses.");
2676 left
= left
.Resolve (ec
);
2677 right
= right
.Resolve (ec
);
2679 if (left
== null || right
== 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
);
2694 return ResolveOperator (ec
);
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
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
;
2727 if (((Constant
) right
).IsZeroInteger
) {
2730 ig
.Emit (OpCodes
.Brtrue
, target
);
2732 ig
.Emit (OpCodes
.Brfalse
, target
);
2735 } else if (right
is BoolConstant
) {
2737 if (my_on_true
!= ((BoolConstant
) right
).Value
)
2738 ig
.Emit (OpCodes
.Brtrue
, target
);
2740 ig
.Emit (OpCodes
.Brfalse
, target
);
2745 } else if (oper
== Operator
.LogicalAnd
) {
2748 Label tests_end
= ig
.DefineLabel ();
2750 left
.EmitBranchable (ec
, tests_end
, false);
2751 right
.EmitBranchable (ec
, target
, true);
2752 ig
.MarkLabel (tests_end
);
2754 left
.EmitBranchable (ec
, target
, false);
2755 right
.EmitBranchable (ec
, target
, false);
2760 } else if (oper
== Operator
.LogicalOr
){
2762 left
.EmitBranchable (ec
, target
, true);
2763 right
.EmitBranchable (ec
, target
, true);
2766 Label tests_end
= ig
.DefineLabel ();
2767 left
.EmitBranchable (ec
, tests_end
, true);
2768 right
.EmitBranchable (ec
, target
, false);
2769 ig
.MarkLabel (tests_end
);
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
);
2785 bool isUnsigned
= is_unsigned (t
) || t
== TypeManager
.double_type
|| t
== TypeManager
.float_type
;
2788 case Operator
.Equality
:
2790 ig
.Emit (OpCodes
.Beq
, target
);
2792 ig
.Emit (OpCodes
.Bne_Un
, target
);
2795 case Operator
.Inequality
:
2797 ig
.Emit (OpCodes
.Bne_Un
, target
);
2799 ig
.Emit (OpCodes
.Beq
, target
);
2802 case Operator
.LessThan
:
2805 ig
.Emit (OpCodes
.Blt_Un
, target
);
2807 ig
.Emit (OpCodes
.Blt
, target
);
2810 ig
.Emit (OpCodes
.Bge_Un
, target
);
2812 ig
.Emit (OpCodes
.Bge
, target
);
2815 case Operator
.GreaterThan
:
2818 ig
.Emit (OpCodes
.Bgt_Un
, target
);
2820 ig
.Emit (OpCodes
.Bgt
, target
);
2823 ig
.Emit (OpCodes
.Ble_Un
, target
);
2825 ig
.Emit (OpCodes
.Ble
, target
);
2828 case Operator
.LessThanOrEqual
:
2831 ig
.Emit (OpCodes
.Ble_Un
, target
);
2833 ig
.Emit (OpCodes
.Ble
, target
);
2836 ig
.Emit (OpCodes
.Bgt_Un
, target
);
2838 ig
.Emit (OpCodes
.Bgt
, target
);
2842 case Operator
.GreaterThanOrEqual
:
2845 ig
.Emit (OpCodes
.Bge_Un
, target
);
2847 ig
.Emit (OpCodes
.Bge
, target
);
2850 ig
.Emit (OpCodes
.Blt_Un
, target
);
2852 ig
.Emit (OpCodes
.Blt
, target
);
2855 Console
.WriteLine (oper
);
2856 throw new Exception ("what is THAT");
2860 public override void Emit (EmitContext ec
)
2862 ILGenerator ig
= ec
.ig
;
2867 // Handle short-circuit operators differently
2870 if (oper
== Operator
.LogicalAnd
) {
2871 Label load_zero
= ig
.DefineLabel ();
2872 Label end
= ig
.DefineLabel ();
2874 left
.EmitBranchable (ec
, load_zero
, false);
2876 ig
.Emit (OpCodes
.Br
, end
);
2878 ig
.MarkLabel (load_zero
);
2879 ig
.Emit (OpCodes
.Ldc_I4_0
);
2882 } else if (oper
== Operator
.LogicalOr
) {
2883 Label load_one
= ig
.DefineLabel ();
2884 Label end
= ig
.DefineLabel ();
2886 left
.EmitBranchable (ec
, load_one
, true);
2888 ig
.Emit (OpCodes
.Br
, end
);
2890 ig
.MarkLabel (load_one
);
2891 ig
.Emit (OpCodes
.Ldc_I4_1
);
2899 bool isUnsigned
= is_unsigned (left
.Type
);
2902 case Operator
.Multiply
:
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
;
2909 opcode
= OpCodes
.Mul
;
2911 opcode
= OpCodes
.Mul
;
2915 case Operator
.Division
:
2917 opcode
= OpCodes
.Div_Un
;
2919 opcode
= OpCodes
.Div
;
2922 case Operator
.Modulus
:
2924 opcode
= OpCodes
.Rem_Un
;
2926 opcode
= OpCodes
.Rem
;
2929 case Operator
.Addition
:
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
;
2936 opcode
= OpCodes
.Add
;
2938 opcode
= OpCodes
.Add
;
2941 case Operator
.Subtraction
:
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
;
2948 opcode
= OpCodes
.Sub
;
2950 opcode
= OpCodes
.Sub
;
2953 case Operator
.RightShift
:
2955 opcode
= OpCodes
.Shr_Un
;
2957 opcode
= OpCodes
.Shr
;
2960 case Operator
.LeftShift
:
2961 opcode
= OpCodes
.Shl
;
2964 case Operator
.Equality
:
2965 opcode
= OpCodes
.Ceq
;
2968 case Operator
.Inequality
:
2969 ig
.Emit (OpCodes
.Ceq
);
2970 ig
.Emit (OpCodes
.Ldc_I4_0
);
2972 opcode
= OpCodes
.Ceq
;
2975 case Operator
.LessThan
:
2977 opcode
= OpCodes
.Clt_Un
;
2979 opcode
= OpCodes
.Clt
;
2982 case Operator
.GreaterThan
:
2984 opcode
= OpCodes
.Cgt_Un
;
2986 opcode
= OpCodes
.Cgt
;
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
);
2995 ig
.Emit (OpCodes
.Cgt
);
2996 ig
.Emit (OpCodes
.Ldc_I4_0
);
2998 opcode
= OpCodes
.Ceq
;
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
);
3007 ig
.Emit (OpCodes
.Clt
);
3009 ig
.Emit (OpCodes
.Ldc_I4_0
);
3011 opcode
= OpCodes
.Ceq
;
3014 case Operator
.BitwiseOr
:
3015 opcode
= OpCodes
.Or
;
3018 case Operator
.BitwiseAnd
:
3019 opcode
= OpCodes
.And
;
3022 case Operator
.ExclusiveOr
:
3023 opcode
= OpCodes
.Xor
;
3027 throw new Exception ("This should not happen: Operator = "
3028 + oper
.ToString ());
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
)
3048 eclass
= ExprClass
.Value
;
3051 public override Expression
DoResolve (EmitContext ec
)
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
);
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
{
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
)
3086 type
= TypeManager
.string_type
;
3087 eclass
= ExprClass
.Value
;
3089 operands
= new ArrayList (2);
3094 public override Expression
DoResolve (EmitContext ec
)
3102 public void Append (EmitContext ec
, Expression operand
)
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
);
3116 // Conversion to object
3118 if (operand
.Type
!= TypeManager
.string_type
) {
3119 Expression no
= Convert
.ImplicitConversion (ec
, operand
, TypeManager
.object_type
, loc
);
3122 Binary
.Error_OperatorCannotBeApplied (loc
, "+", TypeManager
.string_type
, operand
.Type
);
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
) {
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?");
3173 concat_method
= is_strings_only
?
3174 TypeManager
.string_concat_string_string
:
3175 TypeManager
.string_concat_object_object
;
3178 concat_method
= is_strings_only
?
3179 TypeManager
.string_concat_string_string_string
:
3180 TypeManager
.string_concat_object_object_object
;
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
)
3191 concat_method
= TypeManager
.string_concat_string_string_string_string
;
3194 concat_method
= is_strings_only
?
3195 TypeManager
.string_concat_string_dot_dot_dot
:
3196 TypeManager
.string_concat_object_dot_dot_dot
;
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
{
3212 public BinaryDelegate (Type t
, MethodInfo mi
, ArrayList args
)
3217 eclass
= ExprClass
.Value
;
3220 public override Expression
DoResolve (EmitContext ec
)
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
{
3237 Argument arg
= (Argument
) args
[1];
3242 public bool IsAddition
{
3244 return method
== TypeManager
.delegate_combine_delegate_delegate
;
3250 // User-defined conditional logical operator
3251 public class ConditionalLogicalOperator
: Expression
{
3252 Expression left
, right
;
3255 public ConditionalLogicalOperator (bool is_and
, Expression left
, Expression right
, Type t
, Location loc
)
3258 eclass
= ExprClass
.Value
;
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
)
3282 Expression operator_group
;
3284 operator_group
= MethodLookup (ec
, type
, is_and
? "op_BitwiseAnd" : "op_BitwiseOr", loc
);
3285 if (operator_group
== 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
)
3298 if ((method
== null) || (method
.ReturnType
!= type
)) {
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)) {
3315 public override void Emit (EmitContext ec
)
3317 ILGenerator ig
= ec
.ig
;
3318 Label false_target
= ig
.DefineLabel ();
3319 Label end_target
= ig
.DefineLabel ();
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
);
3329 ig
.MarkLabel (end_target
);
3333 public class PointerArithmetic
: Expression
{
3334 Expression left
, right
;
3338 // We assume that `l' is always a pointer
3340 public PointerArithmetic (bool is_addition
, Expression l
, Expression r
, Type t
, Location loc
)
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");
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)
3375 ig
.Emit (OpCodes
.Sub
);
3379 ig
.Emit (OpCodes
.Sizeof
, element
);
3381 IntLiteral
.EmitInt (ig
, size
);
3382 ig
.Emit (OpCodes
.Div
);
3384 ig
.Emit (OpCodes
.Conv_I8
);
3387 // handle + and - on (pointer op int)
3390 ig
.Emit (OpCodes
.Conv_I
);
3394 ig
.Emit (OpCodes
.Sizeof
, element
);
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
);
3408 ig
.Emit (OpCodes
.Add
);
3410 ig
.Emit (OpCodes
.Sub
);
3416 /// Implements the ternary conditional operator (?:)
3418 public class Conditional
: Expression
{
3419 Expression expr
, trueExpr
, falseExpr
;
3421 public Conditional (Expression expr
, Expression trueExpr
, Expression falseExpr
, Location l
)
3424 this.trueExpr
= trueExpr
;
3425 this.falseExpr
= falseExpr
;
3429 public Expression Expr
{
3435 public Expression TrueExpr
{
3441 public Expression FalseExpr
{
3447 public override Expression
DoResolve (EmitContext ec
)
3449 expr
= expr
.Resolve (ec
);
3454 if (expr
.Type
!= TypeManager
.bool_type
){
3455 expr
= Expression
.ResolveBoolean (
3462 trueExpr
= trueExpr
.Resolve (ec
);
3463 falseExpr
= falseExpr
.Resolve (ec
);
3465 if (trueExpr
== null || falseExpr
== null)
3468 if ((trueExpr
is NullLiteral
) && (falseExpr
is NullLiteral
))
3471 eclass
= ExprClass
.Value
;
3472 if (trueExpr
.Type
== falseExpr
.Type
)
3473 type
= trueExpr
.Type
;
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
);
3486 // Check if both can convert implicitl to each other's type
3488 if (Convert
.ImplicitConversion (ec
, falseExpr
, true_type
, loc
) != null){
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");
3498 } else if ((conv
= Convert
.ImplicitConversion(ec
, falseExpr
, true_type
,loc
))!= null){
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
) + "'");
3510 if (expr
is BoolConstant
){
3511 BoolConstant bc
= (BoolConstant
) expr
;
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);
3530 ig
.Emit (OpCodes
.Br
, end_target
);
3531 ig
.MarkLabel (false_target
);
3532 falseExpr
.Emit (ec
);
3533 ig
.MarkLabel (end_target
);
3541 public class LocalVariableReference
: Expression
, IAssignMethod
, IMemoryLocation
, IVariable
{
3542 public readonly string Name
;
3543 public readonly Block Block
;
3544 public LocalInfo local_info
;
3547 LocalTemporary temp
;
3549 public LocalVariableReference (Block block
, string name
, Location 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
{
3571 return local_info
.VariableInfo
;
3575 public bool IsReadOnly
{
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){
3593 Error (1604, "cannot assign to `" + Name
+ "' because it is readonly");
3597 if (variable_info
!= null)
3598 variable_info
.SetAssigned (ec
);
3601 Expression e
= Block
.GetConstantExpression (Name
);
3603 local_info
.Used
= true;
3604 eclass
= ExprClass
.Value
;
3605 return e
.Resolve (ec
);
3608 if ((variable_info
!= null) && !variable_info
.IsAssigned (ec
, loc
))
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);
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
);
3637 CheckObsoleteAttribute (ret
.Type
);
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
);
3658 // A local variable captured by anonymous methods.
3661 ec
.EmitCapturedVariableInstance (local_info
);
3663 ig
.Emit (OpCodes
.Ldfld
, local_info
.FieldBuilder
);
3667 public void Emit (EmitContext ec
, bool leave_copy
)
3671 ec
.ig
.Emit (OpCodes
.Dup
);
3672 if (local_info
.FieldBuilder
!= null){
3673 temp
= new LocalTemporary (ec
, Type
);
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");
3693 ec
.ig
.Emit (OpCodes
.Dup
);
3694 ig
.Emit (OpCodes
.Stloc
, local_info
.LocalBuilder
);
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
);
3705 ig
.Emit (OpCodes
.Dup
);
3706 temp
= new LocalTemporary (ec
, Type
);
3709 ig
.Emit (OpCodes
.Stfld
, local_info
.FieldBuilder
);
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
);
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
);
3740 /// This represents a reference to a parameter in the intermediate
3743 public class ParameterReference
: Expression
, IAssignMethod
, IMemoryLocation
, IVariable
{
3749 public Parameter
.Modifier mod
;
3750 public bool is_ref
, is_out
, prepared
;
3764 LocalTemporary temp
;
3766 public ParameterReference (Parameters pars
, Block block
, int idx
, string name
, Location loc
)
3773 eclass
= ExprClass
.Variable
;
3776 public VariableInfo VariableInfo
{
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
))
3790 Report
.Error (165, loc
,
3791 "Use of unassigned parameter `" + name
+ "'");
3795 public bool IsFieldAssigned (EmitContext ec
, string field_name
, Location loc
)
3797 if (!ec
.DoFlowAnalysis
|| !is_out
|| ec
.CurrentBranching
.IsFieldAssigned (vi
, field_name
))
3800 Report
.Error (170, loc
,
3801 "Use of possibly unassigned field `" + field_name
+ "'");
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
;
3825 vi
= block
.ParameterMap
[idx
];
3827 if (ec
.CurrentAnonymousMethod
!= null){
3829 Report
.Error (1628, Location
,
3830 "Can not reference a ref or out parameter in an anonymous method");
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.
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
)
3861 if (is_out
&& ec
.DoFlowAnalysis
&& !IsAssigned (ec
, loc
))
3864 if (ec
.RemapToProxy
)
3865 return ec
.RemapParameter (idx
);
3870 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
3876 if (ec
.RemapToProxy
)
3877 return ec
.RemapParameterLValue (idx
, right_side
);
3882 static public void EmitLdArg (ILGenerator ig
, int 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;
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
;
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
);
3927 public void Emit (EmitContext ec
, bool leave_copy
)
3929 ILGenerator ig
= ec
.ig
;
3935 EmitLdArg (ig
, arg_idx
);
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
);
3949 ec
.ig
.Emit (OpCodes
.Dup
);
3952 temp
= new LocalTemporary (ec
, type
);
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
);
3965 ILGenerator ig
= ec
.ig
;
3968 prepared
= prepare_for_load
;
3973 if (is_ref
&& !prepared
)
3974 EmitLdArg (ig
, arg_idx
);
3979 ec
.ig
.Emit (OpCodes
.Dup
);
3983 temp
= new LocalTemporary (ec
, type
);
3987 StoreFromPtr (ig
, type
);
3993 ig
.Emit (OpCodes
.Starg_S
, (byte) arg_idx
);
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
);
4013 ec
.ig
.Emit (OpCodes
.Ldarg_S
, (byte) arg_idx
);
4015 ec
.ig
.Emit (OpCodes
.Ldarg
, arg_idx
);
4018 ec
.ig
.Emit (OpCodes
.Ldarga_S
, (byte) arg_idx
);
4020 ec
.ig
.Emit (OpCodes
.Ldarga
, arg_idx
);
4027 /// Used for arguments to New(), Invocation()
4029 public class Argument
{
4030 public enum AType
: byte {
4037 public readonly AType ArgType
;
4038 public Expression Expr
;
4040 public Argument (Expression expr
, AType type
)
4043 this.ArgType
= type
;
4046 public Argument (Expression expr
)
4049 this.ArgType
= AType
.Expression
;
4054 if (ArgType
== AType
.Ref
|| ArgType
== AType
.Out
)
4055 return TypeManager
.GetReferenceType (Expr
.Type
);
4061 public Parameter
.Modifier
GetParameterModifier ()
4065 return Parameter
.Modifier
.OUT
| Parameter
.Modifier
.ISBYREF
;
4068 return Parameter
.Modifier
.REF
| Parameter
.Modifier
.ISBYREF
;
4071 return Parameter
.Modifier
.NONE
;
4075 public static string FullDesc (Argument a
)
4077 if (a
.ArgType
== AType
.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
);
4096 public bool Resolve (EmitContext ec
, Location loc
)
4098 if (ArgType
== AType
.Ref
) {
4099 Expr
= Expr
.Resolve (ec
);
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)");
4109 Report
.Error (192, loc
, "A readonly field cannot be passed ref or out (except in a constructor)");
4113 Expr
= Expr
.ResolveLValue (ec
, Expr
);
4114 } else if (ArgType
== AType
.Out
)
4115 Expr
= Expr
.ResolveLValue (ec
, EmptyExpression
.Null
);
4117 Expr
= Expr
.Resolve (ec
);
4122 if (ArgType
== AType
.Expression
)
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");
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
){
4151 "A property or indexer can not be passed as an out or ref " +
4156 "An lvalue is required as an argument to out or ref");
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
;
4185 pr
.AddressOf (ec
, mode
);
4188 ((IMemoryLocation
)Expr
).AddressOf (ec
, mode
);
4196 /// Invocation of methods or delegates.
4198 public class Invocation
: ExpressionStatement
{
4199 public readonly ArrayList Arguments
;
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
)
4221 Arguments
= arguments
;
4225 public Expression Expr
{
4232 /// Returns the Parameters (a ParameterData interface) for the
4235 public static ParameterData
GetParameterData (MethodBase mb
)
4237 object pd
= method_parameter_cache
[mb
];
4241 return (ParameterData
) pd
;
4244 ip
= TypeManager
.LookupParametersByBuilder (mb
);
4246 method_parameter_cache
[mb
] = ip
;
4248 return (ParameterData
) ip
;
4250 ReflectionParameters rp
= new ReflectionParameters (mb
);
4251 method_parameter_cache
[mb
] = rp
;
4253 return (ParameterData
) rp
;
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
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");
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
)
4297 if (!q
.IsValueType
&& p
== TypeManager
.object_type
)
4301 if (argument_type
== p
)
4304 if (argument_type
== 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
)
4316 if (q_to_p
&& !p_to_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
)
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
)
4328 if (p
== TypeManager
.short_type
)
4329 if (q
== TypeManager
.ushort_type
|| q
== TypeManager
.uint32_type
||
4330 q
== TypeManager
.uint64_type
)
4332 if (q
== TypeManager
.short_type
)
4333 if (p
== TypeManager
.ushort_type
|| p
== TypeManager
.uint32_type
||
4334 p
== TypeManager
.uint64_type
)
4337 if (p
== TypeManager
.int32_type
)
4338 if (q
== TypeManager
.uint32_type
|| q
== TypeManager
.uint64_type
)
4340 if (q
== TypeManager
.int32_type
)
4341 if (p
== TypeManager
.uint32_type
|| p
== TypeManager
.uint64_type
)
4344 if (p
== TypeManager
.int64_type
)
4345 if (q
== TypeManager
.uint64_type
)
4347 if (q
== TypeManager
.int64_type
)
4348 if (p
== TypeManager
.uint64_type
)
4355 /// Determines "Better function" between candidate
4356 /// and the current best match
4359 /// Returns an integer indicating :
4360 /// false if candidate ain't better
4361 /// true if candidate is better than the current best match
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
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
)
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
)
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'.
4423 // for at least one argument, the conversion to 'ct' should be better than
4424 // the conversion to 'bt'.
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
)
4439 return better_at_least_one
;
4442 public static string FullMethodDesc (MethodBase mb
)
4444 string ret_type
= "";
4449 if (mb
is MethodInfo
)
4450 ret_type
= TypeManager
.CSharpName (((MethodInfo
) mb
).ReturnType
);
4452 StringBuilder sb
= new StringBuilder (ret_type
);
4454 sb
.Append (mb
.ReflectedType
.ToString ());
4456 sb
.Append (mb
.Name
);
4458 ParameterData pd
= GetParameterData (mb
);
4460 int count
= pd
.Count
;
4463 for (int i
= count
; i
> 0; ) {
4466 sb
.Append (pd
.ParameterDesc (count
- i
- 1));
4472 return sb
.ToString ();
4475 public static MethodGroupExpr
MakeUnionSet (Expression mg1
, Expression mg2
, Location loc
)
4477 MemberInfo
[] miset
;
4478 MethodGroupExpr union
;
4483 return (MethodGroupExpr
) mg2
;
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
))
4505 miset
= new MemberInfo
[length1
+ length2
- common
.Count
];
4506 left_set
.Methods
.CopyTo (miset
, 0);
4510 foreach (MethodBase r
in right_set
.Methods
) {
4511 if (!common
.Contains (r
))
4515 union
= new MethodGroupExpr (miset
, loc
);
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
);
4541 /// Determines if the candidate method, if a params method, is applicable
4542 /// in its expanded form to the given set of arguments
4544 static bool IsParamsMethodApplicable (EmitContext ec
, ArrayList arguments
,
4545 int arg_count
, MethodBase candidate
,
4548 ParameterData pd
= GetParameterData (candidate
);
4550 int pd_count
= pd
.Count
;
4554 int count
= pd_count
- 1;
4556 if (pd
.ParameterModifier (count
) != Parameter
.Modifier
.ARGLIST
)
4558 if (pd_count
!= arg_count
)
4561 if (pd
.ParameterModifier (count
) != Parameter
.Modifier
.PARAMS
)
4565 if (count
> arg_count
)
4568 if (pd_count
== 1 && arg_count
== 0)
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
,
4590 pd
.ParameterType (i
)))
4593 if ((a_mod
& Parameter
.Modifier
.ISBYREF
) != 0) {
4594 Type pt
= pd
.ParameterType (i
);
4597 pt
= TypeManager
.GetReferenceType (pt
);
4608 Argument a
= (Argument
) arguments
[count
];
4609 if (!(a
.Expr
is Arglist
))
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
))
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
);
4635 /// Determines if the candidate method is applicable (section 14.4.2.1)
4636 /// to the given set of arguments
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
)
4646 for (int i
= arg_count
; i
> 0; ) {
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
,
4662 pd
.ParameterType (i
)))
4666 if ((a_mod
& Parameter
.Modifier
.ISBYREF
) != 0) {
4667 Type pt
= pd
.ParameterType (i
);
4670 pt
= TypeManager
.GetReferenceType (pt
);
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
));
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.
4705 public static MethodBase
OverloadResolve (EmitContext ec
, MethodGroupExpr me
,
4706 ArrayList Arguments
, bool may_fail
,
4709 MethodBase method
= null;
4710 bool method_params
= false;
4711 Type applicable_type
= null;
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
);
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
))
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;
4771 candidates
.Add (methods
[i
]);
4773 if (applicable_type
== null)
4774 applicable_type
= decl_type
;
4775 else if (applicable_type
!= decl_type
) {
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
)
4796 VerifyArgumentsCompat (ec
, Arguments
, arg_count
,
4797 c
, false, null, may_fail
, loc
);
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
);
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
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
];
4844 if (IsAncestralType (decl_type
, applicable_type
))
4847 if (next_applicable_type
!= null &&
4848 IsAncestralType (decl_type
, next_applicable_type
))
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
;
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
)) {
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
)
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
,
4898 Report
.SymbolRelatedToPreviousError (candidate
);
4904 Report
.SymbolRelatedToPreviousError (method
);
4905 Report
.Error (121, loc
, "Ambiguous call when selecting function due to implicit casts");
4911 // And now check if the arguments are all
4912 // compatible, perform conversions if
4913 // necessary etc. and return if everything is
4916 if (!VerifyArgumentsCompat (ec
, Arguments
, arg_count
, method
,
4917 method_params
, null, may_fail
, loc
))
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");
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
,
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 ()) {
4971 Error_InvalidArguments (
4972 loc
, j
, method
, delegate_type
,
4973 Argument
.FullDesc (a
), pd
.ParameterDesc (j
));
4977 if (chose_params_expanded
)
4978 parameter_type
= TypeManager
.GetElementType (parameter_type
);
4979 } else if (pm
== Parameter
.Modifier
.ARGLIST
){
4985 if (pd
.ParameterModifier (j
) != a
.GetParameterModifier ()){
4987 Error_InvalidArguments (
4988 loc
, j
, method
, delegate_type
,
4989 Argument
.FullDesc (a
), pd
.ParameterDesc (j
));
4997 if (!a
.Type
.Equals (parameter_type
)){
5000 conv
= Convert
.ImplicitConversion (ec
, a_expr
, parameter_type
, loc
);
5004 Error_InvalidArguments (
5005 loc
, j
, method
, delegate_type
,
5006 Argument
.FullDesc (a
), pd
.ParameterDesc (j
));
5011 // Update the argument with the implicit conversion
5017 if (parameter_type
.IsPointer
){
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
) {
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
) + "'");
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
);
5058 if (!(expr
is MethodGroupExpr
)) {
5059 Type expr_type
= expr
.Type
;
5061 if (expr_type
!= null){
5062 bool IsDelegate
= TypeManager
.IsDelegateType (expr_type
);
5064 return (new DelegateInvocation (
5065 this.expr
, Arguments
, loc
)).Resolve (ec
);
5069 if (!(expr
is MethodGroupExpr
)){
5070 expr
.Error_UnexpectedKind (ResolveFlags
.MethodGroup
, loc
);
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
))
5084 MethodGroupExpr mg
= (MethodGroupExpr
) expr
;
5085 method
= OverloadResolve (ec
, mg
, Arguments
, false, loc
);
5090 MethodInfo mi
= method
as MethodInfo
;
5092 type
= TypeManager
.TypeToCoreType (mi
.ReturnType
);
5093 if (!mi
.IsStatic
&& !mg
.IsExplicitImpl
&& (mg
.InstanceExpression
== null)) {
5094 SimpleName
.Error_ObjectRefRequired (ec
, loc
, mi
.Name
);
5098 Expression iexpr
= mg
.InstanceExpression
;
5099 if (mi
.IsStatic
&& (iexpr
!= null) && !(iexpr
is This
)) {
5100 if (mg
.IdenticalTypeName
)
5101 mg
.InstanceExpression
= null;
5103 MemberAccess
.error176 (loc
, mi
.Name
);
5109 if (type
.IsPointer
){
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
));
5125 if (method
.Name
== "Finalize" && Arguments
== null) {
5127 Report
.Error (250, loc
, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5129 Report
.Error (245, loc
, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
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");
5140 eclass
= ExprClass
.Value
;
5145 // Emits the list of arguments as an array
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
);
5165 OpCode op
= ArrayAccess
.GetStoreOpcode (t
, out is_stobj
);
5167 ig
.Emit (OpCodes
.Ldelema
, t
);
5172 ig
.Emit (OpCodes
.Stobj
, t
);
5179 /// Emits a list of resolved Arguments that are in the arguments
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)
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.
5192 public static void EmitArguments (EmitContext ec
, MethodBase mb
, ArrayList arguments
, bool dup_args
, LocalTemporary this_arg
)
5196 pd
= GetParameterData (mb
);
5200 LocalTemporary
[] temps
= null;
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)));
5220 int top
= arguments
.Count
;
5222 for (int i
= 0; i
< top
; i
++){
5223 Argument a
= (Argument
) arguments
[i
];
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
)
5234 EmitParams (ec
, i
, arguments
);
5241 ec
.ig
.Emit (OpCodes
.Dup
);
5242 (temps
[i
] = new LocalTemporary (ec
, a
.Type
)).Store (ec
);
5247 if (this_arg
!= null)
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
;
5278 /// This checks the ConditionalAttribute on the method
5280 static bool IsMethodExcluded (MethodBase method
, EmitContext ec
)
5282 if (method
.IsConstructor
)
5285 IMethodData md
= TypeManager
.GetMethod (method
);
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
)
5294 return AttributeTester
.IsConditionalMethodExcluded (method
);
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.
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
);
5362 AttributeTester
.Report_ObsoleteMessage (oa
, TypeManager
.CSharpSignature (method
), loc
);
5365 oa
= AttributeTester
.GetObsoleteAttribute (method
.DeclaringType
);
5367 AttributeTester
.Report_ObsoleteMessage (oa
, method
.DeclaringType
.FullName
, loc
);
5371 if (IsMethodExcluded (method
, ec
))
5375 this_call
= instance_expr
== null;
5376 if (decl_type
.IsValueType
|| (!this_call
&& instance_expr
.Type
.IsValueType
))
5380 // If this is ourselves, push "this"
5385 ig
.Emit (OpCodes
.Ldarg_0
);
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
5402 // If not we have to use some temporary storage for
5404 if (instance_expr
is IMemoryLocation
) {
5405 ((IMemoryLocation
)instance_expr
).
5406 AddressOf (ec
, AddressOp
.LoadStore
);
5408 LocalTemporary temp
= new LocalTemporary (ec
, instance_expr
.Type
);
5409 instance_expr
.Emit (ec
);
5411 temp
.AddressOf (ec
, AddressOp
.Load
);
5414 // avoid the overhead of doing this all the time.
5416 t
= TypeManager
.GetReferenceType (instance_expr
.Type
);
5418 instance_expr
.Emit (ec
);
5419 ig
.Emit (OpCodes
.Box
, instance_expr
.Type
);
5420 t
= TypeManager
.object_type
;
5423 instance_expr
.Emit (ec
);
5424 t
= instance_expr
.Type
;
5429 this_arg
= new LocalTemporary (ec
, t
);
5430 ig
.Emit (OpCodes
.Dup
);
5431 this_arg
.Store (ec
);
5437 EmitArguments (ec
, method
, Arguments
, dup_args
, this_arg
);
5440 if (is_static
|| struct_call
|| is_base
|| (this_call
&& !method
.IsVirtual
))
5441 call_op
= OpCodes
.Call
;
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
);
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
);
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
)
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
5488 Expression argument
;
5490 public InvocationOrCast (Expression expr
, Expression argument
, Location loc
)
5493 this.argument
= argument
;
5497 public override Expression
DoResolve (EmitContext ec
)
5500 // First try to resolve it as a cast.
5502 TypeExpr te
= expr
.ResolveAsTypeTerminal (ec
, true);
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
);
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");
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
);
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);
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
)) {
5566 // It's a delegate invocation.
5568 if (!TypeManager
.IsDelegateType (expr
.Type
)) {
5569 Error (149, "Method name expected");
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
)
5602 /// Implements the new expression
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
;
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
);
5642 // This function is used to disable the following code sequence for
5643 // value type initialization:
5645 // AddressOf (temporary)
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)
5679 if (RequestedType
is NewDelegate
)
5680 return RequestedType
;
5684 TypeExpr texpr
= RequestedType
.ResolveAsTypeTerminal (ec
, false);
5688 type
= texpr
.ResolveType (ec
);
5690 CheckObsoleteAttribute (type
);
5692 bool IsDelegate
= TypeManager
.IsDelegateType (type
);
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
));
5707 if (type
.IsInterface
|| type
.IsAbstract
){
5708 Error (144, "It is not possible to create instances of interfaces or abstract classes");
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)
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
);
5731 if (! (ml
is MethodGroupExpr
)){
5733 ml
.Error_UnexpectedKind ("method group", loc
);
5739 if (Arguments
!= null){
5740 foreach (Argument a
in Arguments
){
5741 if (!a
.Resolve (ec
, loc
))
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
)));
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
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
;
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
);
5806 Invocation
.EmitArguments (ec
, method
, Arguments
, false, null);
5810 ig
.Emit (OpCodes
.Initobj
, type
);
5812 ig
.Emit (OpCodes
.Call
, (ConstructorInfo
) method
);
5813 if (need_value_on_stack
){
5814 value_target
.Emit (ec
);
5819 ig
.Emit (OpCodes
.Newobj
, (ConstructorInfo
) method
);
5824 public override void Emit (EmitContext ec
)
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
5841 // foreach (int j in new StructType ())
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
);
5853 Invocation
.EmitArguments (ec
, method
, Arguments
, false, null);
5856 ec
.ig
.Emit (OpCodes
.Initobj
, type
);
5858 ec
.ig
.Emit (OpCodes
.Call
, (ConstructorInfo
) method
);
5860 ((IMemoryLocation
) value_target
).AddressOf (ec
, Mode
);
5865 /// 14.5.10.2: Represents an array creation expression.
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.
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;
5898 ArrayList array_data
;
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
;
5917 arguments
= new ArrayList ();
5919 foreach (Expression e
in exprs
) {
5920 arguments
.Add (new Argument (e
, Argument
.AType
.Expression
));
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
;
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
);
5945 for (int i
= 1; i
< idx_count
; i
++)
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
))
5966 if (!(a
.Expr
is Constant
)) {
5967 Error (150, "A constant value is expected");
5971 int value = (int) ((Constant
) a
.Expr
).GetValue ();
5973 if (value != probe
.Count
) {
5974 Error_IncorrectArrayInitializer ();
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 ();
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");
5998 bool ret
= CheckIndices (ec
, (ArrayList
) o
, idx
+ 1, specified_dims
);
6002 if (child_bounds
!= -1){
6003 Error_IncorrectArrayInitializer ();
6007 Expression tmp
= (Expression
) o
;
6008 tmp
= tmp
.Resolve (ec
);
6012 // Console.WriteLine ("I got: " + tmp);
6013 // Handle initialization from vars, fields etc.
6015 Expression conv
= Convert
.ImplicitConversionRequired (
6016 ec
, tmp
, underlying_type
, loc
);
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
++;
6032 array_data
.Add (conv
);
6039 public void UpdateIndices (EmitContext ec
)
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];
6052 Expression e
= new IntConstant (probe
.Count
);
6053 arguments
.Add (new Argument (e
, Argument
.AType
.Expression
));
6055 bounds
[i
++] = probe
.Count
;
6062 public bool ValidateInitializers (EmitContext ec
, Type array_type
)
6064 if (initializers
== null) {
6065 if (expect_initializers
)
6071 if (underlying_type
== null)
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 ();
6083 if (arguments
!= null) {
6084 ret
= CheckIndices (ec
, initializers
, 0, true);
6087 arguments
= new ArrayList ();
6089 ret
= CheckIndices (ec
, initializers
, 0, false);
6096 if (arguments
.Count
!= dimensions
) {
6097 Error_IncorrectArrayInitializer ();
6106 // Converts `source' to an int, uint, long or ulong.
6108 Expression
ExpressionToArrayArgument (EmitContext ec
, Expression source
)
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
);
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
);
6140 if (target
is LongConstant
){
6141 if (((LongConstant
) target
).Value
< 0){
6142 Expression
.Error_NegativeArrayIndex (loc
);
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 ("]");
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)
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.");
6185 underlying_type
= TypeManager
.GetElementType (type
);
6186 dimensions
= type
.GetArrayRank ();
6191 public override Expression
DoResolve (EmitContext ec
)
6195 if (!LookupType (ec
))
6199 // First step is to validate the initializers and fill
6200 // in any missing bits
6202 if (!ValidateInitializers (ec
, type
))
6205 if (arguments
== null)
6208 arg_count
= arguments
.Count
;
6209 foreach (Argument a
in arguments
){
6210 if (!a
.Resolve (ec
, loc
))
6213 Expression real_arg
= ExpressionToArrayArgument (ec
, a
.Expr
, loc
);
6214 if (real_arg
== null)
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
));
6228 if (arg_count
== 1) {
6229 is_one_dimensional
= true;
6230 eclass
= ExprClass
.Value
;
6234 is_builtin_type
= TypeManager
.IsBuiltinType (type
);
6236 if (is_builtin_type
) {
6239 ml
= MemberLookup (ec
, type
, ".ctor", MemberTypes
.Constructor
,
6240 AllBindingFlags
, loc
);
6242 if (!(ml
is MethodGroupExpr
)) {
6243 ml
.Error_UnexpectedKind ("method group", loc
);
6248 Error (-6, "New invocation: Can not find a constructor for " +
6249 "this argument list");
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");
6262 eclass
= ExprClass
.Value
;
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;
6276 arg_types
= new Type
[args
.Count
];
6278 args
.CopyTo (arg_types
, 0);
6280 new_method
= mb
.GetArrayMethod (type
, ".ctor", CallingConventions
.HasThis
, null,
6283 if (new_method
== null) {
6284 Error (-6, "New invocation: Can not find a constructor for " +
6285 "this argument list");
6289 eclass
= ExprClass
.Value
;
6294 public static byte [] MakeByteBlob (ArrayList array_data
, Type underlying_type
, Location loc
)
6299 int count
= array_data
.Count
;
6301 if (underlying_type
.IsEnum
)
6302 underlying_type
= TypeManager
.EnumToUnderlying (underlying_type
);
6304 factor
= GetTypeSize (underlying_type
);
6306 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type
);
6308 data
= new byte [(count
* factor
+ 4) & ~
3];
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 ();
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);
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);
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
)){
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
);
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);
6430 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type
);
6439 // Emits the initializers for the array
6441 void EmitStaticInitializers (EmitContext ec
)
6444 // First, the static data
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;
6476 ModuleBuilder mb
= null;
6477 mb
= CodeGen
.Module
.Builder
;
6478 args
= new Type
[dims
+ 1];
6481 for (j
= 0; j
< dims
; j
++)
6482 args
[j
] = TypeManager
.int32_type
;
6484 args
[j
] = array_element_type
;
6486 set = mb
.GetArrayMethod (
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
];
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.
6522 etype
.IsSubclassOf (TypeManager
.value_type
) &&
6523 (!TypeManager
.IsBuiltinOrEnum (etype
) ||
6524 etype
== TypeManager
.decimal_type
)) {
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
);
6542 OpCode op
= ArrayAccess
.GetStoreOpcode (etype
, out is_stobj
);
6544 ig
.Emit (OpCodes
.Stobj
, etype
);
6548 ig
.Emit (OpCodes
.Call
, set);
6556 for (int j
= dims
- 1; j
>= 0; j
--){
6558 if (current_pos
[j
] < (int) bounds
[j
])
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
;
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
);
6588 if (is_builtin_type
)
6589 ig
.Emit (OpCodes
.Newobj
, (ConstructorInfo
) new_method
);
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
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");
6618 if (array_data
== null){
6619 Report
.Error (-212, Location
, "array should be initialized when passing it to an attribute");
6623 object [] ret
= new object [array_data
.Count
];
6625 foreach (Expression e
in array_data
){
6628 if (e
is NullLiteral
)
6631 if (!Attribute
.GetAttributeArgumentExpression (e
, Location
, array_element_type
, out v
))
6641 /// Represents the `this' construct
6643 public class This
: Expression
, IAssignMethod
, IMemoryLocation
, IVariable
{
6646 VariableInfo variable_info
;
6648 public This (Block block
, Location loc
)
6654 public This (Location 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))
6668 return variable_info
.LocalInfo
.IsFixed
;
6671 public bool ResolveBase (EmitContext ec
)
6673 eclass
= ExprClass
.Variable
;
6674 type
= ec
.ContainerType
;
6677 Error (26, "Keyword this not valid in static code");
6681 if ((block
!= null) && (block
.ThisVariable
!= null))
6682 variable_info
= block
.ThisVariable
.VariableInfo
;
6687 public override Expression
DoResolve (EmitContext ec
)
6689 if (!ResolveBase (ec
))
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
);
6699 if (ec
.IsFieldInitializer
) {
6700 Error (27, "Keyword `this' can't be used outside a constructor, " +
6701 "a method or a property.");
6708 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
6710 if (!ResolveBase (ec
))
6713 if (variable_info
!= null)
6714 variable_info
.SetAssigned (ec
);
6716 if (ec
.TypeContainer
is Class
){
6717 Error (1604, "Cannot assign to `this'");
6724 public void Emit (EmitContext ec
, bool 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
){
6739 ec
.ig
.Emit (OpCodes
.Dup
);
6740 ig
.Emit (OpCodes
.Stobj
, type
);
6742 throw new Exception ("how did you get here");
6746 public override void Emit (EmitContext ec
)
6748 ILGenerator ig
= ec
.ig
;
6751 if (ec
.TypeContainer
is Struct
)
6752 ig
.Emit (OpCodes
.Ldobj
, type
);
6755 public void AddressOf (EmitContext ec
, AddressOp mode
)
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
6766 // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6771 /// Represents the `__arglist' construct
6773 public class ArglistAccess
: Expression
6775 public ArglistAccess (Location loc
)
6780 public bool ResolveBase (EmitContext ec
)
6782 eclass
= ExprClass
.Variable
;
6783 type
= TypeManager
.runtime_argument_handle_type
;
6787 public override Expression
DoResolve (EmitContext ec
)
6789 if (!ResolveBase (ec
))
6792 if (ec
.IsFieldInitializer
|| !ec
.CurrentBlock
.HasVarargs
) {
6793 Error (190, "The __arglist construct is valid only within " +
6794 "a variable argument method.");
6801 public override void Emit (EmitContext ec
)
6803 ec
.ig
.Emit (OpCodes
.Arglist
);
6808 /// Represents the `__arglist (....)' construct
6810 public class Arglist
: Expression
6812 public readonly Argument
[] Arguments
;
6814 public Arglist (Argument
[] args
, Location l
)
6820 public Type
[] ArgumentTypes
{
6822 Type
[] retval
= new Type
[Arguments
.Length
];
6823 for (int i
= 0; i
< Arguments
.Length
; i
++)
6824 retval
[i
] = Arguments
[i
].Type
;
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
))
6842 public override void Emit (EmitContext ec
)
6844 foreach (Argument arg
in Arguments
)
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
;
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
);
6873 /// Implements the typeof operator
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
;
6885 public override Expression
DoResolve (EmitContext ec
)
6887 TypeExpr texpr
= QueriedType
.ResolveAsTypeTerminal (ec
, false);
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");
6899 if (typearg
.IsPointer
&& !ec
.InUnsafe
){
6903 CheckObsoleteAttribute (typearg
);
6905 type
= TypeManager
.type_type
;
6906 eclass
= ExprClass
.Type
;
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; }
6922 /// Implements the `typeof (void)' operator
6924 public class TypeOfVoid
: TypeOf
{
6925 public TypeOfVoid (Location l
) : base (null, l
)
6930 public override Expression
DoResolve (EmitContext ec
)
6932 type
= TypeManager
.type_type
;
6933 typearg
= TypeManager
.void_type
;
6934 eclass
= ExprClass
.Type
;
6940 /// Implements the sizeof expression
6942 public class SizeOf
: Expression
{
6943 public Expression QueriedType
;
6946 public SizeOf (Expression queried_type
, Location l
)
6948 this.QueriedType
= queried_type
;
6952 public override Expression
DoResolve (EmitContext ec
)
6956 233, loc
, "Sizeof may only be used in an unsafe context " +
6957 "(consider using System.Runtime.InteropServices.Marshal.SizeOf");
6961 TypeExpr texpr
= QueriedType
.ResolveAsTypeTerminal (ec
, false);
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
) + ")");
6974 type
= TypeManager
.int32_type
;
6975 eclass
= ExprClass
.Value
;
6979 public override void Emit (EmitContext ec
)
6981 int size
= GetTypeSize (type_queried
);
6984 ec
.ig
.Emit (OpCodes
.Sizeof
, type_queried
);
6986 IntConstant
.EmitInt (ec
.ig
, size
);
6991 /// Implements the member access expression
6993 public class MemberAccess
: Expression
{
6994 public readonly string Identifier
;
6997 public MemberAccess (Expression expr
, string id
, Location l
)
7004 public Expression 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
)
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.
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
);
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
);
7057 if (!c
.LookupConstantValue (out o
))
7060 object real_value
= ((Constant
) c
.Expr
).GetValue ();
7062 return Constantify (real_value
, fi
.FieldType
);
7067 Type t
= fi
.FieldType
;
7071 if (fi
is FieldBuilder
)
7072 o
= TypeManager
.GetValue ((FieldBuilder
) fi
);
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
);
7083 Expression enum_member
= MemberLookup (
7084 ec
, decl_type
, "value__", MemberTypes
.Field
,
7085 AllBindingFlags
, loc
);
7087 Enum en
= TypeManager
.LookupEnum (decl_type
);
7091 c
= Constantify (o
, en
.UnderlyingType
);
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
);
7108 if (fi
.FieldType
.IsPointer
&& !ec
.InUnsafe
){
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
7122 if (ee
.EventInfo
.DeclaringType
== ec
.ContainerType
||
7123 TypeManager
.IsNestedChildOf(ec
.ContainerType
, ee
.EventInfo
.DeclaringType
)) {
7124 MemberInfo mi
= GetFieldFromEvent (ee
);
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
;
7136 Expression ml
= ExprClassFromMemberInfo (ec
, mi
, loc
);
7139 Report
.Error (-200, loc
, "Internal error!!");
7143 if (!left_is_explicit
)
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
;
7157 if ((mg
!= null) && left_is_explicit
&& left
.Type
.IsInterface
)
7158 mg
.IsExplicitImpl
= left_is_explicit
;
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
);
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
);
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
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
);
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);
7216 public Expression
DoResolve (EmitContext ec
, Expression right_side
, ResolveFlags flags
)
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
);
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
);
7257 if (expr_type
== TypeManager
.enum_type
|| expr_type
.IsSubclassOf (TypeManager
.enum_type
)){
7258 Enum en
= TypeManager
.LookupEnum (expr_type
);
7261 object value = en
.LookupEnumValue (ec
, Identifier
, loc
);
7264 MemberCore mc
= en
.GetDefinition (Identifier
);
7265 ObsoleteAttribute oa
= mc
.GetObsoleteAttribute (en
);
7267 AttributeTester
.Report_ObsoleteMessage (oa
, mc
.GetSignatureForError (), Location
);
7269 oa
= en
.GetObsoleteAttribute (en
);
7271 AttributeTester
.Report_ObsoleteMessage (oa
, en
.GetSignatureForError (), Location
);
7274 Constant c
= Constantify (value, en
.UnderlyingType
);
7275 return new EnumConstant (c
, expr_type
);
7278 CheckObsoleteAttribute (expr_type
);
7280 FieldInfo fi
= expr_type
.GetField (Identifier
);
7282 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (fi
);
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
) + ")");
7296 Expression member_lookup
;
7297 member_lookup
= MemberLookupFinal (ec
, expr_type
, expr_type
, Identifier
, loc
);
7298 if (member_lookup
== 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");
7308 return member_lookup
;
7311 member_lookup
= ResolveMemberAccess (ec
, member_lookup
, expr
, loc
, original
);
7312 if (member_lookup
== null)
7315 // The following DoResolve/DoResolveLValue will do the definite assignment
7318 if (right_side
!= null)
7319 member_lookup
= member_lookup
.DoResolveLValue (ec
, right_side
);
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) {
7344 fname
= String
.Concat (full_expr
.Identifier
, ".", fname
);
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)
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
) + ")");
7379 Expression member_lookup
;
7380 member_lookup
= MemberLookupFinal (ec
, expr_type
, expr_type
, Identifier
, loc
);
7381 if (member_lookup
== null)
7384 if (member_lookup
is TypeExpr
){
7385 member_lookup
.Resolve (ec
, ResolveFlags
.Type
);
7386 return member_lookup
;
7392 public override void Emit (EmitContext ec
)
7394 throw new Exception ("Should not happen");
7397 public override string ToString ()
7399 return expr
+ "." + Identifier
;
7404 /// Implements checked expressions
7406 public class CheckedExpr
: Expression
{
7408 public Expression Expr
;
7410 public CheckedExpr (Expression e
, Location 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
;
7430 if (Expr
is Constant
)
7433 eclass
= Expr
.eclass
;
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;
7446 ec
.CheckState
= last_check
;
7447 ec
.ConstantCheckState
= last_const_check
;
7453 /// Implements the unchecked expression
7455 public class UnCheckedExpr
: Expression
{
7457 public Expression Expr
;
7459 public UnCheckedExpr (Expression e
, Location 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
;
7479 if (Expr
is Constant
)
7482 eclass
= Expr
.eclass
;
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;
7495 ec
.CheckState
= last_check
;
7496 ec
.ConstantCheckState
= last_const_check
;
7502 /// An Element Access expression.
7504 /// During semantic analysis these are transformed into
7505 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7507 public class ElementAccess
: Expression
{
7508 public ArrayList Arguments
;
7509 public Expression Expr
;
7511 public ElementAccess (Expression e
, ArrayList e_list
, Location l
)
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
);
7533 if (Arguments
== null)
7536 foreach (Argument a
in Arguments
){
7537 if (!a
.Resolve (ec
, loc
))
7544 Expression
MakePointerAccess (EmitContext ec
)
7548 if (t
== TypeManager
.void_ptr_type
){
7549 Error (242, "The array index operation is not valid for void pointers");
7552 if (Arguments
.Count
!= 1){
7553 Error (196, "A pointer must be indexed by a single value");
7558 p
= new PointerArithmetic (true, Expr
, ((Argument
)Arguments
[0]).Expr
, t
, loc
).Resolve (ec
);
7561 return new Indirection (p
, loc
).Resolve (ec
);
7564 public override Expression
DoResolve (EmitContext ec
)
7566 if (!CommonResolve (ec
))
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.
7577 if (t
== TypeManager
.array_type
){
7578 Report
.Error (21, loc
, "Cannot use indexer on System.Array");
7583 return (new ArrayAccess (this, loc
)).Resolve (ec
);
7584 else if (t
.IsPointer
)
7585 return MakePointerAccess (ec
);
7587 return (new IndexerAccess (this, loc
)).Resolve (ec
);
7590 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
7592 if (!CommonResolve (ec
))
7597 return (new ArrayAccess (this, loc
)).ResolveLValue (ec
, right_side
);
7598 else if (t
.IsPointer
)
7599 return MakePointerAccess (ec
);
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");
7611 /// Implements array access
7613 public class ArrayAccess
: Expression
, IAssignMethod
, IMemoryLocation
{
7615 // Points to our "data" repository
7619 LocalTemporary temp
;
7622 public ArrayAccess (ElementAccess ea_data
, Location l
)
7625 eclass
= ExprClass
.Variable
;
7629 public override Expression
DoResolve (EmitContext ec
)
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");
7642 Type t
= ea
.Expr
.Type
;
7643 if (t
.GetArrayRank () != ea
.Arguments
.Count
){
7645 "Incorrect number of indexes for array " +
7646 " expected: " + t
.GetArrayRank () + " got: " +
7647 ea
.Arguments
.Count
);
7651 type
= TypeManager
.GetElementType (t
);
7652 if (type
.IsPointer
&& !ec
.InUnsafe
){
7653 UnsafeError (ea
.Location
);
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)");
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
);
7682 eclass
= ExprClass
.Variable
;
7688 /// Emits the right opcode to load an object of Type `t'
7689 /// from an array of T
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
);
7721 ig
.Emit (OpCodes
.Ldelem_Ref
);
7725 /// Returns the right opcode to store an object of Type `t'
7726 /// from an array of T.
7728 static public OpCode
GetStoreOpcode (Type t
, out bool is_stobj
)
7730 //Console.WriteLine (new System.Diagnostics.StackTrace ());
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
) {
7751 return OpCodes
.Stobj
;
7752 } else if (t
.IsValueType
) {
7754 return OpCodes
.Stobj
;
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
];
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
,
7780 MethodInfo
FetchAddressMethod ()
7782 ModuleBuilder mb
= CodeGen
.Module
.Builder
;
7783 int arg_count
= ea
.Arguments
.Count
;
7784 Type
[] args
= new Type
[arg_count
];
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
,
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
;
7816 foreach (Argument a
in ea
.Arguments
){
7817 Type argtype
= a
.Expr
.Type
;
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
;
7834 LoadArrayAndArguments (ec
);
7837 EmitLoadOpcode (ig
, type
);
7841 method
= FetchGetMethod ();
7842 ig
.Emit (OpCodes
.Call
, method
);
7845 LoadFromPtr (ec
.ig
, this.type
);
7848 ec
.ig
.Emit (OpCodes
.Dup
);
7849 temp
= new LocalTemporary (ec
, this.type
);
7854 public override void Emit (EmitContext ec
)
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
);
7871 ec
.ig
.Emit (OpCodes
.Dup
);
7872 temp
= new LocalTemporary (ec
, this.type
);
7875 StoreFromPtr (ec
.ig
, t
);
7883 LoadArrayAndArguments (ec
);
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
7894 ig
.Emit (OpCodes
.Ldelema
, t
);
7898 ec
.ig
.Emit (OpCodes
.Dup
);
7899 temp
= new LocalTemporary (ec
, this.type
);
7904 ig
.Emit (OpCodes
.Stobj
, t
);
7908 ModuleBuilder mb
= CodeGen
.Module
.Builder
;
7909 int arg_count
= ea
.Arguments
.Count
;
7910 Type
[] args
= new Type
[arg_count
+ 1];
7915 ec
.ig
.Emit (OpCodes
.Dup
);
7916 temp
= new LocalTemporary (ec
, this.type
);
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);
7940 public void AddressOf (EmitContext ec
, AddressOp mode
)
7942 int rank
= ea
.Expr
.Type
.GetArrayRank ();
7943 ILGenerator ig
= ec
.ig
;
7945 LoadArrayAndArguments (ec
);
7948 ig
.Emit (OpCodes
.Ldelema
, type
);
7950 MethodInfo address
= FetchAddressMethod ();
7951 ig
.Emit (OpCodes
.Call
, address
);
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)
7975 map
= new Hashtable ();
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)
8009 static public Indexers
GetIndexersForType (Type caller_type
, Type lookup_type
, Location loc
)
8011 Indexers ix
= (Indexers
) map
[lookup_type
];
8016 Type copy
= lookup_type
;
8017 while (copy
!= TypeManager
.object_type
&& copy
!= null){
8018 MemberInfo
[] mi
= GetIndexersForTypeOrInterface (caller_type
, copy
);
8022 ix
= new Indexers ();
8027 copy
= copy
.BaseType
;
8030 if (!lookup_type
.IsInterface
)
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
);
8040 ix
= new Indexers ();
8052 /// Expressions that represent an indexer call.
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
,
8076 this.instance_expr
= instance_expr
;
8077 this.is_base_indexer
= is_base_indexer
;
8078 this.eclass
= ExprClass
.Value
;
8082 protected virtual bool CommonResolve (EmitContext ec
)
8084 indexer_type
= instance_expr
.Type
;
8085 current_type
= ec
.ContainerType
;
8090 public override Expression
DoResolve (EmitContext ec
)
8092 ArrayList AllGetters
= new ArrayList();
8093 if (!CommonResolve (ec
))
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
;
8106 ilist
= Indexers
.GetIndexersForType (current_type
, lookup_type
, loc
);
8107 if (ilist
!= null) {
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
);
8125 Report
.Error (21, loc
,
8126 "Type `" + TypeManager
.CSharpName (indexer_type
) +
8127 "' does not have any indexers defined");
8131 if (!found_any_getters
) {
8132 Error (154, "indexer can not be used in this context, because " +
8133 "it lacks a `get' accessor");
8138 Error (1501, "No Overload for method `this' takes `" +
8139 arguments
.Count
+ "' arguments");
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));
8151 type
= get.ReturnType
;
8152 if (type
.IsPointer
&& !ec
.InUnsafe
){
8157 eclass
= ExprClass
.IndexerAccess
;
8161 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
8163 ArrayList AllSetters
= new ArrayList();
8164 if (!CommonResolve (ec
))
8167 bool found_any
= false, found_any_setters
= false;
8169 Indexers ilist
= Indexers
.GetIndexersForType (current_type
, indexer_type
, loc
);
8170 if (ilist
!= null) {
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
);
8189 Report
.Error (21, loc
,
8190 "Type `" + TypeManager
.CSharpName (indexer_type
) +
8191 "' does not have any indexers defined");
8195 if (!found_any_setters
) {
8196 Error (154, "indexer can not be used in this context, because " +
8197 "it lacks a `set' accessor");
8202 Error (1501, "No Overload for method `this' takes `" +
8203 arguments
.Count
+ "' arguments");
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));
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){
8226 eclass
= ExprClass
.IndexerAccess
;
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);
8237 ec
.ig
.Emit (OpCodes
.Dup
);
8238 temp
= new LocalTemporary (ec
, Type
);
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];
8256 ec
.ig
.Emit (OpCodes
.Dup
);
8257 temp
= new LocalTemporary (ec
, Type
);
8260 } else if (leave_copy
) {
8261 temp
= new LocalTemporary (ec
, Type
);
8267 Invocation
.EmitCall (ec
, is_base_indexer
, false, instance_expr
, set, set_arguments
, loc
, false, prepared
);
8274 public override void Emit (EmitContext ec
)
8281 /// The base operator for method names
8283 public class BaseAccess
: Expression
{
8286 public BaseAccess (string member
, Location l
)
8288 this.member
= member
;
8292 public override Expression
DoResolve (EmitContext ec
)
8294 Expression c
= CommonResolve (ec
);
8300 // MethodGroups use this opportunity to flag an error on lacking ()
8302 if (!(c
is MethodGroupExpr
))
8303 return c
.Resolve (ec
);
8307 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
8309 Expression c
= CommonResolve (ec
);
8315 // MethodGroups use this opportunity to flag an error on lacking ()
8317 if (! (c
is MethodGroupExpr
))
8318 return c
.DoResolveLValue (ec
, right_side
);
8323 Expression
CommonResolve (EmitContext ec
)
8325 Expression member_lookup
;
8326 Type current_type
= ec
.ContainerType
;
8327 Type base_type
= current_type
.BaseType
;
8331 Error (1511, "Keyword base is not allowed in static method");
8335 if (ec
.IsFieldInitializer
){
8336 Error (1512, "Keyword base is not available in the current context");
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
);
8350 left
= new TypeExpression (base_type
, loc
);
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
;
8362 if (e
is MethodGroupExpr
)
8363 ((MethodGroupExpr
) e
).IsBase
= true;
8368 public override void Emit (EmitContext ec
)
8370 throw new Exception ("Should never be called");
8375 /// The base indexer operator
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
))
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).
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
)
8426 eclass
= ExprClass
.Value
;
8427 loc
= Location
.Null
;
8430 public override Expression
DoResolve (EmitContext ec
)
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
)
8451 public class UserCast
: Expression
{
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
;
8464 public override Expression
DoResolve (EmitContext ec
)
8467 // We are born fully resolved
8472 public override void Emit (EmitContext ec
)
8474 ILGenerator ig
= ec
.ig
;
8478 if (method
is MethodInfo
)
8479 ig
.Emit (OpCodes
.Call
, (MethodInfo
) method
);
8481 ig
.Emit (OpCodes
.Call
, (ConstructorInfo
) method
);
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.
8492 public class ComposedCast
: TypeExpr
{
8496 public ComposedCast (Expression left
, string dim
, Location l
)
8503 public override TypeExpr
DoResolveAsTypeStep (EmitContext ec
)
8505 TypeExpr lexpr
= left
.ResolveAsTypeTerminal (ec
, false);
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");
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
);
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
);
8537 if (!ec
.InUnsafe
&& type
.IsPointer
){
8542 eclass
= ExprClass
.Type
;
8546 public override string Name
{
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
{
8560 public ArrayPtr (Expression array
, Location l
)
8562 Type array_type
= TypeManager
.GetElementType (array
.Type
);
8566 type
= TypeManager
.GetPointerType (array_type
);
8567 eclass
= ExprClass
.Value
;
8571 public override void Emit (EmitContext ec
)
8573 ILGenerator ig
= ec
.ig
;
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
8590 // Used by the fixed statement
8592 public class StringPtr
: Expression
{
8595 public StringPtr (LocalBuilder b
, Location l
)
8598 eclass
= ExprClass
.Value
;
8599 type
= TypeManager
.char_ptr_type
;
8603 public override Expression
DoResolve (EmitContext ec
)
8605 // This should never be invoked, we are born in fully
8606 // initialized state.
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
{
8630 public StackAlloc (Expression type
, Expression count
, Location l
)
8637 public override Expression
DoResolve (EmitContext ec
)
8639 count
= count
.Resolve (ec
);
8643 if (count
.Type
!= TypeManager
.int32_type
){
8644 count
= Convert
.ImplicitConversionRequired (ec
, count
, TypeManager
.int32_type
, loc
);
8649 Constant c
= count
as Constant
;
8650 if (c
!= null && c
.IsNegative
) {
8651 Report
.Error (247, loc
, "Cannot use a negative size with stackalloc");
8655 if (ec
.CurrentBranching
.InCatch () ||
8656 ec
.CurrentBranching
.InFinally (true)) {
8658 "stackalloc can not be used in a catch or finally block");
8662 TypeExpr texpr
= t
.ResolveAsTypeTerminal (ec
, false);
8666 otype
= texpr
.ResolveType (ec
);
8668 if (!TypeManager
.VerifyUnManaged (otype
, loc
))
8671 type
= TypeManager
.GetPointerType (otype
);
8672 eclass
= ExprClass
.Value
;
8677 public override void Emit (EmitContext ec
)
8679 int size
= GetTypeSize (otype
);
8680 ILGenerator ig
= ec
.ig
;
8683 ig
.Emit (OpCodes
.Sizeof
, otype
);
8685 IntConstant
.EmitInt (ig
, size
);
8687 ig
.Emit (OpCodes
.Mul
);
8688 ig
.Emit (OpCodes
.Localloc
);