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
;
18 using Microsoft
.VisualBasic
;
21 /// This is just a helper class, it is generated by Unary, UnaryMutator
22 /// when an overloaded method has been found. It just emits the code for a
25 public class StaticCallExpr
: ExpressionStatement
{
29 public StaticCallExpr (MethodInfo m
, ArrayList a
, Location l
)
35 eclass
= ExprClass
.Value
;
39 public override Expression
DoResolve (EmitContext ec
)
42 // We are born fully resolved
47 public override void Emit (EmitContext ec
)
50 Invocation
.EmitArguments (ec
, mi
, args
, false, null);
52 ec
.ig
.Emit (OpCodes
.Call
, mi
);
56 static public StaticCallExpr
MakeSimpleCall (EmitContext ec
, MethodGroupExpr mg
,
57 Expression e
, Location loc
)
62 args
= new ArrayList (1);
63 Argument a
= new Argument (e
, Argument
.AType
.Expression
);
65 // We need to resolve the arguments before sending them in !
66 if (!a
.Resolve (ec
, loc
))
70 method
= Invocation
.OverloadResolve (
71 ec
, (MethodGroupExpr
) mg
, args
, false, loc
);
76 return new StaticCallExpr ((MethodInfo
) method
, args
, loc
);
79 public override void EmitStatement (EmitContext ec
)
82 if (TypeManager
.TypeToCoreType (type
) != TypeManager
.void_type
)
83 ec
.ig
.Emit (OpCodes
.Pop
);
86 public MethodInfo Method
{
91 public class ParenthesizedExpression
: Expression
93 public Expression Expr
;
95 public ParenthesizedExpression (Expression expr
, Location loc
)
101 public override Expression
DoResolve (EmitContext ec
)
103 Expr
= Expr
.Resolve (ec
);
107 public override void Emit (EmitContext ec
)
109 throw new Exception ("Should not happen");
114 /// Unary expressions.
118 /// Unary implements unary expressions. It derives from
119 /// ExpressionStatement becuase the pre/post increment/decrement
120 /// operators can be used in a statement context.
122 public class Unary
: Expression
{
123 public enum Operator
: byte {
124 UnaryPlus
, UnaryNegation
, LogicalNot
, OnesComplement
,
125 Indirection
, AddressOf
, TOP
128 public Operator Oper
;
129 public Expression Expr
;
131 public Unary (Operator op
, Expression expr
, Location loc
)
139 /// Returns a stringified representation of the Operator
141 static public string OperName (Operator oper
)
144 case Operator
.UnaryPlus
:
146 case Operator
.UnaryNegation
:
148 case Operator
.LogicalNot
:
150 case Operator
.OnesComplement
:
152 case Operator
.AddressOf
:
154 case Operator
.Indirection
:
158 return oper
.ToString ();
161 public static readonly string [] oper_names
;
165 oper_names
= new string [(int)Operator
.TOP
];
167 oper_names
[(int) Operator
.UnaryPlus
] = "op_UnaryPlus";
168 oper_names
[(int) Operator
.UnaryNegation
] = "op_UnaryNegation";
169 oper_names
[(int) Operator
.LogicalNot
] = "op_LogicalNot";
170 oper_names
[(int) Operator
.OnesComplement
] = "op_OnesComplement";
171 oper_names
[(int) Operator
.Indirection
] = "op_Indirection";
172 oper_names
[(int) Operator
.AddressOf
] = "op_AddressOf";
175 void Error23 (Type t
)
178 23, "Operator " + OperName (Oper
) +
179 " cannot be applied to operand of type `" +
180 TypeManager
.CSharpName (t
) + "'");
184 /// The result has been already resolved:
186 /// FIXME: a minus constant -128 sbyte cant be turned into a
189 static Expression
TryReduceNegative (Constant expr
)
193 if (expr
is IntConstant
)
194 e
= new IntConstant (-((IntConstant
) expr
).Value
);
195 else if (expr
is UIntConstant
){
196 uint value = ((UIntConstant
) expr
).Value
;
198 if (value < 2147483649)
199 return new IntConstant (-(int)value);
201 e
= new LongConstant (-value);
203 else if (expr
is LongConstant
)
204 e
= new LongConstant (-((LongConstant
) expr
).Value
);
205 else if (expr
is ULongConstant
){
206 ulong value = ((ULongConstant
) expr
).Value
;
208 if (value < 9223372036854775809)
209 return new LongConstant(-(long)value);
211 else if (expr
is FloatConstant
)
212 e
= new FloatConstant (-((FloatConstant
) expr
).Value
);
213 else if (expr
is DoubleConstant
)
214 e
= new DoubleConstant (-((DoubleConstant
) expr
).Value
);
215 else if (expr
is DecimalConstant
)
216 e
= new DecimalConstant (-((DecimalConstant
) expr
).Value
);
217 else if (expr
is ShortConstant
)
218 e
= new IntConstant (-((ShortConstant
) expr
).Value
);
219 else if (expr
is UShortConstant
)
220 e
= new IntConstant (-((UShortConstant
) expr
).Value
);
221 else if (expr
is SByteConstant
)
222 e
= new IntConstant (-((SByteConstant
) expr
).Value
);
223 else if (expr
is ByteConstant
)
224 e
= new IntConstant (-((ByteConstant
) expr
).Value
);
229 // This routine will attempt to simplify the unary expression when the
230 // argument is a constant. The result is returned in `result' and the
231 // function returns true or false depending on whether a reduction
232 // was performed or not
234 bool Reduce (EmitContext ec
, Constant e
, out Expression result
)
236 Type expr_type
= e
.Type
;
239 case Operator
.UnaryPlus
:
243 case Operator
.UnaryNegation
:
244 result
= TryReduceNegative (e
);
245 return result
!= null;
247 case Operator
.LogicalNot
:
248 if (expr_type
!= TypeManager
.bool_type
) {
254 BoolConstant b
= (BoolConstant
) e
;
255 result
= new BoolConstant (!(b
.Value
));
258 case Operator
.OnesComplement
:
259 if (!((expr_type
== TypeManager
.int32_type
) ||
260 (expr_type
== TypeManager
.uint32_type
) ||
261 (expr_type
== TypeManager
.int64_type
) ||
262 (expr_type
== TypeManager
.uint64_type
) ||
263 (expr_type
.IsSubclassOf (TypeManager
.enum_type
)))){
266 if (Convert
.WideningConversionExists (ec
, e
, TypeManager
.int32_type
)){
267 result
= new Cast (new TypeExpression (TypeManager
.int32_type
, loc
), e
, loc
);
268 result
= result
.Resolve (ec
);
269 } else if (Convert
.WideningConversionExists (ec
, e
, TypeManager
.uint32_type
)){
270 result
= new Cast (new TypeExpression (TypeManager
.uint32_type
, loc
), e
, loc
);
271 result
= result
.Resolve (ec
);
272 } else if (Convert
.WideningConversionExists (ec
, e
, TypeManager
.int64_type
)){
273 result
= new Cast (new TypeExpression (TypeManager
.int64_type
, loc
), e
, loc
);
274 result
= result
.Resolve (ec
);
275 } else if (Convert
.WideningConversionExists (ec
, e
, TypeManager
.uint64_type
)){
276 result
= new Cast (new TypeExpression (TypeManager
.uint64_type
, loc
), e
, loc
);
277 result
= result
.Resolve (ec
);
280 if (result
== null || !(result
is Constant
)){
286 expr_type
= result
.Type
;
287 e
= (Constant
) result
;
290 if (e
is EnumConstant
){
291 EnumConstant enum_constant
= (EnumConstant
) e
;
294 if (Reduce (ec
, enum_constant
.Child
, out reduced
)){
295 result
= new EnumConstant ((Constant
) reduced
, enum_constant
.Type
);
303 if (expr_type
== TypeManager
.int32_type
){
304 result
= new IntConstant (~
((IntConstant
) e
).Value
);
305 } else if (expr_type
== TypeManager
.uint32_type
){
306 result
= new UIntConstant (~
((UIntConstant
) e
).Value
);
307 } else if (expr_type
== TypeManager
.int64_type
){
308 result
= new LongConstant (~
((LongConstant
) e
).Value
);
309 } else if (expr_type
== TypeManager
.uint64_type
){
310 result
= new ULongConstant (~
((ULongConstant
) e
).Value
);
318 case Operator
.AddressOf
:
322 case Operator
.Indirection
:
326 throw new Exception ("Can not constant fold: " + Oper
.ToString());
329 Expression
ResolveOperator (EmitContext ec
)
332 // Step 1: Default operations on CLI native types.
335 // Attempt to use a constant folding operation.
336 if (Expr
is Constant
){
339 if (Reduce (ec
, (Constant
) Expr
, out result
))
344 // Step 2: Perform Operator Overload location
346 Type expr_type
= Expr
.Type
;
350 op_name
= oper_names
[(int) Oper
];
352 mg
= MemberLookup (ec
, expr_type
, op_name
, MemberTypes
.Method
, AllBindingFlags
, loc
);
355 Expression e
= StaticCallExpr
.MakeSimpleCall (
356 ec
, (MethodGroupExpr
) mg
, Expr
, loc
);
366 // Only perform numeric promotions on:
369 if (expr_type
== null)
373 case Operator
.LogicalNot
:
374 if (expr_type
!= TypeManager
.bool_type
) {
375 Expr
= ResolveBoolean (ec
, Expr
, loc
);
382 type
= TypeManager
.bool_type
;
385 case Operator
.OnesComplement
:
386 if (!((expr_type
== TypeManager
.int32_type
) ||
387 (expr_type
== TypeManager
.uint32_type
) ||
388 (expr_type
== TypeManager
.int64_type
) ||
389 (expr_type
== TypeManager
.uint64_type
) ||
390 (expr_type
.IsSubclassOf (TypeManager
.enum_type
)))){
393 e
= Convert
.WideningConversion (ec
, Expr
, TypeManager
.int32_type
, loc
);
395 type
= TypeManager
.int32_type
;
398 e
= Convert
.WideningConversion (ec
, Expr
, TypeManager
.uint32_type
, loc
);
400 type
= TypeManager
.uint32_type
;
403 e
= Convert
.WideningConversion (ec
, Expr
, TypeManager
.int64_type
, loc
);
405 type
= TypeManager
.int64_type
;
408 e
= Convert
.WideningConversion (ec
, Expr
, TypeManager
.uint64_type
, loc
);
410 type
= TypeManager
.uint64_type
;
419 case Operator
.AddressOf
:
420 if (Expr
.eclass
!= ExprClass
.Variable
){
421 Error (211, "Cannot take the address of non-variables");
430 if (!TypeManager
.VerifyUnManaged (Expr
.Type
, loc
)){
434 IVariable variable
= Expr
as IVariable
;
435 bool is_fixed
= variable
!= null && variable
.VerifyFixed (false);
437 if (!ec
.InFixedInitializer
&& !is_fixed
) {
438 Error (212, "You can only take the address of an unfixed expression inside " +
439 "of a fixed statement initializer");
443 if (ec
.InFixedInitializer
&& is_fixed
) {
444 Error (213, "You can not fix an already fixed expression");
448 LocalVariableReference lr
= Expr
as LocalVariableReference
;
450 if (lr
.local_info
.IsCaptured
){
451 AnonymousMethod
.Error_AddressOfCapturedVar (lr
.Name
, loc
);
454 lr
.local_info
.AddressTaken
= true;
455 lr
.local_info
.Used
= true;
458 // According to the specs, a variable is considered definitely assigned if you take
460 if ((variable
!= null) && (variable
.VariableInfo
!= null))
461 variable
.VariableInfo
.SetAssigned (ec
);
463 type
= TypeManager
.GetPointerType (Expr
.Type
);
466 case Operator
.Indirection
:
472 if (!expr_type
.IsPointer
){
473 Error (193, "The * or -> operator can only be applied to pointers");
478 // We create an Indirection expression, because
479 // it can implement the IMemoryLocation.
481 return new Indirection (Expr
, loc
);
483 case Operator
.UnaryPlus
:
485 // A plus in front of something is just a no-op, so return the child.
489 case Operator
.UnaryNegation
:
491 // Deals with -literals
492 // int operator- (int x)
493 // long operator- (long x)
494 // float operator- (float f)
495 // double operator- (double d)
496 // decimal operator- (decimal d)
498 Expression expr
= null;
501 // transform - - expr into expr
504 Unary unary
= (Unary
) Expr
;
506 if (unary
.Oper
== Operator
.UnaryNegation
)
511 // perform numeric promotions to int,
515 // The following is inneficient, because we call
516 // WideningConversion too many times.
518 // It is also not clear if we should convert to Float
519 // or Double initially.
521 if (expr_type
== TypeManager
.uint32_type
){
523 // FIXME: handle exception to this rule that
524 // permits the int value -2147483648 (-2^31) to
525 // bt wrote as a decimal interger literal
527 type
= TypeManager
.int64_type
;
528 Expr
= Convert
.WideningConversion (ec
, Expr
, type
, loc
);
532 if (expr_type
== TypeManager
.uint64_type
){
534 // FIXME: Handle exception of `long value'
535 // -92233720368547758087 (-2^63) to be wrote as
536 // decimal integer literal.
542 if (expr_type
== TypeManager
.float_type
){
547 expr
= Convert
.WideningConversion (ec
, Expr
, TypeManager
.int32_type
, loc
);
554 expr
= Convert
.WideningConversion (ec
, Expr
, TypeManager
.int64_type
, loc
);
561 expr
= Convert
.WideningConversion (ec
, Expr
, TypeManager
.double_type
, loc
);
572 Error (187, "No such operator '" + OperName (Oper
) + "' defined for type '" +
573 TypeManager
.CSharpName (expr_type
) + "'");
577 public override Expression
DoResolve (EmitContext ec
)
579 if (Oper
== Operator
.AddressOf
)
580 Expr
= Expr
.ResolveLValue (ec
, new EmptyExpression ());
582 Expr
= Expr
.Resolve (ec
);
587 if (TypeManager
.IsNullableType (Expr
.Type
))
588 return new Nullable
.LiftedUnaryOperator (Oper
, Expr
, loc
).Resolve (ec
);
590 eclass
= ExprClass
.Value
;
591 return ResolveOperator (ec
);
594 public override Expression
DoResolveLValue (EmitContext ec
, Expression right
)
596 if (Oper
== Operator
.Indirection
)
597 return base.DoResolveLValue (ec
, right
);
599 Error (131, "The left-hand side of an assignment must be a " +
600 "variable, property or indexer");
604 public override void Emit (EmitContext ec
)
606 ILGenerator ig
= ec
.ig
;
609 case Operator
.UnaryPlus
:
610 throw new Exception ("This should be caught by Resolve");
612 case Operator
.UnaryNegation
:
614 ig
.Emit (OpCodes
.Ldc_I4_0
);
615 if (type
== TypeManager
.int64_type
)
616 ig
.Emit (OpCodes
.Conv_U8
);
618 ig
.Emit (OpCodes
.Sub_Ovf
);
621 ig
.Emit (OpCodes
.Neg
);
626 case Operator
.LogicalNot
:
628 ig
.Emit (OpCodes
.Ldc_I4_0
);
629 ig
.Emit (OpCodes
.Ceq
);
632 case Operator
.OnesComplement
:
634 ig
.Emit (OpCodes
.Not
);
637 case Operator
.AddressOf
:
638 ((IMemoryLocation
)Expr
).AddressOf (ec
, AddressOp
.LoadStore
);
642 throw new Exception ("This should not happen: Operator = "
647 public override void EmitBranchable (EmitContext ec
, Label target
, bool onTrue
)
649 if (Oper
== Operator
.LogicalNot
)
650 Expr
.EmitBranchable (ec
, target
, !onTrue
);
652 base.EmitBranchable (ec
, target
, onTrue
);
655 public override string ToString ()
657 return "Unary (" + Oper
+ ", " + Expr
+ ")";
663 // Unary operators are turned into Indirection expressions
664 // after semantic analysis (this is so we can take the address
665 // of an indirection).
667 public class Indirection
: Expression
, IMemoryLocation
, IAssignMethod
, IVariable
{
669 LocalTemporary temporary
;
672 public Indirection (Expression expr
, Location l
)
675 this.type
= TypeManager
.GetElementType (expr
.Type
);
676 eclass
= ExprClass
.Variable
;
680 void LoadExprValue (EmitContext ec
)
684 public override void Emit (EmitContext ec
)
689 LoadFromPtr (ec
.ig
, Type
);
692 public void Emit (EmitContext ec
, bool leave_copy
)
696 ec
.ig
.Emit (OpCodes
.Dup
);
697 temporary
= new LocalTemporary (ec
, expr
.Type
);
698 temporary
.Store (ec
);
702 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
704 prepared
= prepare_for_load
;
708 if (prepare_for_load
)
709 ec
.ig
.Emit (OpCodes
.Dup
);
713 ec
.ig
.Emit (OpCodes
.Dup
);
714 temporary
= new LocalTemporary (ec
, expr
.Type
);
715 temporary
.Store (ec
);
718 StoreFromPtr (ec
.ig
, type
);
720 if (temporary
!= null)
724 public void AddressOf (EmitContext ec
, AddressOp Mode
)
729 public override Expression
DoResolve (EmitContext ec
)
732 // Born fully resolved
737 public override string ToString ()
739 return "*(" + expr
+ ")";
742 #region IVariable Members
744 public VariableInfo VariableInfo
{
750 public bool VerifyFixed (bool is_expression
)
759 /// Unary Mutator expressions (pre and post ++ and --)
763 /// UnaryMutator implements ++ and -- expressions. It derives from
764 /// ExpressionStatement becuase the pre/post increment/decrement
765 /// operators can be used in a statement context.
767 /// FIXME: Idea, we could split this up in two classes, one simpler
768 /// for the common case, and one with the extra fields for more complex
769 /// classes (indexers require temporary access; overloaded require method)
772 public class UnaryMutator
: ExpressionStatement
{
774 public enum Mode
: byte {
781 PreDecrement
= IsDecrement
,
782 PostIncrement
= IsPost
,
783 PostDecrement
= IsPost
| IsDecrement
787 bool is_expr
= false;
788 bool recurse
= false;
793 // This is expensive for the simplest case.
795 StaticCallExpr method
;
797 public UnaryMutator (Mode m
, Expression e
, Location l
)
804 static string OperName (Mode mode
)
806 return (mode
== Mode
.PreIncrement
|| mode
== Mode
.PostIncrement
) ?
810 void Error23 (Type t
)
813 23, "Operator " + OperName (mode
) +
814 " cannot be applied to operand of type `" +
815 TypeManager
.CSharpName (t
) + "'");
819 /// Returns whether an object of type `t' can be incremented
820 /// or decremented with add/sub (ie, basically whether we can
821 /// use pre-post incr-decr operations on it, but it is not a
822 /// System.Decimal, which we require operator overloading to catch)
824 static bool IsIncrementableNumber (Type t
)
826 return (t
== TypeManager
.sbyte_type
) ||
827 (t
== TypeManager
.byte_type
) ||
828 (t
== TypeManager
.short_type
) ||
829 (t
== TypeManager
.ushort_type
) ||
830 (t
== TypeManager
.int32_type
) ||
831 (t
== TypeManager
.uint32_type
) ||
832 (t
== TypeManager
.int64_type
) ||
833 (t
== TypeManager
.uint64_type
) ||
834 (t
== TypeManager
.char_type
) ||
835 (t
.IsSubclassOf (TypeManager
.enum_type
)) ||
836 (t
== TypeManager
.float_type
) ||
837 (t
== TypeManager
.double_type
) ||
838 (t
.IsPointer
&& t
!= TypeManager
.void_ptr_type
);
841 Expression
ResolveOperator (EmitContext ec
)
843 Type expr_type
= expr
.Type
;
846 // Step 1: Perform Operator Overload location
851 if (mode
== Mode
.PreIncrement
|| mode
== Mode
.PostIncrement
)
852 op_name
= "op_Increment";
854 op_name
= "op_Decrement";
856 mg
= MemberLookup (ec
, expr_type
, op_name
, MemberTypes
.Method
, AllBindingFlags
, loc
);
858 if (mg
== null && expr_type
.BaseType
!= null)
859 mg
= MemberLookup (ec
, expr_type
.BaseType
, op_name
,
860 MemberTypes
.Method
, AllBindingFlags
, loc
);
863 method
= StaticCallExpr
.MakeSimpleCall (
864 ec
, (MethodGroupExpr
) mg
, expr
, loc
);
871 // The operand of the prefix/postfix increment decrement operators
872 // should be an expression that is classified as a variable,
873 // a property access or an indexer access
876 if (expr
.eclass
== ExprClass
.Variable
){
877 LocalVariableReference
var = expr
as LocalVariableReference
;
878 if ((var != null) && var.IsReadOnly
)
879 Error (1604, "cannot assign to `" + var.Name
+ "' because it is readonly");
880 if (IsIncrementableNumber (expr_type
) ||
881 expr_type
== TypeManager
.decimal_type
){
884 } else if (expr
.eclass
== ExprClass
.IndexerAccess
){
885 IndexerAccess ia
= (IndexerAccess
) expr
;
887 expr
= ia
.ResolveLValue (ec
, this);
892 } else if (expr
.eclass
== ExprClass
.PropertyAccess
){
893 PropertyExpr pe
= (PropertyExpr
) expr
;
895 if (pe
.VerifyAssignable ())
900 expr
.Error_UnexpectedKind ("variable, indexer or property access", loc
);
904 Error (187, "No such operator '" + OperName (mode
) + "' defined for type '" +
905 TypeManager
.CSharpName (expr_type
) + "'");
909 public override Expression
DoResolve (EmitContext ec
)
911 expr
= expr
.Resolve (ec
);
916 eclass
= ExprClass
.Value
;
918 if (TypeManager
.IsNullableType (expr
.Type
))
919 return new Nullable
.LiftedUnaryMutator (mode
, expr
, loc
).Resolve (ec
);
921 return ResolveOperator (ec
);
924 static int PtrTypeSize (Type t
)
926 return GetTypeSize (TypeManager
.GetElementType (t
));
930 // Loads the proper "1" into the stack based on the type, then it emits the
931 // opcode for the operation requested
933 void LoadOneAndEmitOp (EmitContext ec
, Type t
)
936 // Measure if getting the typecode and using that is more/less efficient
937 // that comparing types. t.GetTypeCode() is an internal call.
939 ILGenerator ig
= ec
.ig
;
941 if (t
== TypeManager
.uint64_type
|| t
== TypeManager
.int64_type
)
942 LongConstant
.EmitLong (ig
, 1);
943 else if (t
== TypeManager
.double_type
)
944 ig
.Emit (OpCodes
.Ldc_R8
, 1.0);
945 else if (t
== TypeManager
.float_type
)
946 ig
.Emit (OpCodes
.Ldc_R4
, 1.0F
);
947 else if (t
.IsPointer
){
948 int n
= PtrTypeSize (t
);
951 ig
.Emit (OpCodes
.Sizeof
, t
);
953 IntConstant
.EmitInt (ig
, n
);
955 ig
.Emit (OpCodes
.Ldc_I4_1
);
958 // Now emit the operation
961 if (t
== TypeManager
.int32_type
||
962 t
== TypeManager
.int64_type
){
963 if ((mode
& Mode
.IsDecrement
) != 0)
964 ig
.Emit (OpCodes
.Sub_Ovf
);
966 ig
.Emit (OpCodes
.Add_Ovf
);
967 } else if (t
== TypeManager
.uint32_type
||
968 t
== TypeManager
.uint64_type
){
969 if ((mode
& Mode
.IsDecrement
) != 0)
970 ig
.Emit (OpCodes
.Sub_Ovf_Un
);
972 ig
.Emit (OpCodes
.Add_Ovf_Un
);
974 if ((mode
& Mode
.IsDecrement
) != 0)
975 ig
.Emit (OpCodes
.Sub_Ovf
);
977 ig
.Emit (OpCodes
.Add_Ovf
);
980 if ((mode
& Mode
.IsDecrement
) != 0)
981 ig
.Emit (OpCodes
.Sub
);
983 ig
.Emit (OpCodes
.Add
);
986 if (t
== TypeManager
.sbyte_type
){
988 ig
.Emit (OpCodes
.Conv_Ovf_I1
);
990 ig
.Emit (OpCodes
.Conv_I1
);
991 } else if (t
== TypeManager
.byte_type
){
993 ig
.Emit (OpCodes
.Conv_Ovf_U1
);
995 ig
.Emit (OpCodes
.Conv_U1
);
996 } else if (t
== TypeManager
.short_type
){
998 ig
.Emit (OpCodes
.Conv_Ovf_I2
);
1000 ig
.Emit (OpCodes
.Conv_I2
);
1001 } else if (t
== TypeManager
.ushort_type
|| t
== TypeManager
.char_type
){
1003 ig
.Emit (OpCodes
.Conv_Ovf_U2
);
1005 ig
.Emit (OpCodes
.Conv_U2
);
1010 void EmitCode (EmitContext ec
, bool is_expr
)
1013 this.is_expr
= is_expr
;
1014 ((IAssignMethod
) expr
).EmitAssign (ec
, this, is_expr
&& (mode
== Mode
.PreIncrement
|| mode
== Mode
.PreDecrement
), true);
1017 public override void Emit (EmitContext ec
)
1020 // We use recurse to allow ourselfs to be the source
1021 // of an assignment. This little hack prevents us from
1022 // having to allocate another expression
1025 ((IAssignMethod
) expr
).Emit (ec
, is_expr
&& (mode
== Mode
.PostIncrement
|| mode
== Mode
.PostDecrement
));
1027 LoadOneAndEmitOp (ec
, expr
.Type
);
1029 ec
.ig
.Emit (OpCodes
.Call
, method
.Method
);
1034 EmitCode (ec
, true);
1037 public override void EmitStatement (EmitContext ec
)
1039 EmitCode (ec
, false);
1044 /// Base class for the `Is' and `As' classes.
1048 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1051 public abstract class Probe
: Expression
{
1052 public Expression ProbeType
;
1053 protected Expression expr
;
1054 protected Type probe_type
;
1056 public Probe (Expression expr
, Expression probe_type
, Location l
)
1058 ProbeType
= probe_type
;
1063 public Expression Expr
{
1069 public override Expression
DoResolve (EmitContext ec
)
1071 TypeExpr texpr
= ProbeType
.ResolveAsTypeTerminal (ec
);
1074 probe_type
= texpr
.Type
;
1076 CheckObsoleteAttribute (probe_type
);
1078 expr
= expr
.Resolve (ec
);
1082 if (expr
.Type
.IsPointer
) {
1083 Report
.Error (244, loc
, "\"is\" or \"as\" are not valid on pointer types");
1091 /// Implementation of the `is' operator.
1093 public class Is
: Probe
{
1094 public Is (Expression expr
, Expression probe_type
, Location l
)
1095 : base (expr
, probe_type
, l
)
1100 AlwaysTrue
, AlwaysNull
, AlwaysFalse
, LeaveOnStack
, Probe
1105 public override void Emit (EmitContext ec
)
1107 ILGenerator ig
= ec
.ig
;
1112 case Action
.AlwaysFalse
:
1113 ig
.Emit (OpCodes
.Pop
);
1114 IntConstant
.EmitInt (ig
, 0);
1116 case Action
.AlwaysTrue
:
1117 ig
.Emit (OpCodes
.Pop
);
1118 IntConstant
.EmitInt (ig
, 1);
1120 case Action
.LeaveOnStack
:
1121 // the `e != null' rule.
1122 ig
.Emit (OpCodes
.Ldnull
);
1123 ig
.Emit (OpCodes
.Ceq
);
1124 ig
.Emit (OpCodes
.Ldc_I4_0
);
1125 ig
.Emit (OpCodes
.Ceq
);
1128 ig
.Emit (OpCodes
.Isinst
, probe_type
);
1129 ig
.Emit (OpCodes
.Ldnull
);
1130 ig
.Emit (OpCodes
.Cgt_Un
);
1133 throw new Exception ("never reached");
1136 public override void EmitBranchable (EmitContext ec
, Label target
, bool onTrue
)
1138 ILGenerator ig
= ec
.ig
;
1141 case Action
.AlwaysFalse
:
1143 ig
.Emit (OpCodes
.Br
, target
);
1146 case Action
.AlwaysTrue
:
1148 ig
.Emit (OpCodes
.Br
, target
);
1151 case Action
.LeaveOnStack
:
1152 // the `e != null' rule.
1154 ig
.Emit (onTrue
? OpCodes
.Brtrue
: OpCodes
.Brfalse
, target
);
1158 ig
.Emit (OpCodes
.Isinst
, probe_type
);
1159 ig
.Emit (onTrue
? OpCodes
.Brtrue
: OpCodes
.Brfalse
, target
);
1162 throw new Exception ("never reached");
1165 public override Expression
DoResolve (EmitContext ec
)
1167 Expression e
= base.DoResolve (ec
);
1169 if ((e
== null) || (expr
== null))
1172 Type etype
= expr
.Type
;
1173 bool warning_always_matches
= false;
1174 bool warning_never_matches
= false;
1176 type
= TypeManager
.bool_type
;
1177 eclass
= ExprClass
.Value
;
1180 // First case, if at compile time, there is an implicit conversion
1181 // then e != null (objects) or true (value types)
1183 e
= Convert
.WideningConversionStandard (ec
, expr
, probe_type
, loc
);
1186 if (etype
.IsValueType
)
1187 action
= Action
.AlwaysTrue
;
1189 action
= Action
.LeaveOnStack
;
1191 warning_always_matches
= true;
1192 } else if (Convert
.NarrowingReferenceConversionExists (etype
, probe_type
)){
1193 if (etype
.IsGenericParameter
)
1194 expr
= new BoxedCast (expr
, etype
);
1197 // Second case: explicit reference convresion
1199 if (expr
is NullLiteral
)
1200 action
= Action
.AlwaysFalse
;
1202 action
= Action
.Probe
;
1204 action
= Action
.AlwaysFalse
;
1205 warning_never_matches
= true;
1208 if (warning_always_matches
)
1209 Warning (183, "The given expression is always of the provided ('{0}') type", TypeManager
.CSharpName (probe_type
));
1210 else if (warning_never_matches
){
1211 if (!(probe_type
.IsInterface
|| expr
.Type
.IsInterface
))
1212 Warning (184, "The given expression is never of the provided ('{0}') type", TypeManager
.CSharpName (probe_type
));
1220 /// Implementation of the `as' operator.
1222 public class As
: Probe
{
1223 public As (Expression expr
, Expression probe_type
, Location l
)
1224 : base (expr
, probe_type
, l
)
1228 bool do_isinst
= false;
1230 public override void Emit (EmitContext ec
)
1232 ILGenerator ig
= ec
.ig
;
1237 ig
.Emit (OpCodes
.Isinst
, probe_type
);
1240 static void Error_CannotConvertType (Type source
, Type target
, Location loc
)
1243 39, loc
, "as operator can not convert from `" +
1244 TypeManager
.CSharpName (source
) + "' to `" +
1245 TypeManager
.CSharpName (target
) + "'");
1248 public override Expression
DoResolve (EmitContext ec
)
1250 Expression e
= base.DoResolve (ec
);
1256 eclass
= ExprClass
.Value
;
1257 Type etype
= expr
.Type
;
1259 if (TypeManager
.IsValueType (probe_type
)){
1260 Report
.Error (77, loc
, "The as operator should be used with a reference type only (" +
1261 TypeManager
.CSharpName (probe_type
) + " is a value type)");
1266 e
= Convert
.WideningConversion (ec
, expr
, probe_type
, loc
);
1273 if (Convert
.NarrowingReferenceConversionExists (etype
, probe_type
)){
1274 if (etype
.IsGenericParameter
)
1275 expr
= new BoxedCast (expr
, etype
);
1281 Error_CannotConvertType (etype
, probe_type
, loc
);
1287 /// This represents a typecast in the source language.
1289 /// FIXME: Cast expressions have an unusual set of parsing
1290 /// rules, we need to figure those out.
1292 public class Cast
: Expression
{
1293 Expression target_type
;
1296 public Cast (Expression cast_type
, Expression expr
, Location loc
)
1298 this.target_type
= cast_type
;
1303 public Expression TargetType
{
1309 public Expression Expr
{
1318 bool CheckRange (EmitContext ec
, long value, Type type
, long min
, long max
)
1320 if (!ec
.ConstantCheckState
)
1323 if ((value < min
) || (value > max
)) {
1324 Error (221, "Constant value `" + value + "' cannot be converted " +
1325 "to a `" + TypeManager
.CSharpName (type
) + "' (use `unchecked' " +
1326 "syntax to override)");
1333 bool CheckRange (EmitContext ec
, ulong value, Type type
, ulong max
)
1335 if (!ec
.ConstantCheckState
)
1339 Error (221, "Constant value `" + value + "' cannot be converted " +
1340 "to a `" + TypeManager
.CSharpName (type
) + "' (use `unchecked' " +
1341 "syntax to override)");
1348 bool CheckUnsigned (EmitContext ec
, long value, Type type
)
1350 if (!ec
.ConstantCheckState
)
1354 Error (221, "Constant value `" + value + "' cannot be converted " +
1355 "to a `" + TypeManager
.CSharpName (type
) + "' (use `unchecked' " +
1356 "syntax to override)");
1364 /// Attempts to do a compile-time folding of a constant cast.
1366 Expression
TryReduce (EmitContext ec
, Type target_type
)
1368 Expression real_expr
= expr
;
1369 if (real_expr
is EnumConstant
)
1370 real_expr
= ((EnumConstant
) real_expr
).Child
;
1372 if (real_expr
is ByteConstant
){
1373 byte v
= ((ByteConstant
) real_expr
).Value
;
1375 if (target_type
== TypeManager
.sbyte_type
) {
1376 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1378 return new SByteConstant ((sbyte) v
);
1380 if (target_type
== TypeManager
.short_type
)
1381 return new ShortConstant ((short) v
);
1382 if (target_type
== TypeManager
.ushort_type
)
1383 return new UShortConstant ((ushort) v
);
1384 if (target_type
== TypeManager
.int32_type
)
1385 return new IntConstant ((int) v
);
1386 if (target_type
== TypeManager
.uint32_type
)
1387 return new UIntConstant ((uint) v
);
1388 if (target_type
== TypeManager
.int64_type
)
1389 return new LongConstant ((long) v
);
1390 if (target_type
== TypeManager
.uint64_type
)
1391 return new ULongConstant ((ulong) v
);
1392 if (target_type
== TypeManager
.float_type
)
1393 return new FloatConstant ((float) v
);
1394 if (target_type
== TypeManager
.double_type
)
1395 return new DoubleConstant ((double) v
);
1396 if (target_type
== TypeManager
.char_type
)
1397 return new CharConstant ((char) v
);
1398 if (target_type
== TypeManager
.decimal_type
)
1399 return new DecimalConstant ((decimal) v
);
1401 if (real_expr
is SByteConstant
){
1402 sbyte v
= ((SByteConstant
) real_expr
).Value
;
1404 if (target_type
== TypeManager
.byte_type
) {
1405 if (!CheckUnsigned (ec
, v
, target_type
))
1407 return new ByteConstant ((byte) v
);
1409 if (target_type
== TypeManager
.short_type
)
1410 return new ShortConstant ((short) v
);
1411 if (target_type
== TypeManager
.ushort_type
) {
1412 if (!CheckUnsigned (ec
, v
, target_type
))
1414 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
);
1421 } if (target_type
== TypeManager
.int64_type
)
1422 return new LongConstant ((long) v
);
1423 if (target_type
== TypeManager
.uint64_type
) {
1424 if (!CheckUnsigned (ec
, v
, target_type
))
1426 return new ULongConstant ((ulong) v
);
1428 if (target_type
== TypeManager
.float_type
)
1429 return new FloatConstant ((float) v
);
1430 if (target_type
== TypeManager
.double_type
)
1431 return new DoubleConstant ((double) v
);
1432 if (target_type
== TypeManager
.char_type
) {
1433 if (!CheckUnsigned (ec
, v
, target_type
))
1435 return new CharConstant ((char) v
);
1437 if (target_type
== TypeManager
.decimal_type
)
1438 return new DecimalConstant ((decimal) v
);
1440 if (real_expr
is ShortConstant
){
1441 short v
= ((ShortConstant
) real_expr
).Value
;
1443 if (target_type
== TypeManager
.byte_type
) {
1444 if (!CheckRange (ec
, v
, target_type
, Byte
.MinValue
, Byte
.MaxValue
))
1446 return new ByteConstant ((byte) v
);
1448 if (target_type
== TypeManager
.sbyte_type
) {
1449 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1451 return new SByteConstant ((sbyte) v
);
1453 if (target_type
== TypeManager
.ushort_type
) {
1454 if (!CheckUnsigned (ec
, v
, target_type
))
1456 return new UShortConstant ((ushort) v
);
1458 if (target_type
== TypeManager
.int32_type
)
1459 return new IntConstant ((int) v
);
1460 if (target_type
== TypeManager
.uint32_type
) {
1461 if (!CheckUnsigned (ec
, v
, target_type
))
1463 return new UIntConstant ((uint) v
);
1465 if (target_type
== TypeManager
.int64_type
)
1466 return new LongConstant ((long) v
);
1467 if (target_type
== TypeManager
.uint64_type
) {
1468 if (!CheckUnsigned (ec
, v
, target_type
))
1470 return new ULongConstant ((ulong) v
);
1472 if (target_type
== TypeManager
.float_type
)
1473 return new FloatConstant ((float) v
);
1474 if (target_type
== TypeManager
.double_type
)
1475 return new DoubleConstant ((double) v
);
1476 if (target_type
== TypeManager
.char_type
) {
1477 if (!CheckRange (ec
, v
, target_type
, Char
.MinValue
, Char
.MaxValue
))
1479 return new CharConstant ((char) v
);
1481 if (target_type
== TypeManager
.decimal_type
)
1482 return new DecimalConstant ((decimal) v
);
1484 if (real_expr
is UShortConstant
){
1485 ushort v
= ((UShortConstant
) real_expr
).Value
;
1487 if (target_type
== TypeManager
.byte_type
) {
1488 if (!CheckRange (ec
, v
, target_type
, Byte
.MinValue
, Byte
.MaxValue
))
1490 return new ByteConstant ((byte) v
);
1492 if (target_type
== TypeManager
.sbyte_type
) {
1493 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1495 return new SByteConstant ((sbyte) v
);
1497 if (target_type
== TypeManager
.short_type
) {
1498 if (!CheckRange (ec
, v
, target_type
, Int16
.MinValue
, Int16
.MaxValue
))
1500 return new ShortConstant ((short) v
);
1502 if (target_type
== TypeManager
.int32_type
)
1503 return new IntConstant ((int) v
);
1504 if (target_type
== TypeManager
.uint32_type
)
1505 return new UIntConstant ((uint) v
);
1506 if (target_type
== TypeManager
.int64_type
)
1507 return new LongConstant ((long) v
);
1508 if (target_type
== TypeManager
.uint64_type
)
1509 return new ULongConstant ((ulong) v
);
1510 if (target_type
== TypeManager
.float_type
)
1511 return new FloatConstant ((float) v
);
1512 if (target_type
== TypeManager
.double_type
)
1513 return new DoubleConstant ((double) v
);
1514 if (target_type
== TypeManager
.char_type
) {
1515 if (!CheckRange (ec
, v
, target_type
, Char
.MinValue
, Char
.MaxValue
))
1517 return new CharConstant ((char) v
);
1519 if (target_type
== TypeManager
.decimal_type
)
1520 return new DecimalConstant ((decimal) v
);
1522 if (real_expr
is IntConstant
){
1523 int v
= ((IntConstant
) real_expr
).Value
;
1525 if (target_type
== TypeManager
.byte_type
) {
1526 if (!CheckRange (ec
, v
, target_type
, Byte
.MinValue
, Byte
.MaxValue
))
1528 return new ByteConstant ((byte) v
);
1530 if (target_type
== TypeManager
.sbyte_type
) {
1531 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1533 return new SByteConstant ((sbyte) v
);
1535 if (target_type
== TypeManager
.short_type
) {
1536 if (!CheckRange (ec
, v
, target_type
, Int16
.MinValue
, Int16
.MaxValue
))
1538 return new ShortConstant ((short) v
);
1540 if (target_type
== TypeManager
.ushort_type
) {
1541 if (!CheckRange (ec
, v
, target_type
, UInt16
.MinValue
, UInt16
.MaxValue
))
1543 return new UShortConstant ((ushort) v
);
1545 if (target_type
== TypeManager
.uint32_type
) {
1546 if (!CheckRange (ec
, v
, target_type
, Int32
.MinValue
, Int32
.MaxValue
))
1548 return new UIntConstant ((uint) v
);
1550 if (target_type
== TypeManager
.int64_type
)
1551 return new LongConstant ((long) v
);
1552 if (target_type
== TypeManager
.uint64_type
) {
1553 if (!CheckUnsigned (ec
, v
, target_type
))
1555 return new ULongConstant ((ulong) v
);
1557 if (target_type
== TypeManager
.float_type
)
1558 return new FloatConstant ((float) v
);
1559 if (target_type
== TypeManager
.double_type
)
1560 return new DoubleConstant ((double) v
);
1561 if (target_type
== TypeManager
.char_type
) {
1562 if (!CheckRange (ec
, v
, target_type
, Char
.MinValue
, Char
.MaxValue
))
1564 return new CharConstant ((char) v
);
1566 if (target_type
== TypeManager
.decimal_type
)
1567 return new DecimalConstant ((decimal) v
);
1569 if (real_expr
is UIntConstant
){
1570 uint v
= ((UIntConstant
) real_expr
).Value
;
1572 if (target_type
== TypeManager
.byte_type
) {
1573 if (!CheckRange (ec
, v
, target_type
, Char
.MinValue
, Char
.MaxValue
))
1575 return new ByteConstant ((byte) v
);
1577 if (target_type
== TypeManager
.sbyte_type
) {
1578 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1580 return new SByteConstant ((sbyte) v
);
1582 if (target_type
== TypeManager
.short_type
) {
1583 if (!CheckRange (ec
, v
, target_type
, Int16
.MinValue
, Int16
.MaxValue
))
1585 return new ShortConstant ((short) v
);
1587 if (target_type
== TypeManager
.ushort_type
) {
1588 if (!CheckRange (ec
, v
, target_type
, UInt16
.MinValue
, UInt16
.MaxValue
))
1590 return new UShortConstant ((ushort) v
);
1592 if (target_type
== TypeManager
.int32_type
) {
1593 if (!CheckRange (ec
, v
, target_type
, Int32
.MinValue
, Int32
.MaxValue
))
1595 return new IntConstant ((int) v
);
1597 if (target_type
== TypeManager
.int64_type
)
1598 return new LongConstant ((long) v
);
1599 if (target_type
== TypeManager
.uint64_type
)
1600 return new ULongConstant ((ulong) v
);
1601 if (target_type
== TypeManager
.float_type
)
1602 return new FloatConstant ((float) v
);
1603 if (target_type
== TypeManager
.double_type
)
1604 return new DoubleConstant ((double) v
);
1605 if (target_type
== TypeManager
.char_type
) {
1606 if (!CheckRange (ec
, v
, target_type
, Char
.MinValue
, Char
.MaxValue
))
1608 return new CharConstant ((char) v
);
1610 if (target_type
== TypeManager
.decimal_type
)
1611 return new DecimalConstant ((decimal) v
);
1613 if (real_expr
is LongConstant
){
1614 long v
= ((LongConstant
) real_expr
).Value
;
1616 if (target_type
== TypeManager
.byte_type
) {
1617 if (!CheckRange (ec
, v
, target_type
, Byte
.MinValue
, Byte
.MaxValue
))
1619 return new ByteConstant ((byte) v
);
1621 if (target_type
== TypeManager
.sbyte_type
) {
1622 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1624 return new SByteConstant ((sbyte) v
);
1626 if (target_type
== TypeManager
.short_type
) {
1627 if (!CheckRange (ec
, v
, target_type
, Int16
.MinValue
, Int16
.MaxValue
))
1629 return new ShortConstant ((short) v
);
1631 if (target_type
== TypeManager
.ushort_type
) {
1632 if (!CheckRange (ec
, v
, target_type
, UInt16
.MinValue
, UInt16
.MaxValue
))
1634 return new UShortConstant ((ushort) v
);
1636 if (target_type
== TypeManager
.int32_type
) {
1637 if (!CheckRange (ec
, v
, target_type
, Int32
.MinValue
, Int32
.MaxValue
))
1639 return new IntConstant ((int) v
);
1641 if (target_type
== TypeManager
.uint32_type
) {
1642 if (!CheckRange (ec
, v
, target_type
, UInt32
.MinValue
, UInt32
.MaxValue
))
1644 return new UIntConstant ((uint) v
);
1646 if (target_type
== TypeManager
.uint64_type
) {
1647 if (!CheckUnsigned (ec
, v
, target_type
))
1649 return new ULongConstant ((ulong) v
);
1651 if (target_type
== TypeManager
.float_type
)
1652 return new FloatConstant ((float) v
);
1653 if (target_type
== TypeManager
.double_type
)
1654 return new DoubleConstant ((double) v
);
1655 if (target_type
== TypeManager
.char_type
) {
1656 if (!CheckRange (ec
, v
, target_type
, Char
.MinValue
, Char
.MaxValue
))
1658 return new CharConstant ((char) v
);
1660 if (target_type
== TypeManager
.decimal_type
)
1661 return new DecimalConstant ((decimal) v
);
1663 if (real_expr
is ULongConstant
){
1664 ulong v
= ((ULongConstant
) real_expr
).Value
;
1666 if (target_type
== TypeManager
.byte_type
) {
1667 if (!CheckRange (ec
, v
, target_type
, Byte
.MaxValue
))
1669 return new ByteConstant ((byte) v
);
1671 if (target_type
== TypeManager
.sbyte_type
) {
1672 if (!CheckRange (ec
, v
, target_type
, (ulong) SByte
.MaxValue
))
1674 return new SByteConstant ((sbyte) v
);
1676 if (target_type
== TypeManager
.short_type
) {
1677 if (!CheckRange (ec
, v
, target_type
, (ulong) Int16
.MaxValue
))
1679 return new ShortConstant ((short) v
);
1681 if (target_type
== TypeManager
.ushort_type
) {
1682 if (!CheckRange (ec
, v
, target_type
, UInt16
.MaxValue
))
1684 return new UShortConstant ((ushort) v
);
1686 if (target_type
== TypeManager
.int32_type
) {
1687 if (!CheckRange (ec
, v
, target_type
, Int32
.MaxValue
))
1689 return new IntConstant ((int) v
);
1691 if (target_type
== TypeManager
.uint32_type
) {
1692 if (!CheckRange (ec
, v
, target_type
, UInt32
.MaxValue
))
1694 return new UIntConstant ((uint) v
);
1696 if (target_type
== TypeManager
.int64_type
) {
1697 if (!CheckRange (ec
, v
, target_type
, (ulong) Int64
.MaxValue
))
1699 return new LongConstant ((long) v
);
1701 if (target_type
== TypeManager
.float_type
)
1702 return new FloatConstant ((float) v
);
1703 if (target_type
== TypeManager
.double_type
)
1704 return new DoubleConstant ((double) v
);
1705 if (target_type
== TypeManager
.char_type
) {
1706 if (!CheckRange (ec
, v
, target_type
, Char
.MaxValue
))
1708 return new CharConstant ((char) v
);
1710 if (target_type
== TypeManager
.decimal_type
)
1711 return new DecimalConstant ((decimal) v
);
1713 if (real_expr
is FloatConstant
){
1714 float v
= ((FloatConstant
) real_expr
).Value
;
1716 if (target_type
== TypeManager
.byte_type
)
1717 return new ByteConstant ((byte) v
);
1718 if (target_type
== TypeManager
.sbyte_type
)
1719 return new SByteConstant ((sbyte) v
);
1720 if (target_type
== TypeManager
.short_type
)
1721 return new ShortConstant ((short) v
);
1722 if (target_type
== TypeManager
.ushort_type
)
1723 return new UShortConstant ((ushort) v
);
1724 if (target_type
== TypeManager
.int32_type
)
1725 return new IntConstant ((int) v
);
1726 if (target_type
== TypeManager
.uint32_type
)
1727 return new UIntConstant ((uint) v
);
1728 if (target_type
== TypeManager
.int64_type
)
1729 return new LongConstant ((long) v
);
1730 if (target_type
== TypeManager
.uint64_type
)
1731 return new ULongConstant ((ulong) v
);
1732 if (target_type
== TypeManager
.double_type
)
1733 return new DoubleConstant ((double) v
);
1734 if (target_type
== TypeManager
.char_type
)
1735 return new CharConstant ((char) v
);
1736 if (target_type
== TypeManager
.decimal_type
)
1737 return new DecimalConstant ((decimal) v
);
1739 if (real_expr
is DoubleConstant
){
1740 double v
= ((DoubleConstant
) real_expr
).Value
;
1742 if (target_type
== TypeManager
.byte_type
){
1743 return new ByteConstant ((byte) v
);
1744 } if (target_type
== TypeManager
.sbyte_type
)
1745 return new SByteConstant ((sbyte) v
);
1746 if (target_type
== TypeManager
.short_type
)
1747 return new ShortConstant ((short) v
);
1748 if (target_type
== TypeManager
.ushort_type
)
1749 return new UShortConstant ((ushort) v
);
1750 if (target_type
== TypeManager
.int32_type
)
1751 return new IntConstant ((int) v
);
1752 if (target_type
== TypeManager
.uint32_type
)
1753 return new UIntConstant ((uint) v
);
1754 if (target_type
== TypeManager
.int64_type
)
1755 return new LongConstant ((long) v
);
1756 if (target_type
== TypeManager
.uint64_type
)
1757 return new ULongConstant ((ulong) v
);
1758 if (target_type
== TypeManager
.float_type
)
1759 return new FloatConstant ((float) v
);
1760 if (target_type
== TypeManager
.char_type
)
1761 return new CharConstant ((char) v
);
1762 if (target_type
== TypeManager
.decimal_type
)
1763 return new DecimalConstant ((decimal) v
);
1766 if (real_expr
is CharConstant
){
1767 char v
= ((CharConstant
) real_expr
).Value
;
1769 if (target_type
== TypeManager
.byte_type
) {
1770 if (!CheckRange (ec
, v
, target_type
, Byte
.MinValue
, Byte
.MaxValue
))
1772 return new ByteConstant ((byte) v
);
1774 if (target_type
== TypeManager
.sbyte_type
) {
1775 if (!CheckRange (ec
, v
, target_type
, SByte
.MinValue
, SByte
.MaxValue
))
1777 return new SByteConstant ((sbyte) v
);
1779 if (target_type
== TypeManager
.short_type
) {
1780 if (!CheckRange (ec
, v
, target_type
, Int16
.MinValue
, Int16
.MaxValue
))
1782 return new ShortConstant ((short) v
);
1784 if (target_type
== TypeManager
.int32_type
)
1785 return new IntConstant ((int) v
);
1786 if (target_type
== TypeManager
.uint32_type
)
1787 return new UIntConstant ((uint) v
);
1788 if (target_type
== TypeManager
.int64_type
)
1789 return new LongConstant ((long) v
);
1790 if (target_type
== TypeManager
.uint64_type
)
1791 return new ULongConstant ((ulong) v
);
1792 if (target_type
== TypeManager
.float_type
)
1793 return new FloatConstant ((float) v
);
1794 if (target_type
== TypeManager
.double_type
)
1795 return new DoubleConstant ((double) v
);
1796 if (target_type
== TypeManager
.char_type
) {
1797 if (!CheckRange (ec
, v
, target_type
, Char
.MinValue
, Char
.MaxValue
))
1799 return new CharConstant ((char) v
);
1801 if (target_type
== TypeManager
.decimal_type
)
1802 return new DecimalConstant ((decimal) v
);
1808 public override Expression
DoResolve (EmitContext ec
)
1810 expr
= expr
.Resolve (ec
);
1814 TypeExpr target
= target_type
.ResolveAsTypeTerminal (ec
);
1820 CheckObsoleteAttribute (type
);
1822 if (type
.IsAbstract
&& type
.IsSealed
) {
1823 Report
.Error (716, loc
, "Cannot convert to static type '{0}'", TypeManager
.CSharpName (type
));
1827 eclass
= ExprClass
.Value
;
1829 if (expr
is Constant
){
1830 Expression e
= TryReduce (ec
, type
);
1836 if (type
.IsPointer
&& !ec
.InUnsafe
) {
1840 expr
= Convert
.WideningAndNarrowingConversion (ec
, expr
, type
, loc
);
1844 public override void Emit (EmitContext ec
)
1847 // This one will never happen
1849 throw new Exception ("Should not happen");
1854 /// Binary operators
1856 public class Binary
: Expression
{
1857 public enum Operator
: byte {
1862 Addition
, Subtraction
,
1864 LeftShift
, RightShift
,
1865 Equality
, Inequality
, LessThan
, GreaterThan
, LessThanOrEqual
, GreaterThanOrEqual
, Like
, Is
,
1866 BitwiseAnd
, LogicalAndAlso
,
1867 BitwiseOr
, LogicalOrElse
,
1873 Expression left
, right
;
1874 Expression intermediate
;
1876 // This must be kept in sync with Operator!!!
1877 public static readonly string [] oper_names
;
1881 oper_names
= new string [(int) Operator
.TOP
];
1883 oper_names
[(int) Operator
.Multiply
] = "op_Multiply";
1884 oper_names
[(int) Operator
.Division
] = "op_Division";
1885 oper_names
[(int) Operator
.Modulus
] = "op_Modulus";
1886 oper_names
[(int) Operator
.Addition
] = "op_Addition";
1887 oper_names
[(int) Operator
.Subtraction
] = "op_Subtraction";
1888 oper_names
[(int) Operator
.LeftShift
] = "op_LeftShift";
1889 oper_names
[(int) Operator
.RightShift
] = "op_RightShift";
1890 oper_names
[(int) Operator
.LessThan
] = "op_LessThan";
1891 oper_names
[(int) Operator
.GreaterThan
] = "op_GreaterThan";
1892 oper_names
[(int) Operator
.LessThanOrEqual
] = "op_LessThanOrEqual";
1893 oper_names
[(int) Operator
.GreaterThanOrEqual
] = "op_GreaterThanOrEqual";
1894 oper_names
[(int) Operator
.Equality
] = "op_Equality";
1895 oper_names
[(int) Operator
.Inequality
] = "op_Inequality";
1896 oper_names
[(int) Operator
.BitwiseAnd
] = "op_BitwiseAnd";
1897 oper_names
[(int) Operator
.BitwiseOr
] = "op_BitwiseOr";
1898 oper_names
[(int) Operator
.ExclusiveOr
] = "op_ExclusiveOr";
1899 oper_names
[(int) Operator
.LogicalOrElse
] = "op_LogicalOr";
1900 oper_names
[(int) Operator
.LogicalAndAlso
] = "op_LogicalAnd";
1903 public Binary (Operator oper
, Expression left
, Expression right
, Location loc
)
1911 public Operator Oper
{
1920 public Expression Left
{
1929 public Expression Right
{
1940 /// Returns a stringified representation of the Operator
1942 static string OperName (Operator oper
)
1945 case Operator
.Exponentiation
:
1947 case Operator
.Multiply
:
1949 case Operator
.Division
:
1951 case Operator
.IntegerDivision
:
1953 case Operator
.Modulus
:
1955 case Operator
.Addition
:
1957 case Operator
.Subtraction
:
1959 case Operator
.LeftShift
:
1961 case Operator
.RightShift
:
1963 case Operator
.LessThan
:
1965 case Operator
.GreaterThan
:
1967 case Operator
.LessThanOrEqual
:
1969 case Operator
.GreaterThanOrEqual
:
1971 case Operator
.Equality
:
1973 case Operator
.Inequality
:
1977 case Operator
.BitwiseAnd
:
1979 case Operator
.BitwiseOr
:
1981 case Operator
.ExclusiveOr
:
1983 case Operator
.LogicalOrElse
:
1985 case Operator
.LogicalAndAlso
:
1989 return oper
.ToString ();
1992 public override string ToString ()
1994 return "operator " + OperName (oper
) + "(" + left
.ToString () + ", " +
1995 right
.ToString () + ")";
1998 Expression
ForceConversion (EmitContext ec
, Expression expr
, Type target_type
)
2000 if (expr
.Type
== target_type
)
2003 return Convert
.WideningConversion (ec
, expr
, target_type
, loc
);
2006 public static void Error_OperatorAmbiguous (Location loc
, Operator oper
, Type l
, Type r
)
2009 34, loc
, "Operator `" + OperName (oper
)
2010 + "' is ambiguous on operands of type `"
2011 + TypeManager
.CSharpName (l
) + "' "
2012 + "and `" + TypeManager
.CSharpName (r
)
2016 bool IsOfType (EmitContext ec
, Type l
, Type r
, Type t
, bool check_user_conversions
)
2018 if ((l
== t
) || (r
== t
))
2021 if (!check_user_conversions
)
2025 // VB.NET has no notion of User defined conversions
2028 // if (Convert.ImplicitUserConversionExists (ec, l, t))
2030 // else if (Convert.ImplicitUserConversionExists (ec, r, t))
2039 // Note that handling the case l == Decimal || r == Decimal
2040 // is taken care of by the Step 1 Operator Overload resolution.
2042 // If `check_user_conv' is true, we also check whether a user-defined conversion
2043 // exists. Note that we only need to do this if both arguments are of a user-defined
2044 // type, otherwise ConvertImplict() already finds the user-defined conversion for us,
2045 // so we don't explicitly check for performance reasons.
2047 bool DoNumericPromotions (EmitContext ec
, Type l
, Type r
, bool check_user_conv
)
2049 if (IsOfType (ec
, l
, r
, TypeManager
.double_type
, check_user_conv
)){
2051 // If either operand is of type double, the other operand is
2052 // conveted to type double.
2054 if (r
!= TypeManager
.double_type
)
2055 right
= Convert
.WideningConversion (ec
, right
, TypeManager
.double_type
, loc
);
2056 if (l
!= TypeManager
.double_type
)
2057 left
= Convert
.WideningConversion (ec
, left
, TypeManager
.double_type
, loc
);
2059 type
= TypeManager
.double_type
;
2060 } else if (IsOfType (ec
, l
, r
, TypeManager
.float_type
, check_user_conv
)){
2062 // if either operand is of type float, the other operand is
2063 // converted to type float.
2065 if (r
!= TypeManager
.double_type
)
2066 right
= Convert
.WideningConversion (ec
, right
, TypeManager
.float_type
, loc
);
2067 if (l
!= TypeManager
.double_type
)
2068 left
= Convert
.WideningConversion (ec
, left
, TypeManager
.float_type
, loc
);
2069 type
= TypeManager
.float_type
;
2070 } else if (IsOfType (ec
, l
, r
, TypeManager
.uint64_type
, check_user_conv
)){
2074 // If either operand is of type ulong, the other operand is
2075 // converted to type ulong. or an error ocurrs if the other
2076 // operand is of type sbyte, short, int or long
2078 if (l
== TypeManager
.uint64_type
){
2079 if (r
!= TypeManager
.uint64_type
){
2080 if (right
is IntConstant
){
2081 IntConstant ic
= (IntConstant
) right
;
2083 e
= Convert
.TryWideningIntConversion (l
, ic
);
2086 } else if (right
is LongConstant
){
2087 long ll
= ((LongConstant
) right
).Value
;
2090 right
= new ULongConstant ((ulong) ll
);
2092 e
= Convert
.WideningNumericConversion (ec
, right
, l
, loc
);
2099 if (left
is IntConstant
){
2100 e
= Convert
.TryWideningIntConversion (r
, (IntConstant
) left
);
2103 } else if (left
is LongConstant
){
2104 long ll
= ((LongConstant
) left
).Value
;
2107 left
= new ULongConstant ((ulong) ll
);
2109 e
= Convert
.WideningNumericConversion (ec
, left
, r
, loc
);
2116 if ((other
== TypeManager
.sbyte_type
) ||
2117 (other
== TypeManager
.short_type
) ||
2118 (other
== TypeManager
.int32_type
) ||
2119 (other
== TypeManager
.int64_type
))
2120 Error_OperatorAmbiguous (loc
, oper
, l
, r
);
2122 left
= ForceConversion (ec
, left
, TypeManager
.uint64_type
);
2123 right
= ForceConversion (ec
, right
, TypeManager
.uint64_type
);
2125 type
= TypeManager
.uint64_type
;
2126 } else if (IsOfType (ec
, l
, r
, TypeManager
.int64_type
, check_user_conv
)){
2128 // If either operand is of type long, the other operand is converted
2131 if (l
!= TypeManager
.int64_type
)
2132 left
= Convert
.WideningConversion (ec
, left
, TypeManager
.int64_type
, loc
);
2133 if (r
!= TypeManager
.int64_type
)
2134 right
= Convert
.WideningConversion (ec
, right
, TypeManager
.int64_type
, loc
);
2136 type
= TypeManager
.int64_type
;
2137 } else if (IsOfType (ec
, l
, r
, TypeManager
.uint32_type
, check_user_conv
)){
2139 // If either operand is of type uint, and the other
2140 // operand is of type sbyte, short or int, othe operands are
2141 // converted to type long (unless we have an int constant).
2145 if (l
== TypeManager
.uint32_type
){
2146 if (right
is IntConstant
){
2147 IntConstant ic
= (IntConstant
) right
;
2151 right
= new UIntConstant ((uint) val
);
2158 } else if (r
== TypeManager
.uint32_type
){
2159 if (left
is IntConstant
){
2160 IntConstant ic
= (IntConstant
) left
;
2164 left
= new UIntConstant ((uint) val
);
2173 if ((other
== TypeManager
.sbyte_type
) ||
2174 (other
== TypeManager
.short_type
) ||
2175 (other
== TypeManager
.int32_type
)){
2176 left
= ForceConversion (ec
, left
, TypeManager
.int64_type
);
2177 right
= ForceConversion (ec
, right
, TypeManager
.int64_type
);
2178 type
= TypeManager
.int64_type
;
2181 // if either operand is of type uint, the other
2182 // operand is converd to type uint
2184 left
= ForceConversion (ec
, left
, TypeManager
.uint32_type
);
2185 right
= ForceConversion (ec
, right
, TypeManager
.uint32_type
);
2186 type
= TypeManager
.uint32_type
;
2188 } else if (l
== TypeManager
.decimal_type
|| r
== TypeManager
.decimal_type
){
2189 if (l
!= TypeManager
.decimal_type
)
2190 left
= Convert
.WideningConversion (ec
, left
, TypeManager
.decimal_type
, loc
);
2192 if (r
!= TypeManager
.decimal_type
)
2193 right
= Convert
.WideningConversion (ec
, right
, TypeManager
.decimal_type
, loc
);
2194 type
= TypeManager
.decimal_type
;
2196 left
= ForceConversion (ec
, left
, TypeManager
.int32_type
);
2197 right
= ForceConversion (ec
, right
, TypeManager
.int32_type
);
2199 type
= TypeManager
.int32_type
;
2202 return (left
!= null) && (right
!= null);
2205 public void Error_OperatorCannotBeAppliedToObjectOperands ()
2207 Report
.Error (30038, loc
,
2208 "Operator " + OperName (oper
) + " cannot be applied to operands of type `" +
2209 TypeManager
.CSharpName (TypeManager
.object_type
) + "'");
2212 static public void Error_OperatorCannotBeApplied (Location loc
, string name
, Type l
, Type r
)
2214 Report
.Error (19, loc
,
2215 "Operator " + name
+ " cannot be applied to operands of type `" +
2216 TypeManager
.CSharpName (l
) + "' and `" +
2217 TypeManager
.CSharpName (r
) + "'");
2220 void Error_OperatorCannotBeApplied ()
2222 Error_OperatorCannotBeApplied (loc
, OperName (oper
), left
.Type
, right
.Type
);
2225 static bool is_unsigned (Type t
)
2227 return (t
== TypeManager
.uint32_type
|| t
== TypeManager
.uint64_type
||
2228 t
== TypeManager
.short_type
|| t
== TypeManager
.byte_type
);
2231 static bool is_user_defined (Type t
)
2233 if (t
.IsSubclassOf (TypeManager
.value_type
) &&
2234 (!TypeManager
.IsBuiltinType (t
) || t
== TypeManager
.decimal_type
))
2240 Expression
Make32or64 (EmitContext ec
, Expression e
)
2244 if (t
== TypeManager
.int32_type
|| t
== TypeManager
.uint32_type
||
2245 t
== TypeManager
.int64_type
|| t
== TypeManager
.uint64_type
)
2247 Expression ee
= Convert
.WideningConversion (ec
, e
, TypeManager
.int32_type
, loc
);
2250 ee
= Convert
.WideningConversion (ec
, e
, TypeManager
.uint32_type
, loc
);
2253 ee
= Convert
.WideningConversion (ec
, e
, TypeManager
.int64_type
, loc
);
2256 ee
= Convert
.WideningConversion (ec
, e
, TypeManager
.uint64_type
, loc
);
2262 void CheckShiftArguments (EmitContext ec
)
2265 Type assumed_target_type
= right
.Type
;
2267 e
= Convert
.ImplicitVBConversion (ec
, right
, TypeManager
.int32_type
, Location
);
2269 Error_OperatorCannotBeApplied ();
2274 if ( !IsOperatorDefinedForType (left
.Type
)) {
2275 Expression target_left_expr
= ConvertOperandToDefinedType(ec
, left
);
2277 if (target_left_expr
== null) {
2278 Error_OperatorCannotBeApplied();
2282 left
= target_left_expr
;
2283 } else if (left
.Type
== TypeManager
.null_type
)
2284 left
= Convert
.ImplicitVBConversion (ec
, left
, assumed_target_type
, Location
);
2290 if (type
== TypeManager
.byte_type
)
2292 else if (type
== TypeManager
.short_type
)
2294 else if (type
== TypeManager
.int32_type
)
2296 else if (type
== TypeManager
.int64_type
)
2299 throw new Exception ("This should not happen");
2301 right
= new Binary (Binary
.Operator
.BitwiseAnd
, right
, new IntLiteral (mask
), loc
);
2302 right
= right
.DoResolve (ec
);
2305 void CheckIsArguments (EmitContext ec
)
2308 Type r
= right
.Type
;
2309 Type
= TypeManager
.bool_type
;
2311 bool left_is_null
= left
is NullLiteral
;
2312 bool right_is_null
= right
is NullLiteral
;
2314 if (left_is_null
|| right_is_null
)
2317 if (l
.IsValueType
|| r
.IsValueType
) {
2318 Error_OperatorCannotBeApplied ();
2326 if (l
.IsSubclassOf (r
) || r
.IsSubclassOf (l
))
2329 if (!(Convert
.WideningStandardConversionExists (ec
, left
, right
.Type
) ||
2330 Convert
.WideningStandardConversionExists (ec
, right
, left
.Type
))){
2331 Error_OperatorCannotBeApplied ();
2335 if (left
.Type
!= TypeManager
.object_type
)
2336 left
= new EmptyCast (left
, TypeManager
.object_type
);
2337 if (right
.Type
!= TypeManager
.object_type
)
2338 right
= new EmptyCast (right
, TypeManager
.object_type
);
2345 Expression
ResolveOperator (EmitContext ec
)
2348 Type r
= right
.Type
;
2351 // Special cases: string or type parameter comapred to null
2353 if (oper
== Operator
.Equality
|| oper
== Operator
.Inequality
){
2354 if ((!TypeManager
.IsValueType (l
) && r
== TypeManager
.null_type
) ||
2355 (!TypeManager
.IsValueType (r
) && l
== TypeManager
.null_type
)) {
2356 Type
= TypeManager
.bool_type
;
2361 if (l
.IsGenericParameter
&& (right
is NullLiteral
)) {
2362 if (l
.BaseType
== TypeManager
.value_type
) {
2363 Error_OperatorCannotBeApplied ();
2367 left
= new BoxedCast (left
);
2368 Type
= TypeManager
.bool_type
;
2372 if (r
.IsGenericParameter
&& (left
is NullLiteral
)) {
2373 if (r
.BaseType
== TypeManager
.value_type
) {
2374 Error_OperatorCannotBeApplied ();
2378 right
= new BoxedCast (right
);
2379 Type
= TypeManager
.bool_type
;
2384 if (l
== TypeManager
.intptr_type
&& r
== TypeManager
.intptr_type
) {
2385 Type
= TypeManager
.bool_type
;
2392 // Do not perform operator overload resolution when both sides are
2395 if (!(TypeManager
.IsCLRType (l
) && TypeManager
.IsCLRType (r
))){
2397 // Step 1: Perform Operator Overload location
2399 Expression left_expr
, right_expr
;
2401 string op
= oper_names
[(int) oper
];
2403 MethodGroupExpr union
;
2404 left_expr
= MemberLookup (ec
, l
, op
, MemberTypes
.Method
, AllBindingFlags
, loc
);
2406 right_expr
= MemberLookup (
2407 ec
, r
, op
, MemberTypes
.Method
, AllBindingFlags
, loc
);
2408 union
= Invocation
.MakeUnionSet (left_expr
, right_expr
, loc
);
2410 union
= (MethodGroupExpr
) left_expr
;
2412 if (union
!= null) {
2413 ArrayList args
= new ArrayList (2);
2414 args
.Add (new Argument (left
, Argument
.AType
.Expression
));
2415 args
.Add (new Argument (right
, Argument
.AType
.Expression
));
2417 MethodBase method
= Invocation
.OverloadResolve (
2418 ec
, union
, args
, true, Location
.Null
);
2420 if (method
!= null) {
2421 MethodInfo mi
= (MethodInfo
) method
;
2423 return new BinaryMethod (mi
.ReturnType
, method
, args
);
2429 // Step 0: String concatenation (because overloading will get this wrong)
2431 if (oper
== Operator
.Addition
){
2433 // If any of the arguments is a string, cast to string
2436 // Simple constant folding
2437 if (left
is StringConstant
&& right
is StringConstant
)
2438 return new StringConstant (((StringConstant
) left
).Value
+ ((StringConstant
) right
).Value
);
2440 if (l
== TypeManager
.string_type
|| r
== TypeManager
.string_type
) {
2442 if (r
== TypeManager
.void_type
|| l
== TypeManager
.void_type
) {
2443 Error_OperatorCannotBeApplied ();
2447 // try to fold it in on the left
2448 if (left
is StringConcat
) {
2451 // We have to test here for not-null, since we can be doubly-resolved
2452 // take care of not appending twice
2455 type
= TypeManager
.string_type
;
2456 ((StringConcat
) left
).Append (ec
, right
);
2457 return left
.Resolve (ec
);
2463 // Otherwise, start a new concat expression
2464 return new StringConcat (ec
, loc
, left
, right
).Resolve (ec
);
2468 // Transform a + ( - b) into a - b
2470 if (right
is Unary
){
2471 Unary right_unary
= (Unary
) right
;
2473 if (right_unary
.Oper
== Unary
.Operator
.UnaryNegation
){
2474 oper
= Operator
.Subtraction
;
2475 right
= right_unary
.Expr
;
2481 if (oper
== Operator
.Equality
|| oper
== Operator
.Inequality
){
2482 if (l
== TypeManager
.bool_type
|| r
== TypeManager
.bool_type
){
2483 if (r
!= TypeManager
.bool_type
|| l
!= TypeManager
.bool_type
){
2484 Error_OperatorCannotBeApplied ();
2488 type
= TypeManager
.bool_type
;
2492 bool left_is_null
= left
is NullLiteral
;
2493 bool right_is_null
= right
is NullLiteral
;
2494 if (left_is_null
|| right_is_null
) {
2495 if (oper
== Operator
.Equality
)
2496 return new BoolLiteral (left_is_null
== right_is_null
);
2498 return new BoolLiteral (left_is_null
!= right_is_null
);
2502 // operator != (object a, object b)
2503 // operator == (object a, object b)
2505 // For this to be used, both arguments have to be reference-types.
2506 // Read the rationale on the spec (14.9.6)
2508 // Also, if at compile time we know that the classes do not inherit
2509 // one from the other, then we catch the error there.
2511 if (!(l
.IsValueType
|| r
.IsValueType
)){
2512 type
= TypeManager
.bool_type
;
2517 if (l
.IsSubclassOf (r
) || r
.IsSubclassOf (l
))
2521 // Also, a standard conversion must exist from either one
2523 if (!(Convert
.WideningStandardConversionExists (ec
, left
, r
) ||
2524 Convert
.WideningStandardConversionExists (ec
, right
, l
))){
2525 Error_OperatorCannotBeApplied ();
2529 // We are going to have to convert to an object to compare
2531 if (l
!= TypeManager
.object_type
)
2532 left
= new EmptyCast (left
, TypeManager
.object_type
);
2533 if (r
!= TypeManager
.object_type
)
2534 right
= new EmptyCast (right
, TypeManager
.object_type
);
2537 // FIXME: CSC here catches errors cs254 and cs252
2543 // One of them is a valuetype, but the other one is not.
2545 if (!l
.IsValueType
|| !r
.IsValueType
) {
2546 Error_OperatorCannotBeApplied ();
2551 // Only perform numeric promotions on:
2552 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2554 if (oper
== Operator
.Addition
|| oper
== Operator
.Subtraction
) {
2555 if (TypeManager
.IsDelegateType (l
)){
2556 if (((right
.eclass
== ExprClass
.MethodGroup
) ||
2557 (r
== TypeManager
.anonymous_method_type
))){
2558 if ((RootContext
.Version
!= LanguageVersion
.ISO_1
)){
2559 Expression tmp
= Convert
.WideningConversionRequired (ec
, right
, l
, loc
);
2567 if (TypeManager
.IsDelegateType (r
)){
2569 ArrayList args
= new ArrayList (2);
2571 args
= new ArrayList (2);
2572 args
.Add (new Argument (left
, Argument
.AType
.Expression
));
2573 args
.Add (new Argument (right
, Argument
.AType
.Expression
));
2575 if (oper
== Operator
.Addition
)
2576 method
= TypeManager
.delegate_combine_delegate_delegate
;
2578 method
= TypeManager
.delegate_remove_delegate_delegate
;
2580 if (!TypeManager
.IsEqual (l
, r
)) {
2581 Error_OperatorCannotBeApplied ();
2585 return new BinaryDelegate (l
, method
, args
);
2590 // Pointer arithmetic:
2592 // T* operator + (T* x, int y);
2593 // T* operator + (T* x, uint y);
2594 // T* operator + (T* x, long y);
2595 // T* operator + (T* x, ulong y);
2597 // T* operator + (int y, T* x);
2598 // T* operator + (uint y, T *x);
2599 // T* operator + (long y, T *x);
2600 // T* operator + (ulong y, T *x);
2602 // T* operator - (T* x, int y);
2603 // T* operator - (T* x, uint y);
2604 // T* operator - (T* x, long y);
2605 // T* operator - (T* x, ulong y);
2607 // long operator - (T* x, T *y)
2610 if (r
.IsPointer
&& oper
== Operator
.Subtraction
){
2612 return new PointerArithmetic (
2613 false, left
, right
, TypeManager
.int64_type
,
2616 Expression t
= Make32or64 (ec
, right
);
2618 return new PointerArithmetic (oper
== Operator
.Addition
, left
, t
, l
, loc
).Resolve (ec
);
2620 } else if (r
.IsPointer
&& oper
== Operator
.Addition
){
2621 Expression t
= Make32or64 (ec
, left
);
2623 return new PointerArithmetic (true, right
, t
, r
, loc
).Resolve (ec
);
2628 // Enumeration operators
2630 bool lie
= TypeManager
.IsEnumType (l
);
2631 bool rie
= TypeManager
.IsEnumType (r
);
2635 // U operator - (E e, E f)
2637 if (oper
== Operator
.Subtraction
){
2639 type
= TypeManager
.EnumToUnderlying (l
);
2642 Error_OperatorCannotBeApplied ();
2648 // operator + (E e, U x)
2649 // operator - (E e, U x)
2651 if (oper
== Operator
.Addition
|| oper
== Operator
.Subtraction
){
2652 Type enum_type
= lie
? l
: r
;
2653 Type other_type
= lie
? r
: l
;
2654 Type underlying_type
= TypeManager
.EnumToUnderlying (enum_type
);
2656 if (underlying_type
!= other_type
){
2657 temp
= Convert
.WideningConversion (ec
, lie
? right
: left
, underlying_type
, loc
);
2667 Error_OperatorCannotBeApplied ();
2676 temp
= Convert
.WideningConversion (ec
, right
, l
, loc
);
2680 Error_OperatorCannotBeApplied ();
2684 temp
= Convert
.WideningConversion (ec
, left
, r
, loc
);
2689 Error_OperatorCannotBeApplied ();
2694 if (oper
== Operator
.Equality
|| oper
== Operator
.Inequality
||
2695 oper
== Operator
.LessThanOrEqual
|| oper
== Operator
.LessThan
||
2696 oper
== Operator
.GreaterThanOrEqual
|| oper
== Operator
.GreaterThan
){
2697 if (left
.Type
!= right
.Type
){
2698 Error_OperatorCannotBeApplied ();
2701 type
= TypeManager
.bool_type
;
2705 if (oper
== Operator
.BitwiseAnd
||
2706 oper
== Operator
.BitwiseOr
||
2707 oper
== Operator
.ExclusiveOr
){
2711 Error_OperatorCannotBeApplied ();
2715 if (oper
== Operator
.LeftShift
|| oper
== Operator
.RightShift
)
2716 return CheckShiftArguments (ec
);
2718 if (oper
== Operator
.LogicalOrElse
|| oper
== Operator
.LogicalAndAlso
){
2719 if (l
== TypeManager
.bool_type
&& r
== TypeManager
.bool_type
) {
2720 type
= TypeManager
.bool_type
;
2725 Error_OperatorCannotBeApplied ();
2729 Expression e
= new ConditionalLogicalOperator (
2730 oper
== Operator
.LogicalAndAlso
, left
, right
, l
, loc
);
2731 return e
.Resolve (ec
);
2735 // operator & (bool x, bool y)
2736 // operator | (bool x, bool y)
2737 // operator ^ (bool x, bool y)
2739 if (l
== TypeManager
.bool_type
&& r
== TypeManager
.bool_type
){
2740 if (oper
== Operator
.BitwiseAnd
||
2741 oper
== Operator
.BitwiseOr
||
2742 oper
== Operator
.ExclusiveOr
){
2749 // Pointer comparison
2751 if (l
.IsPointer
&& r
.IsPointer
){
2752 if (oper
== Operator
.Equality
|| oper
== Operator
.Inequality
||
2753 oper
== Operator
.LessThan
|| oper
== Operator
.LessThanOrEqual
||
2754 oper
== Operator
.GreaterThan
|| oper
== Operator
.GreaterThanOrEqual
){
2755 type
= TypeManager
.bool_type
;
2761 // This will leave left or right set to null if there is an error
2763 bool check_user_conv
= is_user_defined (l
) && is_user_defined (r
);
2764 DoNumericPromotions (ec
, l
, r
, check_user_conv
);
2765 if (left
== null || right
== null){
2766 Error_OperatorCannotBeApplied (loc
, OperName (oper
), l
, r
);
2771 // reload our cached types if required
2776 if (oper
== Operator
.BitwiseAnd
||
2777 oper
== Operator
.BitwiseOr
||
2778 oper
== Operator
.ExclusiveOr
){
2780 if (((l
== TypeManager
.int32_type
) ||
2781 (l
== TypeManager
.uint32_type
) ||
2782 (l
== TypeManager
.short_type
) ||
2783 (l
== TypeManager
.ushort_type
) ||
2784 (l
== TypeManager
.int64_type
) ||
2785 (l
== TypeManager
.uint64_type
))){
2788 Error_OperatorCannotBeApplied ();
2792 Error_OperatorCannotBeApplied ();
2797 if (oper
== Operator
.Equality
||
2798 oper
== Operator
.Inequality
||
2799 oper
== Operator
.LessThanOrEqual
||
2800 oper
== Operator
.LessThan
||
2801 oper
== Operator
.GreaterThanOrEqual
||
2802 oper
== Operator
.GreaterThan
){
2803 type
= TypeManager
.bool_type
;
2810 public override Expression
DoResolve (EmitContext ec
)
2812 if ((oper
== Operator
.Subtraction
) && (left
is ParenthesizedExpression
)) {
2813 left
= ((ParenthesizedExpression
) left
).Expr
;
2814 left
= left
.Resolve (ec
, ResolveFlags
.VariableOrValue
| ResolveFlags
.Type
);
2818 if (left
.eclass
== ExprClass
.Type
) {
2819 Error (75, "Casting a negative value needs to have the value in parentheses.");
2823 left
= left
.Resolve (ec
);
2828 Constant lc
= left
as Constant
;
2829 if (lc
!= null && lc
.Type
== TypeManager
.bool_type
&&
2830 ((oper
== Operator
.LogicalAndAlso
&& (bool)lc
.GetValue () == false) ||
2831 (oper
== Operator
.LogicalOrElse
&& (bool)lc
.GetValue () == true))) {
2833 // TODO: make a sense to resolve unreachable expression as we do for statement
2834 Report
.Warning (429, 4, loc
, "Unreachable expression code detected");
2838 right
= right
.Resolve (ec
);
2842 eclass
= ExprClass
.Value
;
2844 Constant rc
= right
as Constant
;
2845 if (rc
!= null & lc
!= null){
2846 Expression e
= ConstantFold
.BinaryFold (
2847 ec
, oper
, lc
, rc
, loc
);
2852 if (TypeManager
.IsNullableType (left
.Type
) || TypeManager
.IsNullableType (right
.Type
))
2853 return new Nullable
.LiftedBinaryOperator (oper
, left
, right
, loc
).Resolve (ec
);
2855 return ResolveVisualBasicOperator (ec
);
2859 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2860 /// context of a conditional bool expression. This function will return
2861 /// false if it is was possible to use EmitBranchable, or true if it was.
2863 /// The expression's code is generated, and we will generate a branch to `target'
2864 /// if the resulting expression value is equal to isTrue
2866 public override void EmitBranchable (EmitContext ec
, Label target
, bool onTrue
)
2868 ILGenerator ig
= ec
.ig
;
2871 // This is more complicated than it looks, but its just to avoid
2872 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2873 // but on top of that we want for == and != to use a special path
2874 // if we are comparing against null
2876 if ((oper
== Operator
.Equality
|| oper
== Operator
.Inequality
) && (left
is Constant
|| right
is Constant
)) {
2877 bool my_on_true
= oper
== Operator
.Inequality
? onTrue
: !onTrue
;
2880 // put the constant on the rhs, for simplicity
2882 if (left
is Constant
) {
2883 Expression swap
= right
;
2888 if (((Constant
) right
).IsZeroInteger
) {
2891 ig
.Emit (OpCodes
.Brtrue
, target
);
2893 ig
.Emit (OpCodes
.Brfalse
, target
);
2896 } else if (right
is BoolConstant
){
2898 if (my_on_true
!= ((BoolConstant
) right
).Value
)
2899 ig
.Emit (OpCodes
.Brtrue
, target
);
2901 ig
.Emit (OpCodes
.Brfalse
, target
);
2906 } else if (oper
== Operator
.LogicalAndAlso
) {
2909 Label tests_end
= ig
.DefineLabel ();
2911 left
.EmitBranchable (ec
, tests_end
, false);
2912 right
.EmitBranchable (ec
, target
, true);
2913 ig
.MarkLabel (tests_end
);
2915 left
.EmitBranchable (ec
, target
, false);
2916 right
.EmitBranchable (ec
, target
, false);
2921 } else if (oper
== Operator
.LogicalOrElse
){
2923 left
.EmitBranchable (ec
, target
, true);
2924 right
.EmitBranchable (ec
, target
, true);
2927 Label tests_end
= ig
.DefineLabel ();
2928 left
.EmitBranchable (ec
, tests_end
, true);
2929 right
.EmitBranchable (ec
, target
, false);
2930 ig
.MarkLabel (tests_end
);
2935 } else if (!(oper
== Operator
.LessThan
|| oper
== Operator
.GreaterThan
||
2936 oper
== Operator
.LessThanOrEqual
|| oper
== Operator
.GreaterThanOrEqual
||
2937 oper
== Operator
.Equality
|| oper
== Operator
.Inequality
)) {
2938 base.EmitBranchable (ec
, target
, onTrue
);
2946 bool isUnsigned
= is_unsigned (t
) || t
== TypeManager
.double_type
|| t
== TypeManager
.float_type
;
2949 case Operator
.Equality
:
2951 ig
.Emit (OpCodes
.Beq
, target
);
2953 ig
.Emit (OpCodes
.Bne_Un
, target
);
2956 case Operator
.Inequality
:
2958 ig
.Emit (OpCodes
.Bne_Un
, target
);
2960 ig
.Emit (OpCodes
.Beq
, target
);
2963 case Operator
.LessThan
:
2966 ig
.Emit (OpCodes
.Blt_Un
, target
);
2968 ig
.Emit (OpCodes
.Blt
, target
);
2971 ig
.Emit (OpCodes
.Bge_Un
, target
);
2973 ig
.Emit (OpCodes
.Bge
, target
);
2976 case Operator
.GreaterThan
:
2979 ig
.Emit (OpCodes
.Bgt_Un
, target
);
2981 ig
.Emit (OpCodes
.Bgt
, target
);
2984 ig
.Emit (OpCodes
.Ble_Un
, target
);
2986 ig
.Emit (OpCodes
.Ble
, target
);
2989 case Operator
.LessThanOrEqual
:
2992 ig
.Emit (OpCodes
.Ble_Un
, target
);
2994 ig
.Emit (OpCodes
.Ble
, target
);
2997 ig
.Emit (OpCodes
.Bgt_Un
, target
);
2999 ig
.Emit (OpCodes
.Bgt
, target
);
3003 case Operator
.GreaterThanOrEqual
:
3006 ig
.Emit (OpCodes
.Bge_Un
, target
);
3008 ig
.Emit (OpCodes
.Bge
, target
);
3011 ig
.Emit (OpCodes
.Blt_Un
, target
);
3013 ig
.Emit (OpCodes
.Blt
, target
);
3016 Console
.WriteLine (oper
);
3017 throw new Exception ("what is THAT");
3021 public override void Emit (EmitContext ec
)
3023 ILGenerator ig
= ec
.ig
;
3026 OpCode opcode1
= OpCodes
.Nop
;
3029 // Handle short-circuit operators differently
3032 if (oper
== Operator
.LogicalAndAlso
) {
3033 Label load_zero
= ig
.DefineLabel ();
3034 Label end
= ig
.DefineLabel ();
3036 left
.EmitBranchable (ec
, load_zero
, false);
3038 ig
.Emit (OpCodes
.Br
, end
);
3040 ig
.MarkLabel (load_zero
);
3041 ig
.Emit (OpCodes
.Ldc_I4_0
);
3044 } else if (oper
== Operator
.LogicalOrElse
) {
3045 Label load_one
= ig
.DefineLabel ();
3046 Label end
= ig
.DefineLabel ();
3048 left
.EmitBranchable (ec
, load_one
, true);
3050 ig
.Emit (OpCodes
.Br
, end
);
3052 ig
.MarkLabel (load_one
);
3053 ig
.Emit (OpCodes
.Ldc_I4_1
);
3058 if (intermediate
!= null) {
3059 intermediate
.Emit (ec
);
3060 ig
.Emit (OpCodes
.Ldc_I4_0
);
3067 bool is_int32_or_int64_type
= (Type
== TypeManager
.int32_type
) || (Type
== TypeManager
.int64_type
);
3070 case Operator
.Multiply
:
3072 if (is_int32_or_int64_type
)
3073 opcode
= OpCodes
.Mul_Ovf
;
3075 opcode
= OpCodes
.Mul
;
3077 opcode
= OpCodes
.Mul
;
3081 case Operator
.Division
:
3082 case Operator
.IntegerDivision
:
3083 opcode
= OpCodes
.Div
;
3086 case Operator
.Modulus
:
3087 opcode
= OpCodes
.Rem
;
3090 case Operator
.Addition
:
3092 if (is_int32_or_int64_type
)
3093 opcode
= OpCodes
.Add_Ovf
;
3095 opcode
= OpCodes
.Add
;
3097 opcode
= OpCodes
.Add
;
3100 case Operator
.Subtraction
:
3102 if (is_int32_or_int64_type
)
3103 opcode
= OpCodes
.Sub_Ovf
;
3105 opcode
= OpCodes
.Sub
;
3107 opcode
= OpCodes
.Sub
;
3110 case Operator
.RightShift
:
3111 opcode
= OpCodes
.Shr
;
3114 case Operator
.LeftShift
:
3115 opcode
= OpCodes
.Shl
;
3119 case Operator
.Equality
:
3120 opcode
= OpCodes
.Ceq
;
3123 case Operator
.Inequality
:
3124 ig
.Emit (OpCodes
.Ceq
);
3125 ig
.Emit (OpCodes
.Ldc_I4_0
);
3127 opcode
= OpCodes
.Ceq
;
3130 case Operator
.LessThan
:
3131 opcode
= OpCodes
.Clt
;
3134 case Operator
.GreaterThan
:
3135 opcode
= OpCodes
.Cgt
;
3138 case Operator
.LessThanOrEqual
:
3139 ig
.Emit (OpCodes
.Cgt
);
3140 ig
.Emit (OpCodes
.Ldc_I4_0
);
3142 opcode
= OpCodes
.Ceq
;
3145 case Operator
.GreaterThanOrEqual
:
3146 ig
.Emit (OpCodes
.Clt
);
3147 ig
.Emit (OpCodes
.Ldc_I4_0
);
3149 opcode
= OpCodes
.Ceq
;
3152 case Operator
.BitwiseOr
:
3153 opcode
= OpCodes
.Or
;
3156 case Operator
.BitwiseAnd
:
3157 opcode
= OpCodes
.And
;
3160 case Operator
.ExclusiveOr
:
3161 opcode
= OpCodes
.Xor
;
3165 throw new Exception ("This should not happen: Operator = "
3166 + oper
.ToString ());
3171 if (!IsArithmeticExpression
&& !IsShiftExpression
)
3174 if (type
== TypeManager
.byte_type
)
3175 ig
.Emit (ec
.CheckState
&& ! IsShiftExpression
? OpCodes
.Conv_Ovf_U1
: OpCodes
.Conv_U1
);
3177 if (type
== TypeManager
.short_type
)
3178 ig
.Emit (ec
.CheckState
&& ! IsShiftExpression
? OpCodes
.Conv_Ovf_I2
: OpCodes
.Conv_I2
);
3181 Expression
ResolveVisualBasicOperator (EmitContext ec
)
3184 Expression ret_expr
;
3187 Type r
= right
.Type
;
3189 //Console.WriteLine (OperName (oper) +"< "+ l + ", " + r + ">");
3191 errors
= Report
.Errors
;
3192 ret_expr
= HandleObjectOperands (ec
);
3193 if (Report
.Errors
> errors
)
3195 if (ret_expr
!= null)
3198 errors
= Report
.Errors
;
3199 CheckArguments (ec
);
3200 if (Report
.Errors
> errors
)
3203 if (oper
== Operator
.Exponentiation
)
3204 return new HelperMethodInvocation (ec
, Location
, TypeManager
.double_type
,
3205 TypeManager
.math_pow_double_double
, left
, right
);
3207 if (type
== TypeManager
.decimal_type
) {
3208 MethodInfo helper_method
= null;
3210 case Operator
.Addition
:
3211 helper_method
= TypeManager
.decimal_add_decimal_decimal
;
3213 case Operator
.Subtraction
:
3214 helper_method
= TypeManager
.decimal_subtract_decimal_decimal
;
3216 case Operator
.Multiply
:
3217 helper_method
= TypeManager
.decimal_multiply_decimal_decimal
;
3219 case Operator
.Division
:
3220 helper_method
= TypeManager
.decimal_divide_decimal_decimal
;
3222 case Operator
.Modulus
:
3223 helper_method
= TypeManager
.decimal_remainder_decimal_decimal
;
3227 return new HelperMethodInvocation (ec
, Location
, TypeManager
.decimal_type
,
3228 helper_method
, left
, right
);
3231 if (IsRelationalExpression
) {
3232 Type
= TypeManager
.bool_type
;
3233 if (left
.Type
== TypeManager
.string_type
) {
3234 Expression is_text_mode
;
3236 is_text_mode
= new BoolConstant (RootContext
.StringComparisonMode
== CompareMethod
.Text
);
3237 intermediate
= new HelperMethodInvocation (ec
, Location
, TypeManager
.int32_type
,
3238 TypeManager
.msvbcs_stringtype_strcmp_string_string_boolean
,
3239 left
, right
, is_text_mode
);
3242 if (left
.Type
== TypeManager
.decimal_type
) {
3243 intermediate
= new HelperMethodInvocation (ec
, Location
, TypeManager
.int32_type
,
3244 TypeManager
.decimal_compare_decimal_decimal
, left
, right
);
3247 if (left
.Type
== TypeManager
.date_type
) {
3248 intermediate
= new HelperMethodInvocation (ec
, Location
, TypeManager
.int32_type
,
3249 TypeManager
.datetime_compare_datetime_datetime
, left
, right
);
3254 if (IsShiftExpression
)
3257 if (IsShortCircuitedLogicalExpression
)
3260 if (oper
== Operator
.Like
) {
3261 Type
= TypeManager
.bool_type
;
3262 Expression compare_mode
= new EnumConstant (new IntConstant ((int) RootContext
.StringComparisonMode
),
3263 typeof (Microsoft
.VisualBasic
.CompareMethod
));
3264 return new HelperMethodInvocation (ec
, Location
, TypeManager
.bool_type
, TypeManager
.msvbcs_stringtype_strlike_string_string_comparemethod
, left
, right
, compare_mode
);
3269 // Step 0: String concatenation (because overloading will get this wrong)
3271 if (oper
== Operator
.Addition
|| oper
== Operator
.Concatenation
){
3274 // If any of the arguments is a string, cast to string
3277 // Simple constant folding
3278 if (left
is StringConstant
&& right
is StringConstant
)
3279 return new StringConstant (((StringConstant
) left
).Value
+ ((StringConstant
) right
).Value
);
3281 if (Type
== TypeManager
.string_type
) {
3283 // try to fold it in on the left
3284 if (left
is StringConcat
) {
3287 // We have to test here for not-null, since we can be doubly-resolved
3288 // take care of not appending twice
3291 type
= TypeManager
.string_type
;
3292 ((StringConcat
) left
).Append (ec
, right
);
3293 return left
.Resolve (ec
);
3299 // Otherwise, start a new concat expression
3300 return new StringConcat (ec
, loc
, left
, right
).Resolve (ec
);
3304 // Transform a + ( - b) into a - b
3306 if (right
is Unary
){
3307 Unary right_unary
= (Unary
) right
;
3309 if (right_unary
.Oper
== Unary
.Operator
.UnaryNegation
){
3310 oper
= Operator
.Subtraction
;
3311 right
= right_unary
.Expr
;
3320 Expression
HandleObjectOperands (EmitContext ec
)
3323 Type r
= right
.Type
;
3325 Expression target_left_expr
= left
;
3326 Expression target_right_expr
= right
;
3328 if (IsShortCircuitedLogicalExpression
|| IsExpression
)
3331 if (l
!= TypeManager
.object_type
&& r
!= TypeManager
.object_type
)
3334 if (RootContext
.StricterTypeChecking
)
3335 if (oper
!= Operator
.Equality
&&
3336 oper
!= Operator
.Inequality
&& oper
!= Operator
.Is
) {
3337 Error_OperatorCannotBeAppliedToObjectOperands ();
3341 if (l
!= TypeManager
.object_type
&& ! IsOperatorDefinedForType (l
) && ConvertOperandToDefinedType(ec
, target_left_expr
) == null) {
3342 Error_OperatorCannotBeApplied ();
3345 if (!IsShiftExpression
&& r
!= TypeManager
.object_type
&& ! IsOperatorDefinedForType (r
) && ConvertOperandToDefinedType(ec
, target_right_expr
) == null) {
3346 Error_OperatorCannotBeApplied ();
3350 if (l
!= TypeManager
.object_type
)
3351 left
= Convert
.ImplicitVBConversionRequired (ec
, left
, TypeManager
.object_type
, Location
);
3353 if (IsShiftExpression
) {
3354 if (r
!= TypeManager
.int32_type
) {
3355 target_right_expr
= Convert
.ImplicitVBConversionRequired (ec
, right
, TypeManager
.int32_type
, Location
);
3356 if (target_right_expr
== null) {
3357 Error_OperatorCannotBeApplied ();
3360 right
= target_right_expr
;
3363 } else if (r
!= TypeManager
.object_type
) {
3364 right
= Convert
.ImplicitVBConversionRequired (ec
, right
, TypeManager
.object_type
, Location
);
3368 Type
= TypeManager
.object_type
;
3369 if (IsRelationalExpression
) {
3370 Type
= TypeManager
.bool_type
;
3371 Expression is_text_mode
= new BoolConstant (RootContext
.StringComparisonMode
== CompareMethod
.Text
);
3372 intermediate
= new HelperMethodInvocation (ec
, Location
, TypeManager
.int32_type
, HelperMethod
, left
, right
, is_text_mode
);
3376 if (oper
== Operator
.Like
) {
3377 Type
= TypeManager
.bool_type
;
3378 Expression compare_mode
= new EnumConstant (new IntConstant ((int) RootContext
.StringComparisonMode
),
3379 typeof (Microsoft
.VisualBasic
.CompareMethod
));
3380 return new HelperMethodInvocation (ec
, Location
, TypeManager
.bool_type
, HelperMethod
, left
, right
, compare_mode
);
3383 if (IsShiftExpression
)
3384 return new HelperMethodInvocation (ec
, Location
, TypeManager
.object_type
, HelperMethod
, left
, right
);
3386 return new HelperMethodInvocation (ec
, Location
, TypeManager
.object_type
, HelperMethod
, left
, right
);
3389 void CheckArguments (EmitContext ec
)
3394 Type r
= right
.Type
;
3396 Expression target_left_expr
= left
;
3397 Expression target_right_expr
= right
;
3399 Type target_left_expr_type
= target_left_expr
.Type
;
3400 Type target_right_expr_type
= target_right_expr
.Type
;
3403 if (IsShiftExpression
) {
3404 CheckShiftArguments (ec
);
3409 CheckIsArguments (ec
);
3417 throw new Exception ("FIXME: An Infinite loop when resolving <" + l
+ "> " + OperName (oper
) + " <" + r
+ ">");
3419 //Console.WriteLine (" STEP " + step + ":");
3420 //Console.WriteLine (" " + "<" + target_left_expr_type + ", " + target_right_expr_type + ">");
3422 if ((target_left_expr_type
== target_right_expr_type
) &&
3423 IsOperatorDefinedForType (target_left_expr_type
)) {
3425 if (target_left_expr_type
== TypeManager
.null_type
) {
3426 target_left_expr
= target_right_expr
= new IntConstant (0);
3427 Type
= TypeManager
.int32_type
;
3430 left
= target_left_expr
;
3431 right
= target_right_expr
;
3432 type
= target_left_expr_type
;
3437 if ( !IsOperatorDefinedForType (target_left_expr_type
)) {
3438 target_left_expr
= ConvertOperandToDefinedType(ec
, target_left_expr
);
3440 if (target_left_expr
== null) {
3441 Error_OperatorCannotBeApplied();
3445 target_left_expr_type
= target_left_expr
.Type
;
3449 if ( !IsOperatorDefinedForType(target_right_expr_type
)) {
3450 target_right_expr
= ConvertOperandToDefinedType(ec
, target_right_expr
);
3452 if(target_right_expr
== null) {
3453 Error_OperatorCannotBeApplied();
3457 target_right_expr_type
= target_right_expr
.Type
;
3461 if (target_left_expr_type
== TypeManager
.null_type
||
3462 target_right_expr_type
== TypeManager
.null_type
)
3465 if (target_left_expr_type
== TypeManager
.string_type
) {
3467 if (target_right_expr_type
== TypeManager
.date_type
)
3468 target_type
= TypeManager
.date_type
;
3469 else if (target_right_expr_type
== TypeManager
.bool_type
)
3470 target_type
= TypeManager
.bool_type
;
3472 target_type
= TypeManager
.double_type
;
3474 if (l
== target_type
)
3475 target_left_expr
= left
;
3477 target_left_expr
= Convert
.ImplicitVBConversionRequired (ec
, left
, target_type
, Location
);
3479 if (target_left_expr
== null) {
3480 Error_OperatorCannotBeApplied();
3484 target_left_expr_type
= target_left_expr
.Type
;
3488 if (target_right_expr_type
== TypeManager
.string_type
) {
3490 if (target_left_expr_type
== TypeManager
.date_type
)
3491 target_type
= TypeManager
.date_type
;
3492 else if (target_left_expr_type
== TypeManager
.bool_type
)
3493 target_type
= TypeManager
.bool_type
;
3495 target_type
= TypeManager
.double_type
;
3497 if (r
== target_type
)
3498 target_right_expr
= right
;
3500 target_right_expr
= Convert
.ImplicitVBConversionRequired (ec
, right
, target_type
, Location
);
3502 if (target_right_expr
== null) {
3503 Error_OperatorCannotBeApplied();
3507 target_right_expr_type
= target_right_expr
.Type
;
3514 if ( !DoOperandPromotions(ec
, target_left_expr
, target_right_expr
))
3515 Error_OperatorCannotBeApplied();
3520 bool IsOperatorDefinedForType (Type t
)
3522 if (t
== TypeManager
.null_type
)
3527 case Operator
.Exponentiation
:
3528 if (t
== TypeManager
.double_type
)
3532 case Operator
.Concatenation
:
3534 if (t
== TypeManager
.string_type
)
3539 case Operator
.BitwiseAnd
:
3540 case Operator
.BitwiseOr
:
3541 case Operator
.ExclusiveOr
:
3542 if (t
== TypeManager
.bool_type
||
3543 TypeManager
.IsFixedNumericType (t
))
3548 case Operator
.LogicalAndAlso
:
3549 case Operator
.LogicalOrElse
:
3550 if (t
== TypeManager
.bool_type
)
3554 case Operator
.RightShift
:
3555 case Operator
.LeftShift
:
3557 if (TypeManager
.IsFixedNumericType (t
))
3562 case Operator
.Equality
:
3563 case Operator
.Inequality
:
3564 case Operator
.LessThan
:
3565 case Operator
.LessThanOrEqual
:
3566 case Operator
.GreaterThan
:
3567 case Operator
.GreaterThanOrEqual
:
3568 if (t
== TypeManager
.bool_type
||
3569 t
== TypeManager
.date_type
||
3570 t
== TypeManager
.char_type
||
3571 t
== TypeManager
.string_type
||
3572 TypeManager
.IsNumericType (t
))
3577 case Operator
.Addition
:
3578 if (t
== TypeManager
.string_type
||
3579 TypeManager
.IsNumericType (t
))
3583 case Operator
.Subtraction
:
3584 case Operator
.Multiply
:
3585 case Operator
.Division
:
3586 case Operator
.Modulus
:
3587 if (TypeManager
.IsNumericType (t
))
3591 case Operator
.IntegerDivision
:
3592 if (TypeManager
.IsFixedNumericType (t
))
3602 Expression
ConvertOperandToDefinedType (EmitContext ec
, Expression expr
)
3604 Type target_type
= null;
3605 Type operand_type
= expr
.Type
;
3607 if (IsOperatorDefinedForType (operand_type
))
3611 case Operator
.Addition
:
3612 case Operator
.Subtraction
:
3613 case Operator
.Multiply
:
3614 if (operand_type
== TypeManager
.bool_type
)
3615 target_type
= TypeManager
.short_type
;
3617 if (operand_type
== TypeManager
.char_type
)
3618 target_type
= TypeManager
.string_type
;
3620 if (operand_type
== TypeManager
.date_type
)
3621 target_type
= TypeManager
.string_type
;
3626 case Operator
.Concatenation
:
3627 return Convert
.ExplicitVBConversion(ec
, expr
, TypeManager
.string_type
, expr
.Location
);
3630 case Operator
.LogicalAndAlso
:
3631 case Operator
.LogicalOrElse
:
3632 return Convert
.ExplicitVBConversion(ec
, expr
, TypeManager
.bool_type
, expr
.Location
);
3635 case Operator
.Exponentiation
:
3636 return Convert
.ExplicitVBConversion(ec
, expr
, TypeManager
.double_type
, expr
.Location
);
3641 if (target_type
!= null)
3642 return Convert
.ImplicitVBConversion(ec
, expr
, target_type
, expr
.Location
);
3647 static Type
GetWiderOfTypes (Type t1
, Type t2
)
3649 // char array and Nothing should be handled here ?
3655 if(t1
== TypeManager
.null_type
)
3658 if (t2
== TypeManager
.null_type
)
3661 if (t1
== TypeManager
.date_type
|| t1
== TypeManager
.char_type
) {
3662 if (t2
== TypeManager
.string_type
)
3668 if (t2
== TypeManager
.date_type
|| t2
== TypeManager
.char_type
) {
3669 if (t1
== TypeManager
.string_type
)
3675 object order1
= TypeManager
.relative_type_order
[t1
];
3679 object order2
= TypeManager
.relative_type_order
[t2
];
3684 if ((int) order1
> (int) order2
)
3691 bool DoOperandPromotions (EmitContext ec
, Expression target_left_expr
, Expression target_right_expr
)
3693 Type l
= target_left_expr
.Type
;
3694 Type r
= target_right_expr
.Type
;
3696 Type target_type
= GetWiderOfTypes(l
, r
);
3698 //Console.WriteLine (" DoingOperandPromotions");
3699 //Console.WriteLine (" left => " + l + " right => " + r);
3700 //Console.WriteLine (" target_type => " + target_type);
3702 if (target_type
== null) {
3703 throw new Exception ("Types " + l
+ " " + r
+" cannot be compared");
3706 if (r
!= target_type
) {
3707 target_right_expr
= Convert
.ImplicitVBConversion (ec
, target_right_expr
, target_type
, Location
);
3709 if (target_right_expr
== null)
3714 if (l
!= target_type
) {
3715 target_left_expr
= Convert
.ImplicitVBConversion (ec
, target_left_expr
, target_type
, Location
);
3717 if (target_left_expr
== null)
3721 left
= target_left_expr
;
3722 right
= target_right_expr
;
3727 bool IsArithmeticExpression
{
3729 if (oper
== Operator
.Addition
|| oper
== Operator
.Subtraction
||
3730 oper
== Operator
.Multiply
|| oper
== Operator
.Division
||
3731 oper
== Operator
.IntegerDivision
|| oper
== Operator
.Modulus
)
3738 bool IsRelationalExpression
{
3740 if (oper
== Operator
.Equality
|| oper
== Operator
.Inequality
||
3741 oper
== Operator
.LessThan
|| oper
== Operator
.LessThanOrEqual
||
3742 oper
== Operator
.GreaterThan
|| oper
== Operator
.GreaterThanOrEqual
)
3749 bool IsShiftExpression
{
3751 if (oper
== Operator
.LeftShift
|| oper
== Operator
.RightShift
)
3758 bool IsShortCircuitedLogicalExpression
{
3760 if (oper
== Operator
.LogicalAndAlso
|| oper
== Operator
.LogicalOrElse
)
3769 return (oper
== Operator
.Is
);
3773 MethodInfo HelperMethod
{
3775 MethodInfo helper_method
= null;
3777 case Operator
.Multiply
:
3778 helper_method
= TypeManager
.msvbcs_objecttype_mulobj_object_object
;
3780 case Operator
.Division
:
3781 helper_method
= TypeManager
.msvbcs_objecttype_divobj_object_object
;
3783 case Operator
.IntegerDivision
:
3784 helper_method
= TypeManager
.msvbcs_objecttype_idivobj_object_object
;
3786 case Operator
.Modulus
:
3787 helper_method
= TypeManager
.msvbcs_objecttype_modobj_object_object
;
3789 case Operator
.Addition
:
3790 helper_method
= TypeManager
.msvbcs_objecttype_addobj_object_object
;
3792 case Operator
.Subtraction
:
3793 helper_method
= TypeManager
.msvbcs_objecttype_subobj_object_object
;
3795 case Operator
.LessThan
:
3796 case Operator
.GreaterThan
:
3797 case Operator
.LessThanOrEqual
:
3798 case Operator
.GreaterThanOrEqual
:
3799 case Operator
.Equality
:
3800 case Operator
.Inequality
:
3801 helper_method
= TypeManager
.msvbcs_objecttype_objtst_object_object_boolean
;
3803 case Operator
.BitwiseAnd
:
3804 helper_method
= TypeManager
.msvbcs_objecttype_bitandobj_object_object
;
3806 case Operator
.BitwiseOr
:
3807 helper_method
= TypeManager
.msvbcs_objecttype_bitorobj_object_object
;
3809 case Operator
.ExclusiveOr
:
3810 helper_method
= TypeManager
.msvbcs_objecttype_bitxorobj_object_object
;
3814 helper_method
= TypeManager
.msvbcs_objecttype_likeobj_object_object_comparemethod
;
3817 case Operator
.Concatenation
:
3818 helper_method
= TypeManager
.msvbcs_objecttype_strcatobj_object_object
;
3821 case Operator
.Exponentiation
:
3822 helper_method
= TypeManager
.msvbcs_objecttype_powobj_object_object
;
3824 case Operator
.LeftShift
:
3825 helper_method
= TypeManager
.msvbcs_objecttype_shiftleftobj_object_int32
;
3827 case Operator
.RightShift
:
3828 helper_method
= TypeManager
.msvbcs_objecttype_shiftrightobj_object_int32
;
3833 return helper_method
;
3839 // Object created by Binary when the binary operator uses an method instead of being
3840 // a binary operation that maps to a CIL binary operation.
3842 public class BinaryMethod
: Expression
{
3843 public MethodBase method
;
3844 public ArrayList Arguments
;
3846 public BinaryMethod (Type t
, MethodBase m
, ArrayList args
)
3851 eclass
= ExprClass
.Value
;
3854 public override Expression
DoResolve (EmitContext ec
)
3859 public override void Emit (EmitContext ec
)
3861 ILGenerator ig
= ec
.ig
;
3863 if (Arguments
!= null)
3864 Invocation
.EmitArguments (ec
, method
, Arguments
, false, null);
3866 if (method
is MethodInfo
)
3867 ig
.Emit (OpCodes
.Call
, (MethodInfo
) method
);
3869 ig
.Emit (OpCodes
.Call
, (ConstructorInfo
) method
);
3874 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3875 // b, c, d... may be strings or objects.
3877 public class StringConcat
: Expression
{
3879 bool invalid
= false;
3880 bool emit_conv_done
= false;
3882 // Are we also concating objects?
3884 bool is_strings_only
= true;
3886 public StringConcat (EmitContext ec
, Location loc
, Expression left
, Expression right
)
3889 type
= TypeManager
.string_type
;
3890 eclass
= ExprClass
.Value
;
3892 operands
= new ArrayList (2);
3897 public override Expression
DoResolve (EmitContext ec
)
3905 public void Append (EmitContext ec
, Expression operand
)
3910 if (operand
is StringConstant
&& operands
.Count
!= 0) {
3911 StringConstant last_operand
= operands
[operands
.Count
- 1] as StringConstant
;
3912 if (last_operand
!= null) {
3913 operands
[operands
.Count
- 1] = new StringConstant (last_operand
.Value
+ ((StringConstant
) operand
).Value
);
3919 // Conversion to object
3921 if (operand
.Type
!= TypeManager
.string_type
) {
3922 Expression no
= Convert
.WideningConversion (ec
, operand
, TypeManager
.object_type
, loc
);
3925 Binary
.Error_OperatorCannotBeApplied (loc
, "+", TypeManager
.string_type
, operand
.Type
);
3931 operands
.Add (operand
);
3934 public override void Emit (EmitContext ec
)
3936 MethodInfo concat_method
= null;
3939 // Do conversion to arguments; check for strings only
3942 // This can get called multiple times, so we have to deal with that.
3943 if (!emit_conv_done
) {
3944 emit_conv_done
= true;
3945 for (int i
= 0; i
< operands
.Count
; i
++) {
3946 Expression e
= (Expression
) operands
[i
];
3947 is_strings_only
&= e
.Type
== TypeManager
.string_type
;
3950 for (int i
= 0; i
< operands
.Count
; i
++) {
3951 Expression e
= (Expression
) operands
[i
];
3953 if (! is_strings_only
&& e
.Type
== TypeManager
.string_type
) {
3954 // need to make sure this is an object, because the EmitParams
3955 // method might look at the type of this expression, see it is a
3956 // string and emit a string [] when we want an object [];
3958 e
= new EmptyCast (e
, TypeManager
.object_type
);
3960 operands
[i
] = new Argument (e
, Argument
.AType
.Expression
);
3965 // Find the right method
3967 switch (operands
.Count
) {
3970 // This should not be possible, because simple constant folding
3971 // is taken care of in the Binary code.
3973 throw new Exception ("how did you get here?");
3976 concat_method
= is_strings_only
?
3977 TypeManager
.string_concat_string_string
:
3978 TypeManager
.string_concat_object_object
;
3981 concat_method
= is_strings_only
?
3982 TypeManager
.string_concat_string_string_string
:
3983 TypeManager
.string_concat_object_object_object
;
3987 // There is not a 4 param overlaod for object (the one that there is
3988 // is actually a varargs methods, and is only in corlib because it was
3989 // introduced there before.).
3991 if (!is_strings_only
)
3994 concat_method
= TypeManager
.string_concat_string_string_string_string
;
3997 concat_method
= is_strings_only
?
3998 TypeManager
.string_concat_string_dot_dot_dot
:
3999 TypeManager
.string_concat_object_dot_dot_dot
;
4003 Invocation
.EmitArguments (ec
, concat_method
, operands
, false, null);
4004 ec
.ig
.Emit (OpCodes
.Call
, concat_method
);
4009 // Object created with +/= on delegates
4011 public class BinaryDelegate
: Expression
{
4015 public BinaryDelegate (Type t
, MethodInfo mi
, ArrayList args
)
4020 eclass
= ExprClass
.Value
;
4023 public override Expression
DoResolve (EmitContext ec
)
4028 public override void Emit (EmitContext ec
)
4030 ILGenerator ig
= ec
.ig
;
4032 Invocation
.EmitArguments (ec
, method
, args
, false, null);
4034 ig
.Emit (OpCodes
.Call
, (MethodInfo
) method
);
4035 ig
.Emit (OpCodes
.Castclass
, type
);
4038 public Expression Right
{
4040 Argument arg
= (Argument
) args
[1];
4045 public bool IsAddition
{
4047 return method
== TypeManager
.delegate_combine_delegate_delegate
;
4053 // User-defined conditional logical operator
4054 public class ConditionalLogicalOperator
: Expression
{
4055 Expression left
, right
;
4058 public ConditionalLogicalOperator (bool is_and
, Expression left
, Expression right
, Type t
, Location loc
)
4061 eclass
= ExprClass
.Value
;
4065 this.is_and
= is_and
;
4068 protected void Error19 ()
4070 Binary
.Error_OperatorCannotBeApplied (loc
, is_and
? "&&" : "||", type
, type
);
4073 protected void Error218 ()
4075 Error (218, "The type ('" + TypeManager
.CSharpName (type
) + "') must contain " +
4076 "declarations of operator true and operator false");
4079 Expression op_true
, op_false
, op
;
4080 LocalTemporary left_temp
;
4082 public override Expression
DoResolve (EmitContext ec
)
4085 Expression operator_group
;
4087 operator_group
= MethodLookup (ec
, type
, is_and
? "op_BitwiseAnd" : "op_BitwiseOr", loc
);
4088 if (operator_group
== null) {
4093 left_temp
= new LocalTemporary (ec
, type
);
4095 ArrayList arguments
= new ArrayList ();
4096 arguments
.Add (new Argument (left_temp
, Argument
.AType
.Expression
));
4097 arguments
.Add (new Argument (right
, Argument
.AType
.Expression
));
4098 method
= Invocation
.OverloadResolve (
4099 ec
, (MethodGroupExpr
) operator_group
, arguments
, false, loc
)
4101 if ((method
== null) || (method
.ReturnType
!= type
)) {
4106 op
= new StaticCallExpr (method
, arguments
, loc
);
4108 op_true
= GetOperatorTrue (ec
, left_temp
, loc
);
4109 op_false
= GetOperatorFalse (ec
, left_temp
, loc
);
4110 if ((op_true
== null) || (op_false
== null)) {
4118 public override void Emit (EmitContext ec
)
4120 ILGenerator ig
= ec
.ig
;
4121 Label false_target
= ig
.DefineLabel ();
4122 Label end_target
= ig
.DefineLabel ();
4125 left_temp
.Store (ec
);
4127 (is_and
? op_false
: op_true
).EmitBranchable (ec
, false_target
, false);
4128 left_temp
.Emit (ec
);
4129 ig
.Emit (OpCodes
.Br
, end_target
);
4130 ig
.MarkLabel (false_target
);
4132 ig
.MarkLabel (end_target
);
4136 public class PointerArithmetic
: Expression
{
4137 Expression left
, right
;
4141 // We assume that `l' is always a pointer
4143 public PointerArithmetic (bool is_addition
, Expression l
, Expression r
, Type t
, Location loc
)
4149 is_add
= is_addition
;
4152 public override Expression
DoResolve (EmitContext ec
)
4154 eclass
= ExprClass
.Variable
;
4156 if (left
.Type
== TypeManager
.void_ptr_type
) {
4157 Error (242, "The operation in question is undefined on void pointers");
4164 public override void Emit (EmitContext ec
)
4166 Type op_type
= left
.Type
;
4167 ILGenerator ig
= ec
.ig
;
4168 Type element
= TypeManager
.GetElementType (op_type
);
4169 int size
= GetTypeSize (element
);
4170 Type rtype
= right
.Type
;
4172 if (rtype
.IsPointer
){
4174 // handle (pointer - pointer)
4178 ig
.Emit (OpCodes
.Sub
);
4182 ig
.Emit (OpCodes
.Sizeof
, element
);
4184 IntLiteral
.EmitInt (ig
, size
);
4185 ig
.Emit (OpCodes
.Div
);
4187 ig
.Emit (OpCodes
.Conv_I8
);
4190 // handle + and - on (pointer op int)
4193 ig
.Emit (OpCodes
.Conv_I
);
4195 Constant right_const
= right
as Constant
;
4196 if (right_const
!= null && size
!= 0) {
4197 Expression ex
= ConstantFold
.BinaryFold (ec
, Binary
.Operator
.Multiply
, new IntConstant (size
), right_const
, loc
);
4205 ig
.Emit (OpCodes
.Sizeof
, element
);
4207 IntLiteral
.EmitInt (ig
, size
);
4208 if (rtype
== TypeManager
.int64_type
)
4209 ig
.Emit (OpCodes
.Conv_I8
);
4210 else if (rtype
== TypeManager
.uint64_type
)
4211 ig
.Emit (OpCodes
.Conv_U8
);
4212 ig
.Emit (OpCodes
.Mul
);
4216 if (rtype
== TypeManager
.int64_type
|| rtype
== TypeManager
.uint64_type
)
4217 ig
.Emit (OpCodes
.Conv_I
);
4220 ig
.Emit (OpCodes
.Add
);
4222 ig
.Emit (OpCodes
.Sub
);
4228 /// Implements the ternary conditional operator (?:)
4230 public class Conditional
: Expression
{
4231 Expression expr
, trueExpr
, falseExpr
;
4233 public Conditional (Expression expr
, Expression trueExpr
, Expression falseExpr
, Location l
)
4236 this.trueExpr
= trueExpr
;
4237 this.falseExpr
= falseExpr
;
4241 public Expression Expr
{
4247 public Expression TrueExpr
{
4253 public Expression FalseExpr
{
4259 public override Expression
DoResolve (EmitContext ec
)
4261 expr
= expr
.Resolve (ec
);
4266 if (TypeManager
.IsNullableType (expr
.Type
))
4267 return new Nullable
.LiftedConditional (expr
, trueExpr
, falseExpr
, loc
).Resolve (ec
);
4269 if (expr
.Type
!= TypeManager
.bool_type
){
4270 expr
= Expression
.ResolveBoolean (
4277 trueExpr
= trueExpr
.Resolve (ec
);
4278 falseExpr
= falseExpr
.Resolve (ec
);
4280 if (trueExpr
== null || falseExpr
== null)
4283 eclass
= ExprClass
.Value
;
4284 if (trueExpr
.Type
== falseExpr
.Type
)
4285 type
= trueExpr
.Type
;
4288 Type true_type
= trueExpr
.Type
;
4289 Type false_type
= falseExpr
.Type
;
4292 // First, if an implicit conversion exists from trueExpr
4293 // to falseExpr, then the result type is of type falseExpr.Type
4295 conv
= Convert
.WideningConversion (ec
, trueExpr
, false_type
, loc
);
4298 // Check if both can convert implicitl to each other's type
4300 if (Convert
.WideningConversion (ec
, falseExpr
, true_type
, loc
) != null){
4302 "Can not compute type of conditional expression " +
4303 "as `" + TypeManager
.CSharpName (trueExpr
.Type
) +
4304 "' and `" + TypeManager
.CSharpName (falseExpr
.Type
) +
4305 "' convert implicitly to each other");
4310 } else if ((conv
= Convert
.WideningConversion(ec
, falseExpr
, true_type
,loc
))!= null){
4314 Error (173, "The type of the conditional expression can " +
4315 "not be computed because there is no implicit conversion" +
4316 " from `" + TypeManager
.CSharpName (trueExpr
.Type
) + "'" +
4317 " and `" + TypeManager
.CSharpName (falseExpr
.Type
) + "'");
4322 // Dead code optimalization
4323 if (expr
is BoolConstant
){
4324 BoolConstant bc
= (BoolConstant
) expr
;
4326 Report
.Warning (429, 4, bc
.Value
? falseExpr
.Location
: trueExpr
.Location
, "Unreachable expression code detected");
4327 return bc
.Value
? trueExpr
: falseExpr
;
4333 public override void Emit (EmitContext ec
)
4335 ILGenerator ig
= ec
.ig
;
4336 Label false_target
= ig
.DefineLabel ();
4337 Label end_target
= ig
.DefineLabel ();
4339 expr
.EmitBranchable (ec
, false_target
, false);
4341 ig
.Emit (OpCodes
.Br
, end_target
);
4342 ig
.MarkLabel (false_target
);
4343 falseExpr
.Emit (ec
);
4344 ig
.MarkLabel (end_target
);
4352 public class LocalVariableReference
: Expression
, IAssignMethod
, IMemoryLocation
, IVariable
{
4353 public readonly string Name
;
4354 public readonly Block Block
;
4355 public LocalInfo local_info
;
4358 LocalTemporary temp
;
4360 public LocalVariableReference (Block block
, string name
, Location l
)
4365 eclass
= ExprClass
.Variable
;
4369 // Setting `is_readonly' to false will allow you to create a writable
4370 // reference to a read-only variable. This is used by foreach and using.
4372 public LocalVariableReference (Block block
, string name
, Location l
,
4373 LocalInfo local_info
, bool is_readonly
)
4374 : this (block
, name
, l
)
4376 this.local_info
= local_info
;
4377 this.is_readonly
= is_readonly
;
4380 public VariableInfo VariableInfo
{
4382 return local_info
.VariableInfo
;
4386 public bool IsReadOnly
{
4392 protected Expression
DoResolveBase (EmitContext ec
, Expression lvalue_right_side
)
4394 if (local_info
== null) {
4395 local_info
= Block
.GetLocalInfo (Name
);
4398 if (lvalue_right_side
== EmptyExpression
.Null
)
4399 local_info
.Used
= true;
4401 is_readonly
= local_info
.ReadOnly
;
4404 type
= local_info
.VariableType
;
4406 VariableInfo variable_info
= local_info
.VariableInfo
;
4407 if (lvalue_right_side
!= null){
4409 Error (1604, "cannot assign to `" + Name
+ "' because it is readonly");
4413 if (variable_info
!= null)
4414 variable_info
.SetAssigned (ec
);
4417 Expression e
= Block
.GetConstantExpression (Name
);
4419 local_info
.Used
= true;
4420 eclass
= ExprClass
.Value
;
4421 return e
.Resolve (ec
);
4424 if ((variable_info
!= null) && !variable_info
.IsAssigned (ec
, loc
))
4427 if (lvalue_right_side
== null)
4428 local_info
.Used
= true;
4430 if (ec
.CurrentAnonymousMethod
!= null){
4432 // If we are referencing a variable from the external block
4433 // flag it for capturing
4435 if (local_info
.Block
.Toplevel
!= ec
.CurrentBlock
.Toplevel
){
4436 if (local_info
.AddressTaken
){
4437 AnonymousMethod
.Error_AddressOfCapturedVar (local_info
.Name
, loc
);
4440 ec
.CaptureVariable (local_info
);
4447 public override Expression
DoResolve (EmitContext ec
)
4449 return DoResolveBase (ec
, null);
4452 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
4454 Expression ret
= DoResolveBase (ec
, right_side
);
4456 CheckObsoleteAttribute (ret
.Type
);
4461 public bool VerifyFixed (bool is_expression
)
4463 return !is_expression
|| local_info
.IsFixed
;
4466 public override void Emit (EmitContext ec
)
4468 ILGenerator ig
= ec
.ig
;
4470 if (local_info
.FieldBuilder
== null){
4472 // A local variable on the local CLR stack
4474 ig
.Emit (OpCodes
.Ldloc
, local_info
.LocalBuilder
);
4477 // A local variable captured by anonymous methods.
4480 ec
.EmitCapturedVariableInstance (local_info
);
4482 ig
.Emit (OpCodes
.Ldfld
, local_info
.FieldBuilder
);
4486 public void Emit (EmitContext ec
, bool leave_copy
)
4490 ec
.ig
.Emit (OpCodes
.Dup
);
4491 if (local_info
.FieldBuilder
!= null){
4492 temp
= new LocalTemporary (ec
, Type
);
4498 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
4500 ILGenerator ig
= ec
.ig
;
4501 prepared
= prepare_for_load
;
4503 if (local_info
.FieldBuilder
== null){
4505 // A local variable on the local CLR stack
4507 if (local_info
.LocalBuilder
== null)
4508 throw new Exception ("This should not happen: both Field and Local are null");
4512 ec
.ig
.Emit (OpCodes
.Dup
);
4513 ig
.Emit (OpCodes
.Stloc
, local_info
.LocalBuilder
);
4516 // A local variable captured by anonymous methods or itereators.
4518 ec
.EmitCapturedVariableInstance (local_info
);
4520 if (prepare_for_load
)
4521 ig
.Emit (OpCodes
.Dup
);
4524 ig
.Emit (OpCodes
.Dup
);
4525 temp
= new LocalTemporary (ec
, Type
);
4528 ig
.Emit (OpCodes
.Stfld
, local_info
.FieldBuilder
);
4534 public void AddressOf (EmitContext ec
, AddressOp mode
)
4536 ILGenerator ig
= ec
.ig
;
4538 if (local_info
.FieldBuilder
== null){
4540 // A local variable on the local CLR stack
4542 ig
.Emit (OpCodes
.Ldloca
, local_info
.LocalBuilder
);
4545 // A local variable captured by anonymous methods or iterators
4547 ec
.EmitCapturedVariableInstance (local_info
);
4548 ig
.Emit (OpCodes
.Ldflda
, local_info
.FieldBuilder
);
4552 public override string ToString ()
4554 return String
.Format ("{0} ({1}:{2})", GetType (), Name
, loc
);
4559 /// This represents a reference to a parameter in the intermediate
4562 public class ParameterReference
: Expression
, IAssignMethod
, IMemoryLocation
, IVariable
{
4568 public Parameter
.Modifier mod
;
4569 public bool is_ref
, is_out
, prepared
;
4583 LocalTemporary temp
;
4585 public ParameterReference (Parameters pars
, Block block
, int idx
, string name
, Location loc
)
4592 eclass
= ExprClass
.Variable
;
4595 public VariableInfo VariableInfo
{
4599 public bool VerifyFixed (bool is_expression
)
4601 return !is_expression
|| TypeManager
.IsValueType (type
);
4604 public bool IsAssigned (EmitContext ec
, Location loc
)
4606 if (!ec
.DoFlowAnalysis
|| !is_out
|| ec
.CurrentBranching
.IsAssigned (vi
))
4609 Report
.Error (165, loc
,
4610 "Use of unassigned parameter `" + name
+ "'");
4614 public bool IsFieldAssigned (EmitContext ec
, string field_name
, Location loc
)
4616 if (!ec
.DoFlowAnalysis
|| !is_out
|| ec
.CurrentBranching
.IsFieldAssigned (vi
, field_name
))
4619 Report
.Error (170, loc
,
4620 "Use of possibly unassigned field `" + field_name
+ "'");
4624 public void SetAssigned (EmitContext ec
)
4626 if (is_out
&& ec
.DoFlowAnalysis
)
4627 ec
.CurrentBranching
.SetAssigned (vi
);
4630 public void SetFieldAssigned (EmitContext ec
, string field_name
)
4632 if (is_out
&& ec
.DoFlowAnalysis
)
4633 ec
.CurrentBranching
.SetFieldAssigned (vi
, field_name
);
4636 protected void DoResolveBase (EmitContext ec
)
4638 type
= pars
.GetParameterInfo (ec
, idx
, out mod
);
4639 is_ref
= (mod
& Parameter
.Modifier
.ISBYREF
) != 0;
4640 is_out
= (mod
& Parameter
.Modifier
.OUT
) != 0;
4641 eclass
= ExprClass
.Variable
;
4644 vi
= block
.ParameterMap
[idx
];
4646 if (ec
.CurrentAnonymousMethod
!= null){
4648 Report
.Error (1628, Location
,
4649 "Can not reference a ref or out parameter in an anonymous method");
4654 // If we are referencing the parameter from the external block
4655 // flag it for capturing
4657 //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name));
4658 if (!block
.IsLocalParameter (name
)){
4659 ec
.CaptureParameter (name
, type
, idx
);
4665 // Notice that for ref/out parameters, the type exposed is not the
4666 // same type exposed externally.
4669 // externally we expose "int&"
4670 // here we expose "int".
4672 // We record this in "is_ref". This means that the type system can treat
4673 // the type as it is expected, but when we generate the code, we generate
4674 // the alternate kind of code.
4676 public override Expression
DoResolve (EmitContext ec
)
4680 if (is_out
&& ec
.DoFlowAnalysis
&& !IsAssigned (ec
, loc
))
4683 if (ec
.RemapToProxy
)
4684 return ec
.RemapParameter (idx
);
4689 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
4695 if (ec
.RemapToProxy
)
4696 return ec
.RemapParameterLValue (idx
, right_side
);
4701 static public void EmitLdArg (ILGenerator ig
, int x
)
4705 case 0: ig
.Emit (OpCodes
.Ldarg_0
); break;
4706 case 1: ig
.Emit (OpCodes
.Ldarg_1
); break;
4707 case 2: ig
.Emit (OpCodes
.Ldarg_2
); break;
4708 case 3: ig
.Emit (OpCodes
.Ldarg_3
); break;
4709 default: ig
.Emit (OpCodes
.Ldarg_S
, (byte) x
); break;
4712 ig
.Emit (OpCodes
.Ldarg
, x
);
4716 // This method is used by parameters that are references, that are
4717 // being passed as references: we only want to pass the pointer (that
4718 // is already stored in the parameter, not the address of the pointer,
4719 // and not the value of the variable).
4721 public void EmitLoad (EmitContext ec
)
4723 ILGenerator ig
= ec
.ig
;
4729 EmitLdArg (ig
, arg_idx
);
4732 // FIXME: Review for anonymous methods
4736 public override void Emit (EmitContext ec
)
4738 if (ec
.HaveCaptureInfo
&& ec
.IsParameterCaptured (name
)){
4739 ec
.EmitParameter (name
);
4746 public void Emit (EmitContext ec
, bool leave_copy
)
4748 ILGenerator ig
= ec
.ig
;
4754 EmitLdArg (ig
, arg_idx
);
4758 ec
.ig
.Emit (OpCodes
.Dup
);
4761 // If we are a reference, we loaded on the stack a pointer
4762 // Now lets load the real value
4764 LoadFromPtr (ig
, type
);
4768 ec
.ig
.Emit (OpCodes
.Dup
);
4771 temp
= new LocalTemporary (ec
, type
);
4777 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
4779 if (ec
.HaveCaptureInfo
&& ec
.IsParameterCaptured (name
)){
4780 ec
.EmitAssignParameter (name
, source
, leave_copy
, prepare_for_load
);
4784 ILGenerator ig
= ec
.ig
;
4787 prepared
= prepare_for_load
;
4792 if (is_ref
&& !prepared
)
4793 EmitLdArg (ig
, arg_idx
);
4798 ec
.ig
.Emit (OpCodes
.Dup
);
4802 temp
= new LocalTemporary (ec
, type
);
4806 StoreFromPtr (ig
, type
);
4812 ig
.Emit (OpCodes
.Starg_S
, (byte) arg_idx
);
4814 ig
.Emit (OpCodes
.Starg
, arg_idx
);
4818 public void AddressOf (EmitContext ec
, AddressOp mode
)
4820 if (ec
.HaveCaptureInfo
&& ec
.IsParameterCaptured (name
)){
4821 ec
.EmitAddressOfParameter (name
);
4832 ec
.ig
.Emit (OpCodes
.Ldarg_S
, (byte) arg_idx
);
4834 ec
.ig
.Emit (OpCodes
.Ldarg
, arg_idx
);
4837 ec
.ig
.Emit (OpCodes
.Ldarga_S
, (byte) arg_idx
);
4839 ec
.ig
.Emit (OpCodes
.Ldarga
, arg_idx
);
4846 /// Used for arguments to New(), Invocation()
4848 public class Argument
{
4849 public enum AType
: byte {
4854 //FIXME: These two are mbas specific and the
4855 // related changes need to be propagated
4860 public readonly AType ArgType
;
4861 public Expression Expr
;
4863 public Argument (Expression expr
, AType type
)
4866 this.ArgType
= type
;
4869 public Argument (Expression expr
)
4872 this.ArgType
= AType
.Expression
;
4877 if (ArgType
== AType
.Ref
|| ArgType
== AType
.Out
)
4878 return TypeManager
.GetReferenceType (Expr
.Type
);
4884 public Parameter
.Modifier
GetParameterModifier ()
4888 return Parameter
.Modifier
.OUT
| Parameter
.Modifier
.ISBYREF
;
4891 return Parameter
.Modifier
.REF
| Parameter
.Modifier
.ISBYREF
;
4894 return Parameter
.Modifier
.NONE
;
4898 public static string FullDesc (Argument a
)
4900 if (a
.ArgType
== AType
.ArgList
)
4903 return (a
.ArgType
== AType
.Ref
? "ref " :
4904 (a
.ArgType
== AType
.Out
? "out " : "")) +
4905 TypeManager
.CSharpName (a
.Expr
.Type
);
4908 public bool ResolveMethodGroup (EmitContext ec
, Location loc
)
4910 ConstructedType ctype
= Expr
as ConstructedType
;
4912 Expr
= ctype
.GetSimpleName (ec
);
4914 // FIXME: csc doesn't report any error if you try to use `ref' or
4915 // `out' in a delegate creation expression.
4916 Expr
= Expr
.Resolve (ec
, ResolveFlags
.VariableOrValue
| ResolveFlags
.MethodGroup
);
4923 public bool Resolve (EmitContext ec
, Location loc
)
4925 if (ArgType
== AType
.Ref
) {
4926 Expr
= Expr
.Resolve (ec
);
4930 if (!ec
.IsConstructor
) {
4931 FieldExpr fe
= Expr
as FieldExpr
;
4932 if (fe
!= null && fe
.FieldInfo
.IsInitOnly
) {
4933 if (fe
.FieldInfo
.IsStatic
)
4934 Report
.Error (199, loc
, "A static readonly field cannot be passed ref or out (except in a static constructor)");
4936 Report
.Error (192, loc
, "A readonly field cannot be passed ref or out (except in a constructor)");
4940 Expr
= Expr
.ResolveLValue (ec
, Expr
);
4941 } else if (ArgType
== AType
.Out
)
4942 Expr
= Expr
.ResolveLValue (ec
, EmptyExpression
.Null
);
4944 Expr
= Expr
.Resolve (ec
);
4949 if (ArgType
== AType
.Expression
)
4953 // Catch errors where fields of a MarshalByRefObject are passed as ref or out
4954 // This is only allowed for `this'
4956 FieldExpr fe
= Expr
as FieldExpr
;
4957 if (fe
!= null && !fe
.IsStatic
){
4958 Expression instance
= fe
.InstanceExpression
;
4960 if (instance
.GetType () != typeof (This
)){
4961 if (fe
.InstanceExpression
.Type
.IsSubclassOf (TypeManager
.mbr_type
)){
4962 Report
.SymbolRelatedToPreviousError (fe
.InstanceExpression
.Type
);
4963 Report
.Error (197, loc
, "Cannot pass '{0}' as ref or out or take its address because it is a member of a marshal-by-reference class",
4971 if (Expr
.eclass
!= ExprClass
.Variable
){
4973 // We just probe to match the CSC output
4975 if (Expr
.eclass
== ExprClass
.PropertyAccess
||
4976 Expr
.eclass
== ExprClass
.IndexerAccess
){
4979 "A property or indexer can not be passed as an out or ref " +
4984 "An lvalue is required as an argument to out or ref");
4992 public void Emit (EmitContext ec
)
4995 // Ref and Out parameters need to have their addresses taken.
4997 // ParameterReferences might already be references, so we want
4998 // to pass just the value
5000 if (ArgType
== AType
.Ref
|| ArgType
== AType
.Out
){
5001 AddressOp mode
= AddressOp
.Store
;
5003 if (ArgType
== AType
.Ref
)
5004 mode
|= AddressOp
.Load
;
5006 if (Expr
is ParameterReference
){
5007 ParameterReference pr
= (ParameterReference
) Expr
;
5013 pr
.AddressOf (ec
, mode
);
5016 if (Expr
is IMemoryLocation
)
5017 ((IMemoryLocation
) Expr
).AddressOf (ec
, mode
);
5020 1510, Expr
.Location
,
5021 "An lvalue is required as an argument to out or ref");
5031 /// Invocation of methods or delegates.
5033 public class Invocation
: ExpressionStatement
{
5034 public readonly ArrayList Arguments
;
5036 public Expression expr
;
5037 MethodBase method
= null;
5039 static Hashtable method_parameter_cache
;
5041 static Invocation ()
5043 method_parameter_cache
= new PtrHashtable ();
5047 // arguments is an ArrayList, but we do not want to typecast,
5048 // as it might be null.
5050 // FIXME: only allow expr to be a method invocation or a
5051 // delegate invocation (7.5.5)
5053 public Invocation (Expression expr
, ArrayList arguments
, Location l
)
5056 Arguments
= arguments
;
5060 public Expression Expr
{
5067 /// Returns the Parameters (a ParameterData interface) for the
5070 public static ParameterData
GetParameterData (MethodBase mb
)
5072 object pd
= method_parameter_cache
[mb
];
5076 return (ParameterData
) pd
;
5078 ip
= TypeManager
.LookupParametersByBuilder (mb
);
5080 method_parameter_cache
[mb
] = ip
;
5082 return (ParameterData
) ip
;
5084 ReflectionParameters rp
= new ReflectionParameters (mb
);
5085 method_parameter_cache
[mb
] = rp
;
5087 return (ParameterData
) rp
;
5092 /// Determines "better conversion" as specified in 7.4.2.3
5094 /// Returns : p if a->p is better,
5095 /// q if a->q is better,
5096 /// null if neither is better
5098 static Type
BetterConversion (EmitContext ec
, Argument a
, Type p
, Type q
, Location loc
)
5100 Type argument_type
= TypeManager
.TypeToCoreType (a
.Type
);
5101 Expression argument_expr
= a
.Expr
;
5103 // p = TypeManager.TypeToCoreType (p);
5104 // q = TypeManager.TypeToCoreType (q);
5106 if (argument_type
== null)
5107 throw new Exception ("Expression of type " + a
.Expr
+
5108 " does not resolve its type");
5110 if (p
== null || q
== null)
5111 throw new InternalErrorException ("BetterConversion Got a null conversion");
5116 if (argument_expr
is NullLiteral
) {
5118 // If the argument is null and one of the types to compare is 'object' and
5119 // the other is a reference type, we prefer the other.
5121 // This follows from the usual rules:
5122 // * There is an implicit conversion from 'null' to type 'object'
5123 // * There is an implicit conversion from 'null' to any reference type
5124 // * There is an implicit conversion from any reference type to type 'object'
5125 // * There is no implicit conversion from type 'object' to other reference types
5126 // => Conversion of 'null' to a reference type is better than conversion to 'object'
5128 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
5129 // null type. I think it used to be 'object' and thus needed a special
5130 // case to avoid the immediately following two checks.
5132 if (!p
.IsValueType
&& q
== TypeManager
.object_type
)
5134 if (!q
.IsValueType
&& p
== TypeManager
.object_type
)
5138 if (argument_type
== p
)
5141 if (argument_type
== q
)
5144 Expression p_tmp
= new EmptyExpression (p
);
5145 Expression q_tmp
= new EmptyExpression (q
);
5147 bool p_to_q
= Convert
.WideningConversionExists (ec
, p_tmp
, q
);
5148 bool q_to_p
= Convert
.WideningConversionExists (ec
, q_tmp
, p
);
5150 if (p_to_q
&& !q_to_p
)
5153 if (q_to_p
&& !p_to_q
)
5156 if (p
== TypeManager
.sbyte_type
)
5157 if (q
== TypeManager
.byte_type
|| q
== TypeManager
.ushort_type
||
5158 q
== TypeManager
.uint32_type
|| q
== TypeManager
.uint64_type
)
5160 if (q
== TypeManager
.sbyte_type
)
5161 if (p
== TypeManager
.byte_type
|| p
== TypeManager
.ushort_type
||
5162 p
== TypeManager
.uint32_type
|| p
== TypeManager
.uint64_type
)
5165 if (p
== TypeManager
.short_type
)
5166 if (q
== TypeManager
.ushort_type
|| q
== TypeManager
.uint32_type
||
5167 q
== TypeManager
.uint64_type
)
5170 if (q
== TypeManager
.short_type
)
5171 if (p
== TypeManager
.ushort_type
|| p
== TypeManager
.uint32_type
||
5172 p
== TypeManager
.uint64_type
)
5175 if (p
== TypeManager
.int32_type
)
5176 if (q
== TypeManager
.uint32_type
|| q
== TypeManager
.uint64_type
)
5179 if (q
== TypeManager
.int32_type
)
5180 if (p
== TypeManager
.uint32_type
|| p
== TypeManager
.uint64_type
)
5183 if (p
== TypeManager
.int64_type
)
5184 if (q
== TypeManager
.uint64_type
)
5186 if (q
== TypeManager
.int64_type
)
5187 if (p
== TypeManager
.uint64_type
)
5194 /// Determines "Better function" between candidate
5195 /// and the current best match
5198 /// Returns a boolean indicating :
5199 /// false if candidate ain't better
5200 /// true if candidate is better than the current best match
5202 static bool BetterFunction (EmitContext ec
, ArrayList args
, int argument_count
,
5203 MethodBase candidate
, bool candidate_params
,
5204 MethodBase best
, bool best_params
, Location loc
)
5206 ParameterData candidate_pd
= GetParameterData (candidate
);
5207 ParameterData best_pd
= GetParameterData (best
);
5209 int cand_count
= candidate_pd
.Count
;
5212 // If there is no best method, than this one
5213 // is better, however, if we already found a
5214 // best method, we cant tell. This happens
5225 // interface IFooBar : IFoo, IBar {}
5227 // We cant tell if IFoo.DoIt is better than IBar.DoIt
5229 // However, we have to consider that
5230 // Trim (); is better than Trim (params char[] chars);
5232 if (cand_count
== 0 && argument_count
== 0)
5233 return !candidate_params
&& best_params
;
5235 if ((candidate_pd
.ParameterModifier (cand_count
- 1) != Parameter
.Modifier
.PARAMS
) &&
5236 (candidate_pd
.ParameterModifier (cand_count
- 1) != Parameter
.Modifier
.ARGLIST
))
5237 if (cand_count
!= argument_count
)
5240 bool better_at_least_one
= false;
5241 bool is_equal
= true;
5243 for (int j
= 0; j
< argument_count
; ++j
) {
5244 Argument a
= (Argument
) args
[j
];
5246 Type ct
= TypeManager
.TypeToCoreType (candidate_pd
.ParameterType (j
));
5247 Type bt
= TypeManager
.TypeToCoreType (best_pd
.ParameterType (j
));
5249 if (candidate_pd
.ParameterModifier (j
) == Parameter
.Modifier
.PARAMS
)
5250 if (candidate_params
)
5251 ct
= TypeManager
.GetElementType (ct
);
5253 if (best_pd
.ParameterModifier (j
) == Parameter
.Modifier
.PARAMS
)
5255 bt
= TypeManager
.GetElementType (bt
);
5257 if (!ct
.Equals (bt
))
5260 Type better
= BetterConversion (ec
, a
, ct
, bt
, loc
);
5261 // for each argument, the conversion to 'ct' should be no worse than
5262 // the conversion to 'bt'.
5266 // for at least one argument, the conversion to 'ct' should be better than
5267 // the conversion to 'bt'.
5269 better_at_least_one
= true;
5273 // If a method (in the normal form) with the
5274 // same signature as the expanded form of the
5275 // current best params method already exists,
5276 // the expanded form is not applicable so we
5277 // force it to select the candidate
5279 if (!candidate_params
&& best_params
&& cand_count
== argument_count
)
5283 // If two methods have equal parameter types, but
5284 // only one of them is generic, the non-generic one wins.
5287 if (TypeManager
.IsGenericMethod (best
) && !TypeManager
.IsGenericMethod (candidate
))
5289 else if (!TypeManager
.IsGenericMethod (best
) && TypeManager
.IsGenericMethod (candidate
))
5293 return better_at_least_one
;
5296 public static string FullMethodDesc (MethodBase mb
)
5298 string ret_type
= "";
5303 if (mb
is MethodInfo
)
5304 ret_type
= TypeManager
.CSharpName (((MethodInfo
) mb
).ReturnType
);
5306 StringBuilder sb
= new StringBuilder (ret_type
);
5308 sb
.Append (mb
.ReflectedType
.ToString ());
5310 sb
.Append (mb
.Name
);
5312 ParameterData pd
= GetParameterData (mb
);
5314 int count
= pd
.Count
;
5317 for (int i
= count
; i
> 0; ) {
5320 sb
.Append (pd
.ParameterDesc (count
- i
- 1));
5326 return sb
.ToString ();
5329 public static MethodGroupExpr
MakeUnionSet (Expression mg1
, Expression mg2
, Location loc
)
5331 MemberInfo
[] miset
;
5332 MethodGroupExpr union
;
5337 return (MethodGroupExpr
) mg2
;
5340 return (MethodGroupExpr
) mg1
;
5343 MethodGroupExpr left_set
= null, right_set
= null;
5344 int length1
= 0, length2
= 0;
5346 left_set
= (MethodGroupExpr
) mg1
;
5347 length1
= left_set
.Methods
.Length
;
5349 right_set
= (MethodGroupExpr
) mg2
;
5350 length2
= right_set
.Methods
.Length
;
5352 ArrayList common
= new ArrayList ();
5354 foreach (MethodBase r
in right_set
.Methods
){
5355 if (TypeManager
.ArrayContainsMethod (left_set
.Methods
, r
))
5359 miset
= new MemberInfo
[length1
+ length2
- common
.Count
];
5360 left_set
.Methods
.CopyTo (miset
, 0);
5364 foreach (MethodBase r
in right_set
.Methods
) {
5365 if (!common
.Contains (r
))
5369 union
= new MethodGroupExpr (miset
, loc
);
5374 static bool IsParamsMethodApplicable (EmitContext ec
, MethodGroupExpr me
,
5375 ArrayList arguments
, int arg_count
,
5376 ref MethodBase candidate
)
5378 return IsParamsMethodApplicable (
5379 ec
, me
, arguments
, arg_count
, false, ref candidate
) ||
5380 IsParamsMethodApplicable (
5381 ec
, me
, arguments
, arg_count
, true, ref candidate
);
5386 static bool IsParamsMethodApplicable (EmitContext ec
, MethodGroupExpr me
,
5387 ArrayList arguments
, int arg_count
,
5388 bool do_varargs
, ref MethodBase candidate
)
5390 if (!me
.HasTypeArguments
&&
5391 !TypeManager
.InferParamsTypeArguments (ec
, arguments
, ref candidate
))
5394 return IsParamsMethodApplicable (
5395 ec
, arguments
, arg_count
, candidate
, do_varargs
);
5399 /// Determines if the candidate method, if a params method, is applicable
5400 /// in its expanded form to the given set of arguments
5402 static bool IsParamsMethodApplicable (EmitContext ec
, ArrayList arguments
,
5403 int arg_count
, MethodBase candidate
,
5406 ParameterData pd
= GetParameterData (candidate
);
5408 int pd_count
= pd
.Count
;
5413 int count
= pd_count
- 1;
5415 if (pd
.ParameterModifier (count
) != Parameter
.Modifier
.ARGLIST
)
5417 if (pd_count
!= arg_count
)
5420 if (pd
.ParameterModifier (count
) != Parameter
.Modifier
.PARAMS
)
5424 if (count
> arg_count
)
5427 if (pd_count
== 1 && arg_count
== 0)
5431 // If we have come this far, the case which
5432 // remains is when the number of parameters is
5433 // less than or equal to the argument count.
5435 for (int i
= 0; i
< count
; ++i
) {
5437 Argument a
= (Argument
) arguments
[i
];
5439 Parameter
.Modifier a_mod
= a
.GetParameterModifier () &
5440 (unchecked (~
(Parameter
.Modifier
.OUT
| Parameter
.Modifier
.REF
)));
5441 Parameter
.Modifier p_mod
= pd
.ParameterModifier (i
) &
5442 (unchecked (~
(Parameter
.Modifier
.OUT
| Parameter
.Modifier
.REF
)));
5444 if (a_mod
== p_mod
) {
5446 if (a_mod
== Parameter
.Modifier
.NONE
)
5447 if (!Convert
.WideningConversionExists (ec
,
5449 pd
.ParameterType (i
)))
5452 if ((a_mod
& Parameter
.Modifier
.ISBYREF
) != 0) {
5453 Type pt
= pd
.ParameterType (i
);
5456 pt
= TypeManager
.GetReferenceType (pt
);
5467 Argument a
= (Argument
) arguments
[count
];
5468 if (!(a
.Expr
is Arglist
))
5474 Type element_type
= TypeManager
.GetElementType (pd
.ParameterType (pd_count
- 1));
5476 for (int i
= pd_count
- 1; i
< arg_count
; i
++) {
5477 Argument a
= (Argument
) arguments
[i
];
5479 if (!Convert
.WideningConversionExists (ec
, a
.Expr
, element_type
))
5486 static bool IsApplicable (EmitContext ec
, MethodGroupExpr me
,
5487 ArrayList arguments
, int arg_count
,
5488 ref MethodBase candidate
)
5490 if (!me
.HasTypeArguments
&&
5491 !TypeManager
.InferTypeArguments (ec
, arguments
, ref candidate
))
5494 return IsApplicable (ec
, arguments
, arg_count
, candidate
);
5498 /// Determines if the candidate method is applicable (section 14.4.2.1)
5499 /// to the given set of arguments
5501 static bool IsApplicable (EmitContext ec
, ArrayList arguments
, int arg_count
,
5502 MethodBase candidate
)
5504 ParameterData pd
= GetParameterData (candidate
);
5506 if (arg_count
!= pd
.Count
)
5509 for (int i
= arg_count
; i
> 0; ) {
5512 Argument a
= (Argument
) arguments
[i
];
5514 Parameter
.Modifier a_mod
= a
.GetParameterModifier () &
5515 unchecked (~
(Parameter
.Modifier
.OUT
| Parameter
.Modifier
.REF
));
5516 Parameter
.Modifier p_mod
= pd
.ParameterModifier (i
) &
5517 unchecked (~
(Parameter
.Modifier
.OUT
| Parameter
.Modifier
.REF
));
5520 if (a_mod
== p_mod
||
5521 (a_mod
== Parameter
.Modifier
.NONE
&& p_mod
== Parameter
.Modifier
.PARAMS
)) {
5522 if (a_mod
== Parameter
.Modifier
.NONE
) {
5523 if (!Convert
.WideningConversionExists (ec
,
5525 pd
.ParameterType (i
)))
5529 if ((a_mod
& Parameter
.Modifier
.ISBYREF
) != 0) {
5530 Type pt
= pd
.ParameterType (i
);
5533 pt
= TypeManager
.GetReferenceType (pt
);
5545 static private bool IsAncestralType (Type first_type
, Type second_type
)
5547 return first_type
!= second_type
&&
5548 (second_type
.IsSubclassOf (first_type
) ||
5549 TypeManager
.ImplementsInterface (second_type
, first_type
));
5553 /// Find the Applicable Function Members (7.4.2.1)
5555 /// me: Method Group expression with the members to select.
5556 /// it might contain constructors or methods (or anything
5557 /// that maps to a method).
5559 /// Arguments: ArrayList containing resolved Argument objects.
5561 /// loc: The location if we want an error to be reported, or a Null
5562 /// location for "probing" purposes.
5564 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
5565 /// that is the best match of me on Arguments.
5568 public static MethodBase
OverloadResolve (EmitContext ec
, MethodGroupExpr me
,
5569 ArrayList Arguments
, bool may_fail
,
5572 MethodBase method
= null;
5573 bool method_params
= false;
5574 Type applicable_type
= null;
5576 ArrayList candidates
= new ArrayList ();
5579 // Used to keep a map between the candidate
5580 // and whether it is being considered in its
5581 // normal or expanded form
5583 // false is normal form, true is expanded form
5585 Hashtable candidate_to_form
= null;
5587 if (Arguments
!= null)
5588 arg_count
= Arguments
.Count
;
5590 if ((me
.Name
== "Invoke") &&
5591 TypeManager
.IsDelegateType (me
.DeclaringType
)) {
5592 Error_InvokeOnDelegate (loc
);
5596 MethodBase
[] methods
= me
.Methods
;
5599 // First we construct the set of applicable methods
5601 bool is_sorted
= true;
5602 for (int i
= 0; i
< methods
.Length
; i
++){
5603 Type decl_type
= methods
[i
].DeclaringType
;
5606 // If we have already found an applicable method
5607 // we eliminate all base types (Section 14.5.5.1)
5609 if ((applicable_type
!= null) &&
5610 IsAncestralType (decl_type
, applicable_type
))
5614 // Check if candidate is applicable (section 14.4.2.1)
5615 // Is candidate applicable in normal form?
5617 bool is_applicable
= IsApplicable (
5618 ec
, me
, Arguments
, arg_count
, ref methods
[i
]);
5620 if (!is_applicable
&&
5621 (IsParamsMethodApplicable (
5622 ec
, me
, Arguments
, arg_count
, ref methods
[i
]))) {
5623 MethodBase candidate
= methods
[i
];
5624 if (candidate_to_form
== null)
5625 candidate_to_form
= new PtrHashtable ();
5626 candidate_to_form
[candidate
] = candidate
;
5627 // Candidate is applicable in expanded form
5628 is_applicable
= true;
5634 candidates
.Add (methods
[i
]);
5636 if (applicable_type
== null)
5637 applicable_type
= decl_type
;
5638 else if (applicable_type
!= decl_type
) {
5640 if (IsAncestralType (applicable_type
, decl_type
))
5641 applicable_type
= decl_type
;
5645 int candidate_top
= candidates
.Count
;
5647 if (candidate_top
== 0) {
5649 // Okay so we have failed to find anything so we
5650 // return by providing info about the closest match
5652 for (int i
= 0; i
< methods
.Length
; ++i
) {
5653 MethodBase c
= (MethodBase
) methods
[i
];
5654 ParameterData pd
= GetParameterData (c
);
5656 if (pd
.Count
!= arg_count
)
5659 if (!TypeManager
.InferTypeArguments (ec
, Arguments
, ref c
))
5662 VerifyArgumentsCompat (ec
, Arguments
, arg_count
,
5663 c
, false, null, may_fail
, loc
);
5668 string report_name
= me
.Name
;
5669 if (report_name
== ".ctor")
5670 report_name
= me
.DeclaringType
.ToString ();
5672 for (int i
= 0; i
< methods
.Length
; ++i
) {
5673 MethodBase c
= methods
[i
];
5674 ParameterData pd
= GetParameterData (c
);
5676 if (pd
.Count
!= arg_count
)
5679 if (TypeManager
.InferTypeArguments (ec
, Arguments
, ref c
))
5683 411, loc
, "The type arguments for " +
5684 "method `{0}' cannot be infered from " +
5685 "the usage. Try specifying the type " +
5686 "arguments explicitly.", report_name
);
5690 Error_WrongNumArguments (
5691 loc
, report_name
, arg_count
);
5700 // At this point, applicable_type is _one_ of the most derived types
5701 // in the set of types containing the methods in this MethodGroup.
5702 // Filter the candidates so that they only contain methods from the
5703 // most derived types.
5706 int finalized
= 0; // Number of finalized candidates
5709 // Invariant: applicable_type is a most derived type
5711 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
5712 // eliminating all it's base types. At the same time, we'll also move
5713 // every unrelated type to the end of the array, and pick the next
5714 // 'applicable_type'.
5716 Type next_applicable_type
= null;
5717 int j
= finalized
; // where to put the next finalized candidate
5718 int k
= finalized
; // where to put the next undiscarded candidate
5719 for (int i
= finalized
; i
< candidate_top
; ++i
) {
5720 Type decl_type
= ((MethodBase
) candidates
[i
]).DeclaringType
;
5722 if (decl_type
== applicable_type
) {
5723 candidates
[k
++] = candidates
[j
];
5724 candidates
[j
++] = candidates
[i
];
5728 if (IsAncestralType (decl_type
, applicable_type
))
5731 if (next_applicable_type
!= null &&
5732 IsAncestralType (decl_type
, next_applicable_type
))
5735 candidates
[k
++] = candidates
[i
];
5737 if (next_applicable_type
== null ||
5738 IsAncestralType (next_applicable_type
, decl_type
))
5739 next_applicable_type
= decl_type
;
5742 applicable_type
= next_applicable_type
;
5745 } while (applicable_type
!= null);
5749 // Now we actually find the best method
5752 method
= (MethodBase
) candidates
[0];
5753 method_params
= candidate_to_form
!= null && candidate_to_form
.Contains (method
);
5754 for (int ix
= 1; ix
< candidate_top
; ix
++){
5755 MethodBase candidate
= (MethodBase
) candidates
[ix
];
5756 bool cand_params
= candidate_to_form
!= null && candidate_to_form
.Contains (candidate
);
5758 if (BetterFunction (ec
, Arguments
, arg_count
,
5759 candidate
, cand_params
,
5760 method
, method_params
, loc
)) {
5762 method_params
= cand_params
;
5767 // Now check that there are no ambiguities i.e the selected method
5768 // should be better than all the others
5770 bool ambiguous
= false;
5771 for (int ix
= 0; ix
< candidate_top
; ix
++){
5772 MethodBase candidate
= (MethodBase
) candidates
[ix
];
5774 if (candidate
== method
)
5777 bool cand_params
= candidate_to_form
!= null && candidate_to_form
.Contains (candidate
);
5778 if (!BetterFunction (ec
, Arguments
, arg_count
,
5779 method
, method_params
,
5780 candidate
, cand_params
,
5782 Report
.SymbolRelatedToPreviousError (candidate
);
5788 Report
.SymbolRelatedToPreviousError (method
);
5789 Report
.Error (121, loc
, "Ambiguous call when selecting function due to implicit casts");
5794 // And now check if the arguments are all
5795 // compatible, perform conversions if
5796 // necessary etc. and return if everything is
5799 if (!VerifyArgumentsCompat (ec
, Arguments
, arg_count
, method
,
5800 method_params
, null, may_fail
, loc
))
5806 static void Error_WrongNumArguments (Location loc
, String name
, int arg_count
)
5808 Report
.Error (1501, loc
,
5809 "No overload for method `" + name
+ "' takes `" +
5810 arg_count
+ "' arguments");
5813 static void Error_InvokeOnDelegate (Location loc
)
5815 Report
.Error (1533, loc
,
5816 "Invoke cannot be called directly on a delegate");
5819 static void Error_InvalidArguments (Location loc
, int idx
, MethodBase method
,
5820 Type delegate_type
, string arg_sig
, string par_desc
)
5822 if (delegate_type
== null)
5823 Report
.Error (1502, loc
,
5824 "The best overloaded match for method '" +
5825 FullMethodDesc (method
) +
5826 "' has some invalid arguments");
5828 Report
.Error (1594, loc
,
5829 "Delegate '" + delegate_type
.ToString () +
5830 "' has some invalid arguments.");
5831 Report
.Error (1503, loc
,
5832 String
.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
5833 idx
, arg_sig
, par_desc
));
5836 public static bool VerifyArgumentsCompat (EmitContext ec
, ArrayList Arguments
,
5837 int arg_count
, MethodBase method
,
5838 bool chose_params_expanded
,
5839 Type delegate_type
, bool may_fail
,
5842 ParameterData pd
= GetParameterData (method
);
5843 int pd_count
= pd
.Count
;
5845 for (int j
= 0; j
< arg_count
; j
++) {
5846 Argument a
= (Argument
) Arguments
[j
];
5847 Expression a_expr
= a
.Expr
;
5848 Type parameter_type
= pd
.ParameterType (j
);
5849 Parameter
.Modifier pm
= pd
.ParameterModifier (j
);
5851 if (pm
== Parameter
.Modifier
.PARAMS
){
5852 if ((pm
& ~Parameter
.Modifier
.PARAMS
) != a
.GetParameterModifier ()) {
5854 Error_InvalidArguments (
5855 loc
, j
, method
, delegate_type
,
5856 Argument
.FullDesc (a
), pd
.ParameterDesc (j
));
5860 if (chose_params_expanded
)
5861 parameter_type
= TypeManager
.GetElementType (parameter_type
);
5862 } else if (pm
== Parameter
.Modifier
.ARGLIST
){
5868 if (pd
.ParameterModifier (j
) != a
.GetParameterModifier ()){
5870 Error_InvalidArguments (
5871 loc
, j
, method
, delegate_type
,
5872 Argument
.FullDesc (a
), pd
.ParameterDesc (j
));
5880 if (!TypeManager
.IsEqual (a
.Type
, parameter_type
)){
5883 conv
= Convert
.WideningConversion (ec
, a_expr
, parameter_type
, loc
);
5887 Error_InvalidArguments (
5888 loc
, j
, method
, delegate_type
,
5889 Argument
.FullDesc (a
), pd
.ParameterDesc (j
));
5894 // Update the argument with the implicit conversion
5900 if (parameter_type
.IsPointer
){
5907 Parameter
.Modifier a_mod
= a
.GetParameterModifier () &
5908 unchecked (~
(Parameter
.Modifier
.OUT
| Parameter
.Modifier
.REF
));
5909 Parameter
.Modifier p_mod
= pd
.ParameterModifier (j
) &
5910 unchecked (~
(Parameter
.Modifier
.OUT
| Parameter
.Modifier
.REF
));
5912 if (a_mod
!= p_mod
&&
5913 pd
.ParameterModifier (pd_count
- 1) != Parameter
.Modifier
.PARAMS
) {
5915 Report
.Error (1502, loc
,
5916 "The best overloaded match for method '" + FullMethodDesc (method
)+
5917 "' has some invalid arguments");
5918 Report
.Error (1503, loc
,
5919 "Argument " + (j
+1) +
5920 ": Cannot convert from '" + Argument
.FullDesc (a
)
5921 + "' to '" + pd
.ParameterDesc (j
) + "'");
5931 public override Expression
DoResolve (EmitContext ec
)
5934 // First, resolve the expression that is used to
5935 // trigger the invocation
5937 if (expr
is ConstructedType
)
5938 expr
= ((ConstructedType
) expr
).GetSimpleName (ec
);
5940 expr
= expr
.Resolve (ec
, ResolveFlags
.VariableOrValue
| ResolveFlags
.MethodGroup
);
5944 if (!(expr
is MethodGroupExpr
)) {
5945 Type expr_type
= expr
.Type
;
5947 if (expr_type
!= null){
5948 bool IsDelegate
= TypeManager
.IsDelegateType (expr_type
);
5950 return (new DelegateInvocation (
5951 this.expr
, Arguments
, loc
)).Resolve (ec
);
5955 if (!(expr
is MethodGroupExpr
)){
5956 expr
.Error_UnexpectedKind (ResolveFlags
.MethodGroup
, loc
);
5961 // Next, evaluate all the expressions in the argument list
5963 if (Arguments
!= null){
5964 foreach (Argument a
in Arguments
){
5965 if (!a
.Resolve (ec
, loc
))
5970 MethodGroupExpr mg
= (MethodGroupExpr
) expr
;
5971 method
= OverloadResolve (ec
, mg
, Arguments
, false, loc
);
5976 MethodInfo mi
= method
as MethodInfo
;
5978 type
= TypeManager
.TypeToCoreType (mi
.ReturnType
);
5979 if (!mi
.IsStatic
&& !mg
.IsExplicitImpl
&& (mg
.InstanceExpression
== null)) {
5980 SimpleName
.Error_ObjectRefRequired (ec
, loc
, mi
.Name
);
5984 Expression iexpr
= mg
.InstanceExpression
;
5985 if (mi
.IsStatic
&& (iexpr
!= null) && !(iexpr
is This
)) {
5986 if (mg
.IdenticalTypeName
)
5987 mg
.InstanceExpression
= null;
5989 MemberAccess
.error176 (loc
, mi
.Name
);
5995 if (type
.IsPointer
){
6003 // Only base will allow this invocation to happen.
6005 if (mg
.IsBase
&& method
.IsAbstract
){
6006 Report
.Error (205, loc
, "Cannot call an abstract base member: " +
6007 FullMethodDesc (method
));
6011 if (method
.Name
== "Finalize" && Arguments
== null) {
6013 Report
.Error (250, loc
, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
6015 Report
.Error (245, loc
, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
6019 if ((method
.Attributes
& MethodAttributes
.SpecialName
) != 0){
6020 if (TypeManager
.LookupDeclSpace (method
.DeclaringType
) != null || TypeManager
.IsSpecialMethod (method
)) {
6021 Report
.Error (571, loc
, TypeManager
.CSharpSignature (method
) + ": can not call operator or accessor");
6026 if (mg
.InstanceExpression
!= null)
6027 mg
.InstanceExpression
.CheckMarshallByRefAccess (ec
.ContainerType
);
6029 eclass
= ExprClass
.Value
;
6034 // Emits the list of arguments as an array
6036 static void EmitParams (EmitContext ec
, int idx
, ArrayList arguments
)
6038 ILGenerator ig
= ec
.ig
;
6039 int count
= arguments
.Count
- idx
;
6040 Argument a
= (Argument
) arguments
[idx
];
6041 Type t
= a
.Expr
.Type
;
6043 IntConstant
.EmitInt (ig
, count
);
6044 ig
.Emit (OpCodes
.Newarr
, TypeManager
.TypeToCoreType (t
));
6046 int top
= arguments
.Count
;
6047 for (int j
= idx
; j
< top
; j
++){
6048 a
= (Argument
) arguments
[j
];
6050 ig
.Emit (OpCodes
.Dup
);
6051 IntConstant
.EmitInt (ig
, j
- idx
);
6053 bool is_stobj
, has_type_arg
;
6054 OpCode op
= ArrayAccess
.GetStoreOpcode (t
, out is_stobj
, out has_type_arg
);
6056 ig
.Emit (OpCodes
.Ldelema
, t
);
6068 /// Emits a list of resolved Arguments that are in the arguments
6071 /// The MethodBase argument might be null if the
6072 /// emission of the arguments is known not to contain
6073 /// a `params' field (for example in constructors or other routines
6074 /// that keep their arguments in this structure)
6076 /// if `dup_args' is true, a copy of the arguments will be left
6077 /// on the stack. If `dup_args' is true, you can specify `this_arg'
6078 /// which will be duplicated before any other args. Only EmitCall
6079 /// should be using this interface.
6081 public static void EmitArguments (EmitContext ec
, MethodBase mb
, ArrayList arguments
, bool dup_args
, LocalTemporary this_arg
)
6085 pd
= GetParameterData (mb
);
6089 LocalTemporary
[] temps
= null;
6092 temps
= new LocalTemporary
[arguments
.Count
];
6095 // If we are calling a params method with no arguments, special case it
6097 if (arguments
== null){
6098 if (pd
!= null && pd
.Count
> 0 &&
6099 pd
.ParameterModifier (0) == Parameter
.Modifier
.PARAMS
){
6100 ILGenerator ig
= ec
.ig
;
6102 IntConstant
.EmitInt (ig
, 0);
6103 ig
.Emit (OpCodes
.Newarr
, TypeManager
.GetElementType (pd
.ParameterType (0)));
6109 int top
= arguments
.Count
;
6111 for (int i
= 0; i
< top
; i
++){
6112 Argument a
= (Argument
) arguments
[i
];
6115 if (pd
.ParameterModifier (i
) == Parameter
.Modifier
.PARAMS
){
6117 // Special case if we are passing the same data as the
6118 // params argument, do not put it in an array.
6120 if (pd
.ParameterType (i
) == a
.Type
)
6123 EmitParams (ec
, i
, arguments
);
6130 ec
.ig
.Emit (OpCodes
.Dup
);
6131 (temps
[i
] = new LocalTemporary (ec
, a
.Type
)).Store (ec
);
6136 if (this_arg
!= null)
6139 for (int i
= 0; i
< top
; i
++)
6140 temps
[i
].Emit (ec
);
6143 if (pd
!= null && pd
.Count
> top
&&
6144 pd
.ParameterModifier (top
) == Parameter
.Modifier
.PARAMS
){
6145 ILGenerator ig
= ec
.ig
;
6147 IntConstant
.EmitInt (ig
, 0);
6148 ig
.Emit (OpCodes
.Newarr
, TypeManager
.GetElementType (pd
.ParameterType (top
)));
6152 static Type
[] GetVarargsTypes (EmitContext ec
, MethodBase mb
,
6153 ArrayList arguments
)
6155 ParameterData pd
= GetParameterData (mb
);
6157 if (arguments
== null)
6158 return new Type
[0];
6160 Argument a
= (Argument
) arguments
[pd
.Count
- 1];
6161 Arglist list
= (Arglist
) a
.Expr
;
6163 return list
.ArgumentTypes
;
6167 /// This checks the ConditionalAttribute on the method
6169 static bool IsMethodExcluded (MethodBase method
, EmitContext ec
)
6171 if (method
.IsConstructor
)
6174 IMethodData md
= TypeManager
.GetMethod (method
);
6176 return md
.IsExcluded (ec
);
6178 // For some methods (generated by delegate class) GetMethod returns null
6179 // because they are not included in builder_to_method table
6180 if (method
.DeclaringType
is TypeBuilder
)
6183 return AttributeTester
.IsConditionalMethodExcluded (method
);
6187 /// is_base tells whether we want to force the use of the `call'
6188 /// opcode instead of using callvirt. Call is required to call
6189 /// a specific method, while callvirt will always use the most
6190 /// recent method in the vtable.
6192 /// is_static tells whether this is an invocation on a static method
6194 /// instance_expr is an expression that represents the instance
6195 /// it must be non-null if is_static is false.
6197 /// method is the method to invoke.
6199 /// Arguments is the list of arguments to pass to the method or constructor.
6201 public static void EmitCall (EmitContext ec
, bool is_base
,
6202 bool is_static
, Expression instance_expr
,
6203 MethodBase method
, ArrayList Arguments
, Location loc
)
6205 EmitCall (ec
, is_base
, is_static
, instance_expr
, method
, Arguments
, loc
, false, false);
6208 // `dup_args' leaves an extra copy of the arguments on the stack
6209 // `omit_args' does not leave any arguments at all.
6210 // So, basically, you could make one call with `dup_args' set to true,
6211 // and then another with `omit_args' set to true, and the two calls
6212 // would have the same set of arguments. However, each argument would
6213 // only have been evaluated once.
6214 public static void EmitCall (EmitContext ec
, bool is_base
,
6215 bool is_static
, Expression instance_expr
,
6216 MethodBase method
, ArrayList Arguments
, Location loc
,
6217 bool dup_args
, bool omit_args
)
6219 ILGenerator ig
= ec
.ig
;
6220 bool struct_call
= false;
6221 bool this_call
= false;
6222 LocalTemporary this_arg
= null;
6224 Type decl_type
= method
.DeclaringType
;
6226 if (!RootContext
.StdLib
) {
6227 // Replace any calls to the system's System.Array type with calls to
6228 // the newly created one.
6229 if (method
== TypeManager
.system_int_array_get_length
)
6230 method
= TypeManager
.int_array_get_length
;
6231 else if (method
== TypeManager
.system_int_array_get_rank
)
6232 method
= TypeManager
.int_array_get_rank
;
6233 else if (method
== TypeManager
.system_object_array_clone
)
6234 method
= TypeManager
.object_array_clone
;
6235 else if (method
== TypeManager
.system_int_array_get_length_int
)
6236 method
= TypeManager
.int_array_get_length_int
;
6237 else if (method
== TypeManager
.system_int_array_get_lower_bound_int
)
6238 method
= TypeManager
.int_array_get_lower_bound_int
;
6239 else if (method
== TypeManager
.system_int_array_get_upper_bound_int
)
6240 method
= TypeManager
.int_array_get_upper_bound_int
;
6241 else if (method
== TypeManager
.system_void_array_copyto_array_int
)
6242 method
= TypeManager
.void_array_copyto_array_int
;
6245 if (ec
.TestObsoleteMethodUsage
) {
6247 // This checks ObsoleteAttribute on the method and on the declaring type
6249 ObsoleteAttribute oa
= AttributeTester
.GetMethodObsoleteAttribute (method
);
6251 AttributeTester
.Report_ObsoleteMessage (oa
, TypeManager
.CSharpSignature (method
), loc
);
6253 oa
= AttributeTester
.GetObsoleteAttribute (method
.DeclaringType
);
6255 AttributeTester
.Report_ObsoleteMessage (oa
, method
.DeclaringType
.FullName
, loc
);
6259 if (IsMethodExcluded (method
, ec
))
6263 this_call
= instance_expr
== null;
6264 if (decl_type
.IsValueType
|| (!this_call
&& instance_expr
.Type
.IsValueType
))
6268 // If this is ourselves, push "this"
6273 ig
.Emit (OpCodes
.Ldarg_0
);
6276 Type iexpr_type
= instance_expr
.Type
;
6279 // Push the instance expression
6281 if (TypeManager
.IsValueType (iexpr_type
)) {
6283 // Special case: calls to a function declared in a
6284 // reference-type with a value-type argument need
6285 // to have their value boxed.
6286 if (decl_type
.IsValueType
||
6287 iexpr_type
.IsGenericParameter
) {
6289 // If the expression implements IMemoryLocation, then
6290 // we can optimize and use AddressOf on the
6293 // If not we have to use some temporary storage for
6295 if (instance_expr
is IMemoryLocation
) {
6296 ((IMemoryLocation
)instance_expr
).
6297 AddressOf (ec
, AddressOp
.LoadStore
);
6299 LocalTemporary temp
= new LocalTemporary (ec
, iexpr_type
);
6300 instance_expr
.Emit (ec
);
6302 temp
.AddressOf (ec
, AddressOp
.Load
);
6305 // avoid the overhead of doing this all the time.
6307 t
= TypeManager
.GetReferenceType (iexpr_type
);
6309 instance_expr
.Emit (ec
);
6310 ig
.Emit (OpCodes
.Box
, instance_expr
.Type
);
6311 t
= TypeManager
.object_type
;
6314 instance_expr
.Emit (ec
);
6315 t
= instance_expr
.Type
;
6320 this_arg
= new LocalTemporary (ec
, t
);
6321 ig
.Emit (OpCodes
.Dup
);
6322 this_arg
.Store (ec
);
6328 EmitArguments (ec
, method
, Arguments
, dup_args
, this_arg
);
6330 if ((instance_expr
!= null) && (instance_expr
.Type
.IsGenericParameter
))
6331 ig
.Emit (OpCodes
.Constrained
, instance_expr
.Type
);
6334 if (is_static
|| struct_call
|| is_base
|| (this_call
&& !method
.IsVirtual
))
6335 call_op
= OpCodes
.Call
;
6337 call_op
= OpCodes
.Callvirt
;
6339 if ((method
.CallingConvention
& CallingConventions
.VarArgs
) != 0) {
6340 Type
[] varargs_types
= GetVarargsTypes (ec
, method
, Arguments
);
6341 ig
.EmitCall (call_op
, (MethodInfo
) method
, varargs_types
);
6348 // and DoFoo is not virtual, you can omit the callvirt,
6349 // because you don't need the null checking behavior.
6351 if (method
is MethodInfo
)
6352 ig
.Emit (call_op
, (MethodInfo
) method
);
6354 ig
.Emit (call_op
, (ConstructorInfo
) method
);
6357 public override void Emit (EmitContext ec
)
6359 MethodGroupExpr mg
= (MethodGroupExpr
) this.expr
;
6361 EmitCall (ec
, mg
.IsBase
, method
.IsStatic
, mg
.InstanceExpression
, method
, Arguments
, loc
);
6364 public override void EmitStatement (EmitContext ec
)
6369 // Pop the return value if there is one
6371 if (method
is MethodInfo
){
6372 Type ret
= ((MethodInfo
)method
).ReturnType
;
6373 if (TypeManager
.TypeToCoreType (ret
) != TypeManager
.void_type
)
6374 ec
.ig
.Emit (OpCodes
.Pop
);
6379 public class InvocationOrCast
: ExpressionStatement
6382 Expression argument
;
6384 public InvocationOrCast (Expression expr
, Expression argument
, Location loc
)
6387 this.argument
= argument
;
6391 public override Expression
DoResolve (EmitContext ec
)
6394 // First try to resolve it as a cast.
6396 TypeExpr te
= expr
.ResolveAsTypeStep (ec
) as TypeExpr
;
6397 if ((te
!= null) && (te
.eclass
== ExprClass
.Type
)) {
6398 Cast cast
= new Cast (te
, argument
, loc
);
6399 return cast
.Resolve (ec
);
6403 // This can either be a type or a delegate invocation.
6404 // Let's just resolve it and see what we'll get.
6406 expr
= expr
.Resolve (ec
, ResolveFlags
.Type
| ResolveFlags
.VariableOrValue
);
6411 // Ok, so it's a Cast.
6413 if (expr
.eclass
== ExprClass
.Type
) {
6414 Cast cast
= new Cast (new TypeExpression (expr
.Type
, loc
), argument
, loc
);
6415 return cast
.Resolve (ec
);
6419 // It's a delegate invocation.
6421 if (!TypeManager
.IsDelegateType (expr
.Type
)) {
6422 Error (149, "Method name expected");
6426 ArrayList args
= new ArrayList ();
6427 args
.Add (new Argument (argument
, Argument
.AType
.Expression
));
6428 DelegateInvocation invocation
= new DelegateInvocation (expr
, args
, loc
);
6429 return invocation
.Resolve (ec
);
6434 Error (201, "Only assignment, call, increment, decrement and new object " +
6435 "expressions can be used as a statement");
6438 public override ExpressionStatement
ResolveStatement (EmitContext ec
)
6441 // First try to resolve it as a cast.
6443 TypeExpr te
= expr
.ResolveAsTypeStep (ec
) as TypeExpr
;
6444 if ((te
!= null) && (te
.eclass
== ExprClass
.Type
)) {
6450 // This can either be a type or a delegate invocation.
6451 // Let's just resolve it and see what we'll get.
6453 expr
= expr
.Resolve (ec
, ResolveFlags
.Type
| ResolveFlags
.VariableOrValue
);
6454 if ((expr
== null) || (expr
.eclass
== ExprClass
.Type
)) {
6460 // It's a delegate invocation.
6462 if (!TypeManager
.IsDelegateType (expr
.Type
)) {
6463 Error (149, "Method name expected");
6467 ArrayList args
= new ArrayList ();
6468 args
.Add (new Argument (argument
, Argument
.AType
.Expression
));
6469 DelegateInvocation invocation
= new DelegateInvocation (expr
, args
, loc
);
6470 return invocation
.ResolveStatement (ec
);
6473 public override void Emit (EmitContext ec
)
6475 throw new Exception ("Cannot happen");
6478 public override void EmitStatement (EmitContext ec
)
6480 throw new Exception ("Cannot happen");
6485 // This class is used to "disable" the code generation for the
6486 // temporary variable when initializing value types.
6488 class EmptyAddressOf
: EmptyExpression
, IMemoryLocation
{
6489 public void AddressOf (EmitContext ec
, AddressOp Mode
)
6496 /// Implements the new expression
6498 public class New
: ExpressionStatement
, IMemoryLocation
{
6499 public readonly ArrayList Arguments
;
6502 // During bootstrap, it contains the RequestedType,
6503 // but if `type' is not null, it *might* contain a NewDelegate
6504 // (because of field multi-initialization)
6506 public Expression RequestedType
;
6508 MethodBase method
= null;
6511 // If set, the new expression is for a value_target, and
6512 // we will not leave anything on the stack.
6514 Expression value_target
;
6515 bool value_target_set
= false;
6516 bool is_type_parameter
= false;
6518 public New (Expression requested_type
, ArrayList arguments
, Location l
)
6520 RequestedType
= requested_type
;
6521 Arguments
= arguments
;
6525 public bool SetValueTypeVariable (Expression
value)
6527 value_target
= value;
6528 value_target_set
= true;
6529 if (!(value_target
is IMemoryLocation
)){
6530 Error_UnexpectedKind ("variable", loc
);
6537 // This function is used to disable the following code sequence for
6538 // value type initialization:
6540 // AddressOf (temporary)
6544 // Instead the provide will have provided us with the address on the
6545 // stack to store the results.
6547 static Expression MyEmptyExpression
;
6549 public void DisableTemporaryValueType ()
6551 if (MyEmptyExpression
== null)
6552 MyEmptyExpression
= new EmptyAddressOf ();
6555 // To enable this, look into:
6556 // test-34 and test-89 and self bootstrapping.
6558 // For instance, we can avoid a copy by using `newobj'
6559 // instead of Call + Push-temp on value types.
6560 // value_target = MyEmptyExpression;
6563 public override Expression
DoResolve (EmitContext ec
)
6566 // The New DoResolve might be called twice when initializing field
6567 // expressions (see EmitFieldInitializers, the call to
6568 // GetInitializerExpression will perform a resolve on the expression,
6569 // and later the assign will trigger another resolution
6571 // This leads to bugs (#37014)
6574 if (RequestedType
is NewDelegate
)
6575 return RequestedType
;
6579 TypeExpr texpr
= RequestedType
.ResolveAsTypeTerminal (ec
);
6587 CheckObsoleteAttribute (type
);
6589 bool IsDelegate
= TypeManager
.IsDelegateType (type
);
6592 RequestedType
= (new NewDelegate (type
, Arguments
, loc
)).Resolve (ec
);
6593 if (RequestedType
!= null)
6594 if (!(RequestedType
is DelegateCreation
))
6595 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType
.GetType ());
6596 return RequestedType
;
6599 if (type
.IsGenericParameter
) {
6600 if (!TypeManager
.HasConstructorConstraint (type
)) {
6601 Error (304, String
.Format (
6602 "Cannot create an instance of the " +
6603 "variable type '{0}' because it " +
6604 "doesn't have the new() constraint",
6609 if ((Arguments
!= null) && (Arguments
.Count
!= 0)) {
6610 Error (417, String
.Format (
6611 "`{0}': cannot provide arguments " +
6612 "when creating an instance of a " +
6613 "variable type.", type
));
6617 is_type_parameter
= true;
6618 eclass
= ExprClass
.Value
;
6622 if (type
.IsInterface
|| type
.IsAbstract
){
6623 Error (144, "It is not possible to create instances of interfaces or abstract classes");
6627 if (type
.IsAbstract
&& type
.IsSealed
) {
6628 Report
.Error (712, loc
, "Cannot create an instance of the static class '{0}'", TypeManager
.CSharpName (type
));
6632 bool is_struct
= type
.IsValueType
;
6633 eclass
= ExprClass
.Value
;
6636 // SRE returns a match for .ctor () on structs (the object constructor),
6637 // so we have to manually ignore it.
6639 if (is_struct
&& Arguments
== null)
6643 ml
= MemberLookupFinal (ec
, type
, type
, ".ctor",
6644 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
6645 MemberTypes
.Constructor
,
6646 AllBindingFlags
| BindingFlags
.DeclaredOnly
, loc
);
6651 if (! (ml
is MethodGroupExpr
)){
6653 ml
.Error_UnexpectedKind ("method group", loc
);
6659 if (Arguments
!= null){
6660 foreach (Argument a
in Arguments
){
6661 if (!a
.Resolve (ec
, loc
))
6666 method
= Invocation
.OverloadResolve (
6667 ec
, (MethodGroupExpr
) ml
, Arguments
, true, loc
);
6671 if (method
== null) {
6672 if (almostMatchedMembers
.Count
!= 0) {
6673 MemberLookupFailed (ec
, type
, type
, ".ctor", null, loc
);
6677 if (!is_struct
|| Arguments
.Count
> 0) {
6678 Error (1501, String
.Format (
6679 "New invocation: Can not find a constructor in `{0}' for this argument list",
6680 TypeManager
.CSharpName (type
)));
6688 bool DoEmitTypeParameter (EmitContext ec
)
6690 ILGenerator ig
= ec
.ig
;
6692 ig
.Emit (OpCodes
.Ldtoken
, type
);
6693 ig
.Emit (OpCodes
.Call
, TypeManager
.system_type_get_type_from_handle
);
6694 ig
.Emit (OpCodes
.Call
, TypeManager
.activator_create_instance
);
6695 ig
.Emit (OpCodes
.Unbox_Any
, type
);
6701 // This DoEmit can be invoked in two contexts:
6702 // * As a mechanism that will leave a value on the stack (new object)
6703 // * As one that wont (init struct)
6705 // You can control whether a value is required on the stack by passing
6706 // need_value_on_stack. The code *might* leave a value on the stack
6707 // so it must be popped manually
6709 // If we are dealing with a ValueType, we have a few
6710 // situations to deal with:
6712 // * The target is a ValueType, and we have been provided
6713 // the instance (this is easy, we are being assigned).
6715 // * The target of New is being passed as an argument,
6716 // to a boxing operation or a function that takes a
6719 // In this case, we need to create a temporary variable
6720 // that is the argument of New.
6722 // Returns whether a value is left on the stack
6724 bool DoEmit (EmitContext ec
, bool need_value_on_stack
)
6726 bool is_value_type
= TypeManager
.IsValueType (type
);
6727 ILGenerator ig
= ec
.ig
;
6732 // Allow DoEmit() to be called multiple times.
6733 // We need to create a new LocalTemporary each time since
6734 // you can't share LocalBuilders among ILGeneators.
6735 if (!value_target_set
)
6736 value_target
= new LocalTemporary (ec
, type
);
6738 ml
= (IMemoryLocation
) value_target
;
6739 ml
.AddressOf (ec
, AddressOp
.Store
);
6743 Invocation
.EmitArguments (ec
, method
, Arguments
, false, null);
6747 ig
.Emit (OpCodes
.Initobj
, type
);
6749 ig
.Emit (OpCodes
.Call
, (ConstructorInfo
) method
);
6750 if (need_value_on_stack
){
6751 value_target
.Emit (ec
);
6756 ig
.Emit (OpCodes
.Newobj
, (ConstructorInfo
) method
);
6761 public override void Emit (EmitContext ec
)
6763 if (is_type_parameter
)
6764 DoEmitTypeParameter (ec
);
6769 public override void EmitStatement (EmitContext ec
)
6771 if (is_type_parameter
)
6772 throw new InvalidOperationException ();
6774 if (DoEmit (ec
, false))
6775 ec
.ig
.Emit (OpCodes
.Pop
);
6778 public void AddressOf (EmitContext ec
, AddressOp Mode
)
6780 if (is_type_parameter
)
6781 throw new InvalidOperationException ();
6783 if (!type
.IsValueType
){
6785 // We throw an exception. So far, I believe we only need to support
6787 // foreach (int j in new StructType ())
6790 throw new Exception ("AddressOf should not be used for classes");
6793 if (!value_target_set
)
6794 value_target
= new LocalTemporary (ec
, type
);
6796 IMemoryLocation ml
= (IMemoryLocation
) value_target
;
6797 ml
.AddressOf (ec
, AddressOp
.Store
);
6799 Invocation
.EmitArguments (ec
, method
, Arguments
, false, null);
6802 ec
.ig
.Emit (OpCodes
.Initobj
, type
);
6804 ec
.ig
.Emit (OpCodes
.Call
, (ConstructorInfo
) method
);
6806 ((IMemoryLocation
) value_target
).AddressOf (ec
, Mode
);
6811 /// 14.5.10.2: Represents an array creation expression.
6815 /// There are two possible scenarios here: one is an array creation
6816 /// expression that specifies the dimensions and optionally the
6817 /// initialization data and the other which does not need dimensions
6818 /// specified but where initialization data is mandatory.
6820 public class ArrayCreation
: Expression
{
6821 Expression requested_base_type
;
6822 ArrayList initializers
;
6825 // The list of Argument types.
6826 // This is used to construct the `newarray' or constructor signature
6828 ArrayList arguments
;
6831 // Method used to create the array object.
6833 MethodBase new_method
= null;
6835 Type array_element_type
;
6836 Type underlying_type
;
6837 bool is_one_dimensional
= false;
6838 bool is_builtin_type
= false;
6839 bool expect_initializers
= false;
6840 int num_arguments
= 0;
6844 ArrayList array_data
;
6849 // The number of array initializers that we can handle
6850 // via the InitializeArray method - through EmitStaticInitializers
6852 int num_automatic_initializers
;
6854 const int max_automatic_initializers
= 6;
6856 public ArrayCreation (Expression requested_base_type
, ArrayList exprs
, string rank
, ArrayList initializers
, Location l
)
6858 this.requested_base_type
= requested_base_type
;
6859 this.initializers
= initializers
;
6863 arguments
= new ArrayList ();
6865 foreach (Expression e
in exprs
) {
6866 arguments
.Add (new Argument (e
, Argument
.AType
.Expression
));
6871 public ArrayCreation (Expression requested_base_type
, string rank
, ArrayList initializers
, Location l
)
6873 this.requested_base_type
= requested_base_type
;
6874 this.initializers
= initializers
;
6878 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
6880 //string tmp = rank.Substring (rank.LastIndexOf ('['));
6882 //dimensions = tmp.Length - 1;
6883 expect_initializers
= true;
6886 public Expression
FormArrayType (Expression base_type
, int idx_count
, string rank
)
6888 StringBuilder sb
= new StringBuilder (rank
);
6891 for (int i
= 1; i
< idx_count
; i
++)
6896 return new ComposedCast (base_type
, sb
.ToString (), loc
);
6899 void Error_IncorrectArrayInitializer ()
6901 Error (178, "Incorrectly structured array initializer");
6904 public bool CheckIndices (EmitContext ec
, ArrayList probe
, int idx
, bool specified_dims
)
6906 if (specified_dims
) {
6907 Argument a
= (Argument
) arguments
[idx
];
6909 if (!a
.Resolve (ec
, loc
))
6912 if (!(a
.Expr
is Constant
)) {
6913 Error (150, "A constant value is expected");
6917 int value = (int) ((Constant
) a
.Expr
).GetValue ();
6919 if (value != probe
.Count
) {
6920 Error_IncorrectArrayInitializer ();
6924 bounds
[idx
] = value;
6927 int child_bounds
= -1;
6928 foreach (object o
in probe
) {
6929 if (o
is ArrayList
) {
6930 int current_bounds
= ((ArrayList
) o
).Count
;
6932 if (child_bounds
== -1)
6933 child_bounds
= current_bounds
;
6935 else if (child_bounds
!= current_bounds
){
6936 Error_IncorrectArrayInitializer ();
6939 if (specified_dims
&& (idx
+ 1 >= arguments
.Count
)){
6940 Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
6944 bool ret
= CheckIndices (ec
, (ArrayList
) o
, idx
+ 1, specified_dims
);
6948 if (child_bounds
!= -1){
6949 Error_IncorrectArrayInitializer ();
6953 Expression tmp
= (Expression
) o
;
6954 tmp
= tmp
.Resolve (ec
);
6958 // Console.WriteLine ("I got: " + tmp);
6959 // Handle initialization from vars, fields etc.
6961 Expression conv
= Convert
.WideningConversionRequired (
6962 ec
, tmp
, underlying_type
, loc
);
6967 if (conv
is StringConstant
|| conv
is DecimalConstant
|| conv
is NullCast
) {
6968 // These are subclasses of Constant that can appear as elements of an
6969 // array that cannot be statically initialized (with num_automatic_initializers
6970 // > max_automatic_initializers), so num_automatic_initializers should be left as zero.
6971 array_data
.Add (conv
);
6972 } else if (conv
is Constant
) {
6973 // These are the types of Constant that can appear in arrays that can be
6974 // statically allocated.
6975 array_data
.Add (conv
);
6976 num_automatic_initializers
++;
6978 array_data
.Add (conv
);
6985 public void UpdateIndices (EmitContext ec
)
6988 for (ArrayList probe
= initializers
; probe
!= null;) {
6989 if (probe
.Count
> 0 && probe
[0] is ArrayList
) {
6990 Expression e
= new IntConstant (probe
.Count
);
6991 arguments
.Add (new Argument (e
, Argument
.AType
.Expression
));
6993 bounds
[i
++] = probe
.Count
;
6995 probe
= (ArrayList
) probe
[0];
6998 Expression e
= new IntConstant (probe
.Count
);
6999 arguments
.Add (new Argument (e
, Argument
.AType
.Expression
));
7001 bounds
[i
++] = probe
.Count
;
7008 public bool ValidateInitializers (EmitContext ec
, Type array_type
)
7010 if (initializers
== null) {
7011 if (expect_initializers
)
7017 if (underlying_type
== null)
7021 // We use this to store all the date values in the order in which we
7022 // will need to store them in the byte blob later
7024 array_data
= new ArrayList ();
7025 bounds
= new Hashtable ();
7029 if (arguments
!= null) {
7030 ret
= CheckIndices (ec
, initializers
, 0, true);
7033 arguments
= new ArrayList ();
7035 ret
= CheckIndices (ec
, initializers
, 0, false);
7042 if (arguments
.Count
!= dimensions
) {
7043 Error_IncorrectArrayInitializer ();
7052 // Converts `source' to an int, uint, long or ulong.
7054 Expression
ExpressionToArrayArgument (EmitContext ec
, Expression source
)
7058 bool old_checked
= ec
.CheckState
;
7059 ec
.CheckState
= true;
7061 target
= Convert
.WideningConversion (ec
, source
, TypeManager
.int32_type
, loc
);
7062 if (target
== null){
7063 target
= Convert
.WideningConversion (ec
, source
, TypeManager
.uint32_type
, loc
);
7064 if (target
== null){
7065 target
= Convert
.WideningConversion (ec
, source
, TypeManager
.int64_type
, loc
);
7066 if (target
== null){
7067 target
= Convert
.WideningConversion (ec
, source
, TypeManager
.uint64_type
, loc
);
7069 Convert
.Error_CannotWideningConversion (loc
, source
.Type
, TypeManager
.int32_type
);
7073 ec
.CheckState
= old_checked
;
7076 // Only positive constants are allowed at compile time
7078 if (target
is Constant
){
7079 if (target
is IntConstant
){
7080 if (((IntConstant
) target
).Value
< 0){
7081 Expression
.Error_NegativeArrayIndex (loc
);
7086 if (target
is LongConstant
){
7087 if (((LongConstant
) target
).Value
< 0){
7088 Expression
.Error_NegativeArrayIndex (loc
);
7099 // Creates the type of the array
7101 bool LookupType (EmitContext ec
)
7103 StringBuilder array_qualifier
= new StringBuilder (rank
);
7106 // `In the first form allocates an array instace of the type that results
7107 // from deleting each of the individual expression from the expression list'
7109 if (num_arguments
> 0) {
7110 array_qualifier
.Append ("[");
7111 for (int i
= num_arguments
-1; i
> 0; i
--)
7112 array_qualifier
.Append (",");
7113 array_qualifier
.Append ("]");
7119 TypeExpr array_type_expr
;
7120 array_type_expr
= new ComposedCast (requested_base_type
, array_qualifier
.ToString (), loc
);
7121 array_type_expr
= array_type_expr
.ResolveAsTypeTerminal (ec
);
7122 if (array_type_expr
== null)
7125 type
= array_type_expr
.Type
;
7127 if (!type
.IsArray
) {
7128 Error (622, "Can only use array initializer expressions to assign to array types. Try using a new expression instead.");
7131 underlying_type
= TypeManager
.GetElementType (type
);
7132 dimensions
= type
.GetArrayRank ();
7137 public override Expression
DoResolve (EmitContext ec
)
7141 if (!LookupType (ec
))
7145 // First step is to validate the initializers and fill
7146 // in any missing bits
7148 if (!ValidateInitializers (ec
, type
))
7151 if (arguments
== null)
7154 arg_count
= arguments
.Count
;
7155 foreach (Argument a
in arguments
){
7156 if (!a
.Resolve (ec
, loc
))
7159 Expression real_arg
= ExpressionToArrayArgument (ec
, a
.Expr
, loc
);
7160 if (real_arg
== null)
7167 array_element_type
= TypeManager
.GetElementType (type
);
7169 if (array_element_type
.IsAbstract
&& array_element_type
.IsSealed
) {
7170 Report
.Error (719, loc
, "'{0}': array elements cannot be of static type", TypeManager
.CSharpName (array_element_type
));
7174 if (arg_count
== 1) {
7175 is_one_dimensional
= true;
7176 eclass
= ExprClass
.Value
;
7180 is_builtin_type
= TypeManager
.IsBuiltinType (type
);
7182 if (is_builtin_type
) {
7185 ml
= MemberLookup (ec
, type
, ".ctor", MemberTypes
.Constructor
,
7186 AllBindingFlags
, loc
);
7188 if (!(ml
is MethodGroupExpr
)) {
7189 ml
.Error_UnexpectedKind ("method group", loc
);
7194 Error (-6, "New invocation: Can not find a constructor for " +
7195 "this argument list");
7199 new_method
= Invocation
.OverloadResolve (
7200 ec
, (MethodGroupExpr
) ml
, arguments
, false, loc
);
7202 if (new_method
== null) {
7203 Error (-6, "New invocation: Can not find a constructor for " +
7204 "this argument list");
7208 eclass
= ExprClass
.Value
;
7211 ModuleBuilder mb
= CodeGen
.Module
.Builder
;
7212 ArrayList args
= new ArrayList ();
7214 if (arguments
!= null) {
7215 for (int i
= 0; i
< arg_count
; i
++)
7216 args
.Add (TypeManager
.int32_type
);
7219 Type
[] arg_types
= null;
7222 arg_types
= new Type
[args
.Count
];
7224 args
.CopyTo (arg_types
, 0);
7226 new_method
= mb
.GetArrayMethod (type
, ".ctor", CallingConventions
.HasThis
, null,
7229 if (new_method
== null) {
7230 Error (-6, "New invocation: Can not find a constructor for " +
7231 "this argument list");
7235 eclass
= ExprClass
.Value
;
7240 public static byte [] MakeByteBlob (ArrayList array_data
, Type underlying_type
, Location loc
)
7245 int count
= array_data
.Count
;
7247 if (underlying_type
.IsEnum
)
7248 underlying_type
= TypeManager
.EnumToUnderlying (underlying_type
);
7250 factor
= GetTypeSize (underlying_type
);
7252 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type
);
7254 data
= new byte [(count
* factor
+ 4) & ~
3];
7257 for (int i
= 0; i
< count
; ++i
) {
7258 object v
= array_data
[i
];
7260 if (v
is EnumConstant
)
7261 v
= ((EnumConstant
) v
).Child
;
7263 if (v
is Constant
&& !(v
is StringConstant
))
7264 v
= ((Constant
) v
).GetValue ();
7270 if (underlying_type
== TypeManager
.int64_type
){
7271 if (!(v
is Expression
)){
7272 long val
= (long) v
;
7274 for (int j
= 0; j
< factor
; ++j
) {
7275 data
[idx
+ j
] = (byte) (val
& 0xFF);
7279 } else if (underlying_type
== TypeManager
.uint64_type
){
7280 if (!(v
is Expression
)){
7281 ulong val
= (ulong) v
;
7283 for (int j
= 0; j
< factor
; ++j
) {
7284 data
[idx
+ j
] = (byte) (val
& 0xFF);
7288 } else if (underlying_type
== TypeManager
.float_type
) {
7289 if (!(v
is Expression
)){
7290 element
= BitConverter
.GetBytes ((float) v
);
7292 for (int j
= 0; j
< factor
; ++j
)
7293 data
[idx
+ j
] = element
[j
];
7295 } else if (underlying_type
== TypeManager
.double_type
) {
7296 if (!(v
is Expression
)){
7297 element
= BitConverter
.GetBytes ((double) v
);
7299 for (int j
= 0; j
< factor
; ++j
)
7300 data
[idx
+ j
] = element
[j
];
7302 } else if (underlying_type
== TypeManager
.char_type
){
7303 if (!(v
is Expression
)){
7304 int val
= (int) ((char) v
);
7306 data
[idx
] = (byte) (val
& 0xff);
7307 data
[idx
+1] = (byte) (val
>> 8);
7309 } else if (underlying_type
== TypeManager
.short_type
){
7310 if (!(v
is Expression
)){
7311 int val
= (int) ((short) v
);
7313 data
[idx
] = (byte) (val
& 0xff);
7314 data
[idx
+1] = (byte) (val
>> 8);
7316 } else if (underlying_type
== TypeManager
.ushort_type
){
7317 if (!(v
is Expression
)){
7318 int val
= (int) ((ushort) v
);
7320 data
[idx
] = (byte) (val
& 0xff);
7321 data
[idx
+1] = (byte) (val
>> 8);
7323 } else if (underlying_type
== TypeManager
.int32_type
) {
7324 if (!(v
is Expression
)){
7327 data
[idx
] = (byte) (val
& 0xff);
7328 data
[idx
+1] = (byte) ((val
>> 8) & 0xff);
7329 data
[idx
+2] = (byte) ((val
>> 16) & 0xff);
7330 data
[idx
+3] = (byte) (val
>> 24);
7332 } else if (underlying_type
== TypeManager
.uint32_type
) {
7333 if (!(v
is Expression
)){
7334 uint val
= (uint) v
;
7336 data
[idx
] = (byte) (val
& 0xff);
7337 data
[idx
+1] = (byte) ((val
>> 8) & 0xff);
7338 data
[idx
+2] = (byte) ((val
>> 16) & 0xff);
7339 data
[idx
+3] = (byte) (val
>> 24);
7341 } else if (underlying_type
== TypeManager
.sbyte_type
) {
7342 if (!(v
is Expression
)){
7343 sbyte val
= (sbyte) v
;
7344 data
[idx
] = (byte) val
;
7346 } else if (underlying_type
== TypeManager
.byte_type
) {
7347 if (!(v
is Expression
)){
7348 byte val
= (byte) v
;
7349 data
[idx
] = (byte) val
;
7351 } else if (underlying_type
== TypeManager
.bool_type
) {
7352 if (!(v
is Expression
)){
7353 bool val
= (bool) v
;
7354 data
[idx
] = (byte) (val
? 1 : 0);
7356 } else if (underlying_type
== TypeManager
.decimal_type
){
7357 if (!(v
is Expression
)){
7358 int [] bits
= Decimal
.GetBits ((decimal) v
);
7361 // FIXME: For some reason, this doesn't work on the MS runtime.
7362 int [] nbits
= new int [4];
7363 nbits
[0] = bits
[3];
7364 nbits
[1] = bits
[2];
7365 nbits
[2] = bits
[0];
7366 nbits
[3] = bits
[1];
7368 for (int j
= 0; j
< 4; j
++){
7369 data
[p
++] = (byte) (nbits
[j
] & 0xff);
7370 data
[p
++] = (byte) ((nbits
[j
] >> 8) & 0xff);
7371 data
[p
++] = (byte) ((nbits
[j
] >> 16) & 0xff);
7372 data
[p
++] = (byte) (nbits
[j
] >> 24);
7376 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type
);
7385 // Emits the initializers for the array
7387 void EmitStaticInitializers (EmitContext ec
)
7390 // First, the static data
7393 ILGenerator ig
= ec
.ig
;
7395 byte [] data
= MakeByteBlob (array_data
, underlying_type
, loc
);
7397 fb
= RootContext
.MakeStaticData (data
);
7399 ig
.Emit (OpCodes
.Dup
);
7400 ig
.Emit (OpCodes
.Ldtoken
, fb
);
7401 ig
.Emit (OpCodes
.Call
,
7402 TypeManager
.void_initializearray_array_fieldhandle
);
7406 // Emits pieces of the array that can not be computed at compile
7407 // time (variables and string locations).
7409 // This always expect the top value on the stack to be the array
7411 void EmitDynamicInitializers (EmitContext ec
)
7413 ILGenerator ig
= ec
.ig
;
7414 int dims
= bounds
.Count
;
7415 int [] current_pos
= new int [dims
];
7416 int top
= array_data
.Count
;
7418 MethodInfo
set = null;
7422 ModuleBuilder mb
= null;
7423 mb
= CodeGen
.Module
.Builder
;
7424 args
= new Type
[dims
+ 1];
7427 for (j
= 0; j
< dims
; j
++)
7428 args
[j
] = TypeManager
.int32_type
;
7430 args
[j
] = array_element_type
;
7432 set = mb
.GetArrayMethod (
7434 CallingConventions
.HasThis
| CallingConventions
.Standard
,
7435 TypeManager
.void_type
, args
);
7438 for (int i
= 0; i
< top
; i
++){
7440 Expression e
= null;
7442 if (array_data
[i
] is Expression
)
7443 e
= (Expression
) array_data
[i
];
7447 // Basically we do this for string literals and
7448 // other non-literal expressions
7450 if (e
is EnumConstant
){
7451 e
= ((EnumConstant
) e
).Child
;
7454 if (e
is StringConstant
|| e
is DecimalConstant
|| !(e
is Constant
) ||
7455 num_automatic_initializers
<= max_automatic_initializers
) {
7456 Type etype
= e
.Type
;
7458 ig
.Emit (OpCodes
.Dup
);
7460 for (int idx
= 0; idx
< dims
; idx
++)
7461 IntConstant
.EmitInt (ig
, current_pos
[idx
]);
7464 // If we are dealing with a struct, get the
7465 // address of it, so we can store it.
7467 if ((dims
== 1) && etype
.IsValueType
&&
7468 (!TypeManager
.IsBuiltinOrEnum (etype
) ||
7469 etype
== TypeManager
.decimal_type
)) {
7474 // Let new know that we are providing
7475 // the address where to store the results
7477 n
.DisableTemporaryValueType ();
7480 ig
.Emit (OpCodes
.Ldelema
, etype
);
7486 bool is_stobj
, has_type_arg
;
7487 OpCode op
= ArrayAccess
.GetStoreOpcode (
7488 etype
, out is_stobj
,
7491 ig
.Emit (OpCodes
.Stobj
, etype
);
7492 else if (has_type_arg
)
7493 ig
.Emit (op
, etype
);
7497 ig
.Emit (OpCodes
.Call
, set);
7504 for (int j
= dims
- 1; j
>= 0; j
--){
7506 if (current_pos
[j
] < (int) bounds
[j
])
7508 current_pos
[j
] = 0;
7513 void EmitArrayArguments (EmitContext ec
)
7515 ILGenerator ig
= ec
.ig
;
7517 foreach (Argument a
in arguments
) {
7518 Type atype
= a
.Type
;
7521 if (atype
== TypeManager
.uint64_type
)
7522 ig
.Emit (OpCodes
.Conv_Ovf_U4
);
7523 else if (atype
== TypeManager
.int64_type
)
7524 ig
.Emit (OpCodes
.Conv_Ovf_I4
);
7528 public override void Emit (EmitContext ec
)
7530 ILGenerator ig
= ec
.ig
;
7532 EmitArrayArguments (ec
);
7533 if (is_one_dimensional
)
7534 ig
.Emit (OpCodes
.Newarr
, array_element_type
);
7536 if (is_builtin_type
)
7537 ig
.Emit (OpCodes
.Newobj
, (ConstructorInfo
) new_method
);
7539 ig
.Emit (OpCodes
.Newobj
, (MethodInfo
) new_method
);
7542 if (initializers
!= null){
7544 // FIXME: Set this variable correctly.
7546 bool dynamic_initializers
= true;
7548 // This will never be true for array types that cannot be statically
7549 // initialized. num_automatic_initializers will always be zero. See
7551 if (num_automatic_initializers
> max_automatic_initializers
)
7552 EmitStaticInitializers (ec
);
7554 if (dynamic_initializers
)
7555 EmitDynamicInitializers (ec
);
7559 public object EncodeAsAttribute ()
7561 if (!is_one_dimensional
){
7562 Report
.Error (-211, Location
, "attribute can not encode multi-dimensional arrays");
7566 if (array_data
== null){
7567 Report
.Error (-212, Location
, "array should be initialized when passing it to an attribute");
7571 object [] ret
= new object [array_data
.Count
];
7573 foreach (Expression e
in array_data
){
7576 if (e
is NullLiteral
)
7579 if (!Attribute
.GetAttributeArgumentExpression (e
, Location
, array_element_type
, out v
))
7589 /// Represents the `this' construct
7591 public class This
: Expression
, IAssignMethod
, IMemoryLocation
, IVariable
{
7594 VariableInfo variable_info
;
7596 public This (Block block
, Location loc
)
7602 public This (Location loc
)
7607 public VariableInfo VariableInfo
{
7608 get { return variable_info; }
7611 public bool VerifyFixed (bool is_expression
)
7613 if ((variable_info
== null) || (variable_info
.LocalInfo
== null))
7616 return variable_info
.LocalInfo
.IsFixed
;
7619 public bool ResolveBase (EmitContext ec
)
7621 eclass
= ExprClass
.Variable
;
7623 if (ec
.TypeContainer
.CurrentType
!= null)
7624 type
= ec
.TypeContainer
.CurrentType
;
7626 type
= ec
.ContainerType
;
7629 Error (26, "Keyword this not valid in static code");
7633 if ((block
!= null) && (block
.ThisVariable
!= null))
7634 variable_info
= block
.ThisVariable
.VariableInfo
;
7639 public override Expression
DoResolve (EmitContext ec
)
7641 if (!ResolveBase (ec
))
7644 if ((variable_info
!= null) && !variable_info
.IsAssigned (ec
)) {
7645 Error (188, "The this object cannot be used before all " +
7646 "of its fields are assigned to");
7647 variable_info
.SetAssigned (ec
);
7651 if (ec
.IsFieldInitializer
) {
7652 Error (27, "Keyword `this' can't be used outside a constructor, " +
7653 "a method or a property.");
7660 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
7662 if (!ResolveBase (ec
))
7665 if (variable_info
!= null)
7666 variable_info
.SetAssigned (ec
);
7668 if (ec
.TypeContainer
is Class
){
7669 Error (1604, "Cannot assign to `this'");
7676 public void Emit (EmitContext ec
, bool leave_copy
)
7680 ec
.ig
.Emit (OpCodes
.Dup
);
7683 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
7685 ILGenerator ig
= ec
.ig
;
7687 if (ec
.TypeContainer
is Struct
){
7691 ec
.ig
.Emit (OpCodes
.Dup
);
7692 ig
.Emit (OpCodes
.Stobj
, type
);
7694 throw new Exception ("how did you get here");
7698 public override void Emit (EmitContext ec
)
7700 ILGenerator ig
= ec
.ig
;
7703 if (ec
.TypeContainer
is Struct
)
7704 ig
.Emit (OpCodes
.Ldobj
, type
);
7707 public void AddressOf (EmitContext ec
, AddressOp mode
)
7712 // FIGURE OUT WHY LDARG_S does not work
7714 // consider: struct X { int val; int P { set { val = value; }}}
7716 // Yes, this looks very bad. Look at `NOTAS' for
7718 // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
7723 /// Represents the `__arglist' construct
7725 public class ArglistAccess
: Expression
7727 public ArglistAccess (Location loc
)
7732 public bool ResolveBase (EmitContext ec
)
7734 eclass
= ExprClass
.Variable
;
7735 type
= TypeManager
.runtime_argument_handle_type
;
7739 public override Expression
DoResolve (EmitContext ec
)
7741 if (!ResolveBase (ec
))
7744 if (ec
.IsFieldInitializer
|| !ec
.CurrentBlock
.HasVarargs
) {
7745 Error (190, "The __arglist construct is valid only within " +
7746 "a variable argument method.");
7753 public override void Emit (EmitContext ec
)
7755 ec
.ig
.Emit (OpCodes
.Arglist
);
7760 /// Represents the `__arglist (....)' construct
7762 public class Arglist
: Expression
7764 public readonly Argument
[] Arguments
;
7766 public Arglist (Argument
[] args
, Location l
)
7772 public Type
[] ArgumentTypes
{
7774 Type
[] retval
= new Type
[Arguments
.Length
];
7775 for (int i
= 0; i
< Arguments
.Length
; i
++)
7776 retval
[i
] = Arguments
[i
].Type
;
7781 public override Expression
DoResolve (EmitContext ec
)
7783 eclass
= ExprClass
.Variable
;
7784 type
= TypeManager
.runtime_argument_handle_type
;
7786 foreach (Argument arg
in Arguments
) {
7787 if (!arg
.Resolve (ec
, loc
))
7794 public override void Emit (EmitContext ec
)
7796 foreach (Argument arg
in Arguments
)
7802 // This produces the value that renders an instance, used by the iterators code
7804 public class ProxyInstance
: Expression
, IMemoryLocation
{
7805 public override Expression
DoResolve (EmitContext ec
)
7807 eclass
= ExprClass
.Variable
;
7808 type
= ec
.ContainerType
;
7812 public override void Emit (EmitContext ec
)
7814 ec
.ig
.Emit (OpCodes
.Ldarg_0
);
7818 public void AddressOf (EmitContext ec
, AddressOp mode
)
7820 ec
.ig
.Emit (OpCodes
.Ldarg_0
);
7825 /// Implements the typeof operator
7827 public class TypeOf
: Expression
{
7828 public Expression QueriedType
;
7829 protected Type typearg
;
7831 public TypeOf (Expression queried_type
, Location l
)
7833 QueriedType
= queried_type
;
7837 public override Expression
DoResolve (EmitContext ec
)
7839 TypeExpr texpr
= QueriedType
.ResolveAsTypeTerminal (ec
);
7843 typearg
= texpr
.Type
;
7845 if (typearg
== TypeManager
.void_type
) {
7846 Error (673, "System.Void cannot be used from C# - " +
7847 "use typeof (void) to get the void type object");
7851 if (typearg
.IsPointer
&& !ec
.InUnsafe
){
7855 CheckObsoleteAttribute (typearg
);
7857 type
= TypeManager
.type_type
;
7858 eclass
= ExprClass
.Type
;
7862 public override void Emit (EmitContext ec
)
7864 ec
.ig
.Emit (OpCodes
.Ldtoken
, typearg
);
7865 ec
.ig
.Emit (OpCodes
.Call
, TypeManager
.system_type_get_type_from_handle
);
7868 public Type TypeArg
{
7869 get { return typearg; }
7874 /// Implements the `typeof (void)' operator
7876 public class TypeOfVoid
: TypeOf
{
7877 public TypeOfVoid (Location l
) : base (null, l
)
7882 public override Expression
DoResolve (EmitContext ec
)
7884 type
= TypeManager
.type_type
;
7885 typearg
= TypeManager
.void_type
;
7886 eclass
= ExprClass
.Type
;
7892 /// Implements the sizeof expression
7894 public class SizeOf
: Expression
{
7895 public Expression QueriedType
;
7898 public SizeOf (Expression queried_type
, Location l
)
7900 this.QueriedType
= queried_type
;
7904 public override Expression
DoResolve (EmitContext ec
)
7908 233, loc
, "Sizeof may only be used in an unsafe context " +
7909 "(consider using System.Runtime.InteropServices.Marshal.SizeOf");
7913 TypeExpr texpr
= QueriedType
.ResolveAsTypeTerminal (ec
);
7917 if (texpr
is TypeParameterExpr
){
7918 ((TypeParameterExpr
)texpr
).Error_CannotUseAsUnmanagedType (loc
);
7922 type_queried
= texpr
.Type
;
7924 CheckObsoleteAttribute (type_queried
);
7926 if (!TypeManager
.IsUnmanagedType (type_queried
)){
7927 Report
.Error (208, loc
, "Cannot take the size of an unmanaged type (" + TypeManager
.CSharpName (type_queried
) + ")");
7931 type
= TypeManager
.int32_type
;
7932 eclass
= ExprClass
.Value
;
7936 public override void Emit (EmitContext ec
)
7938 int size
= GetTypeSize (type_queried
);
7941 ec
.ig
.Emit (OpCodes
.Sizeof
, type_queried
);
7943 IntConstant
.EmitInt (ec
.ig
, size
);
7948 /// Implements the member access expression
7950 public class MemberAccess
: Expression
{
7951 public string Identifier
;
7952 protected Expression expr
;
7953 protected TypeArguments args
;
7955 public MemberAccess (Expression expr
, string id
, Location l
)
7962 public MemberAccess (Expression expr
, string id
, TypeArguments args
,
7964 : this (expr
, id
, l
)
7969 public Expression Expr
{
7975 public static void error176 (Location loc
, string name
)
7977 Report
.Error (176, loc
, "Static member `" +
7978 name
+ "' cannot be accessed " +
7979 "with an instance reference, qualify with a " +
7980 "type name instead");
7983 public static bool IdenticalNameAndTypeName (EmitContext ec
, Expression left_original
, Expression left
, Location loc
)
7985 SimpleName sn
= left_original
as SimpleName
;
7986 if (sn
== null || left
== null || left
.Type
.Name
!= sn
.Name
)
7989 return ec
.DeclSpace
.LookupType (sn
.Name
, true, loc
) != null;
7992 // TODO: possible optimalization
7993 // Cache resolved constant result in FieldBuilder <-> expresion map
7994 public static Expression
ResolveMemberAccess (EmitContext ec
, Expression member_lookup
,
7995 Expression left
, Location loc
,
7996 Expression left_original
)
7998 bool left_is_type
, left_is_explicit
;
8000 // If `left' is null, then we're called from SimpleNameResolve and this is
8001 // a member in the currently defining class.
8003 left_is_type
= ec
.IsStatic
|| ec
.IsFieldInitializer
;
8004 left_is_explicit
= false;
8006 // Implicitly default to `this' unless we're static.
8007 if (!ec
.IsStatic
&& !ec
.IsFieldInitializer
&& !ec
.InEnumContext
)
8008 left
= ec
.GetThis (loc
);
8010 left_is_type
= left
is TypeExpr
;
8011 left_is_explicit
= true;
8014 if (member_lookup
is FieldExpr
){
8015 FieldExpr fe
= (FieldExpr
) member_lookup
;
8016 FieldInfo fi
= fe
.FieldInfo
.Mono_GetGenericFieldDefinition ();
8017 Type decl_type
= fi
.DeclaringType
;
8019 bool is_emitted
= fi
is FieldBuilder
;
8020 Type t
= fi
.FieldType
;
8023 Const c
= TypeManager
.LookupConstant ((FieldBuilder
) fi
);
8027 if (!c
.LookupConstantValue (out o
))
8030 object real_value
= ((Constant
) c
.Expr
).GetValue ();
8032 Expression exp
= Constantify (real_value
, t
);
8034 if (left_is_explicit
&& !left_is_type
&& !IdenticalNameAndTypeName (ec
, left_original
, left
, loc
)) {
8035 Report
.SymbolRelatedToPreviousError (c
);
8036 error176 (loc
, c
.GetSignatureForError ());
8044 // IsInitOnly is because of MS compatibility, I don't know why but they emit decimal constant as InitOnly
8045 if (fi
.IsInitOnly
&& !is_emitted
&& t
== TypeManager
.decimal_type
) {
8046 object[] attrs
= fi
.GetCustomAttributes (TypeManager
.decimal_constant_attribute_type
, false);
8047 if (attrs
.Length
== 1)
8048 return new DecimalConstant (((System
.Runtime
.CompilerServices
.DecimalConstantAttribute
) attrs
[0]).Value
);
8055 o
= TypeManager
.GetValue ((FieldBuilder
) fi
);
8057 o
= fi
.GetValue (fi
);
8059 if (decl_type
.IsSubclassOf (TypeManager
.enum_type
)) {
8060 if (left_is_explicit
&& !left_is_type
&&
8061 !IdenticalNameAndTypeName (ec
, left_original
, member_lookup
, loc
)) {
8062 error176 (loc
, fe
.FieldInfo
.Name
);
8066 Expression enum_member
= MemberLookup (
8067 ec
, decl_type
, "value__", MemberTypes
.Field
,
8068 AllBindingFlags
, loc
);
8070 Enum en
= TypeManager
.LookupEnum (decl_type
);
8074 c
= Constantify (o
, en
.UnderlyingType
);
8076 c
= Constantify (o
, enum_member
.Type
);
8078 return new EnumConstant (c
, decl_type
);
8081 Expression exp
= Constantify (o
, t
);
8083 if (left_is_explicit
&& !left_is_type
) {
8084 error176 (loc
, fe
.FieldInfo
.Name
);
8091 if (t
.IsPointer
&& !ec
.InUnsafe
){
8097 if (member_lookup
is EventExpr
) {
8098 EventExpr ee
= (EventExpr
) member_lookup
;
8101 // If the event is local to this class, we transform ourselves into
8105 if (ee
.EventInfo
.DeclaringType
== ec
.ContainerType
||
8106 TypeManager
.IsNestedChildOf(ec
.ContainerType
, ee
.EventInfo
.DeclaringType
)) {
8107 MemberInfo mi
= GetFieldFromEvent (ee
);
8111 // If this happens, then we have an event with its own
8112 // accessors and private field etc so there's no need
8113 // to transform ourselves.
8115 ee
.InstanceExpression
= left
;
8119 Expression ml
= ExprClassFromMemberInfo (ec
, mi
, loc
);
8122 Report
.Error (-200, loc
, "Internal error!!");
8126 if (!left_is_explicit
)
8129 ee
.InstanceExpression
= left
;
8131 return ResolveMemberAccess (ec
, ml
, left
, loc
, left_original
);
8135 if (member_lookup
is IMemberExpr
) {
8136 IMemberExpr me
= (IMemberExpr
) member_lookup
;
8137 MethodGroupExpr mg
= me
as MethodGroupExpr
;
8140 if ((mg
!= null) && left_is_explicit
&& left
.Type
.IsInterface
)
8141 mg
.IsExplicitImpl
= left_is_explicit
;
8144 if ((ec
.IsFieldInitializer
|| ec
.IsStatic
) &&
8145 IdenticalNameAndTypeName (ec
, left_original
, member_lookup
, loc
))
8146 return member_lookup
;
8148 SimpleName
.Error_ObjectRefRequired (ec
, loc
, me
.Name
);
8153 if (!me
.IsInstance
){
8154 if (IdenticalNameAndTypeName (ec
, left_original
, left
, loc
))
8155 return member_lookup
;
8157 if (left_is_explicit
) {
8158 error176 (loc
, me
.Name
);
8164 // Since we can not check for instance objects in SimpleName,
8165 // becaue of the rule that allows types and variables to share
8166 // the name (as long as they can be de-ambiguated later, see
8167 // IdenticalNameAndTypeName), we have to check whether left
8168 // is an instance variable in a static context
8170 // However, if the left-hand value is explicitly given, then
8171 // it is already our instance expression, so we aren't in
8175 if (ec
.IsStatic
&& !left_is_explicit
&& left
is IMemberExpr
){
8176 IMemberExpr mexp
= (IMemberExpr
) left
;
8178 if (!mexp
.IsStatic
){
8179 SimpleName
.Error_ObjectRefRequired (ec
, loc
, mexp
.Name
);
8184 if ((mg
!= null) && IdenticalNameAndTypeName (ec
, left_original
, left
, loc
))
8185 mg
.IdenticalTypeName
= true;
8187 me
.InstanceExpression
= left
;
8190 return member_lookup
;
8193 Console
.WriteLine ("Left is: " + left
);
8194 Report
.Error (-100, loc
, "Support for [" + member_lookup
+ "] is not present yet");
8195 Environment
.Exit (1);
8199 public virtual Expression
DoResolve (EmitContext ec
, Expression right_side
,
8203 throw new Exception ();
8206 // Resolve the expression with flow analysis turned off, we'll do the definite
8207 // assignment checks later. This is because we don't know yet what the expression
8208 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
8209 // definite assignment check on the actual field and not on the whole struct.
8212 Expression original
= expr
;
8213 expr
= expr
.Resolve (ec
, flags
| ResolveFlags
.Intermediate
| ResolveFlags
.DisableFlowAnalysis
);
8217 if (expr
is Namespace
) {
8218 Namespace ns
= (Namespace
) expr
;
8219 string lookup_id
= MemberName
.MakeName (Identifier
, args
);
8220 FullNamedExpression retval
= ns
.Lookup (ec
.DeclSpace
, lookup_id
, loc
);
8221 if ((retval
!= null) && (args
!= null))
8222 retval
= new ConstructedType (retval
, args
, loc
).ResolveAsTypeStep (ec
);
8224 Report
.Error (234, loc
, "The type or namespace name `{0}' could not be found in namespace `{1}'", Identifier
, ns
.FullName
);
8229 // TODO: I mailed Ravi about this, and apparently we can get rid
8230 // of this and put it in the right place.
8232 // Handle enums here when they are in transit.
8233 // Note that we cannot afford to hit MemberLookup in this case because
8234 // it will fail to find any members at all
8238 if (expr
is TypeExpr
){
8239 expr_type
= expr
.Type
;
8241 if (!ec
.DeclSpace
.CheckAccessLevel (expr_type
)){
8242 Report
.Error (122, loc
, "'{0}' is inaccessible due to its protection level", expr_type
);
8246 if (expr_type
== TypeManager
.enum_type
|| expr_type
.IsSubclassOf (TypeManager
.enum_type
)){
8247 Enum en
= TypeManager
.LookupEnum (expr_type
);
8250 object value = en
.LookupEnumValue (ec
, Identifier
, loc
);
8253 MemberCore mc
= en
.GetDefinition (Identifier
);
8254 ObsoleteAttribute oa
= mc
.GetObsoleteAttribute (en
);
8256 AttributeTester
.Report_ObsoleteMessage (oa
, mc
.GetSignatureForError (), Location
);
8258 oa
= en
.GetObsoleteAttribute (en
);
8260 AttributeTester
.Report_ObsoleteMessage (oa
, en
.GetSignatureForError (), Location
);
8263 Constant c
= Constantify (value, en
.UnderlyingType
);
8264 return new EnumConstant (c
, expr_type
);
8267 CheckObsoleteAttribute (expr_type
);
8269 FieldInfo fi
= expr_type
.GetField (Identifier
);
8271 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (fi
);
8273 AttributeTester
.Report_ObsoleteMessage (oa
, TypeManager
.GetFullNameSignature (fi
), Location
);
8278 expr_type
= expr
.Type
;
8280 if (expr_type
.IsPointer
){
8281 Error (23, "The `.' operator can not be applied to pointer operands (" +
8282 TypeManager
.CSharpName (expr_type
) + ")");
8286 Expression member_lookup
;
8287 member_lookup
= MemberLookup (
8288 ec
, expr_type
, expr_type
, Identifier
, loc
);
8289 if ((member_lookup
== null) && (args
!= null)) {
8290 string lookup_id
= MemberName
.MakeName (Identifier
, args
);
8291 member_lookup
= MemberLookup (
8292 ec
, expr_type
, expr_type
, lookup_id
, loc
);
8294 if (member_lookup
== null) {
8295 MemberLookupFailed (
8296 ec
, expr_type
, expr_type
, Identifier
, null, loc
);
8300 if (member_lookup
is TypeExpr
) {
8301 if (!(expr
is TypeExpr
) &&
8302 !IdenticalNameAndTypeName (ec
, original
, expr
, loc
)) {
8303 Error (572, "Can't reference type `" + Identifier
+ "' through an expression; try `" +
8304 member_lookup
.Type
+ "' instead");
8308 return member_lookup
;
8312 string full_name
= expr_type
+ "." + Identifier
;
8314 if (member_lookup
is FieldExpr
) {
8315 Report
.Error (307, loc
, "The field `{0}' cannot " +
8316 "be used with type arguments", full_name
);
8318 } else if (member_lookup
is EventExpr
) {
8319 Report
.Error (307, loc
, "The event `{0}' cannot " +
8320 "be used with type arguments", full_name
);
8322 } else if (member_lookup
is PropertyExpr
) {
8323 Report
.Error (307, loc
, "The property `{0}' cannot " +
8324 "be used with type arguments", full_name
);
8329 member_lookup
= ResolveMemberAccess (ec
, member_lookup
, expr
, loc
, original
);
8330 if (member_lookup
== null)
8334 MethodGroupExpr mg
= member_lookup
as MethodGroupExpr
;
8336 throw new InternalErrorException ();
8338 return mg
.ResolveGeneric (ec
, args
);
8341 // The following DoResolve/DoResolveLValue will do the definite assignment
8344 if (right_side
!= null)
8345 member_lookup
= member_lookup
.DoResolveLValue (ec
, right_side
);
8347 member_lookup
= member_lookup
.DoResolve (ec
);
8349 return member_lookup
;
8352 public override Expression
DoResolve (EmitContext ec
)
8354 return DoResolve (ec
, null, ResolveFlags
.VariableOrValue
| ResolveFlags
.Type
);
8357 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
8359 return DoResolve (ec
, right_side
, ResolveFlags
.VariableOrValue
| ResolveFlags
.Type
);
8362 public override FullNamedExpression
ResolveAsTypeStep (EmitContext ec
)
8364 return ResolveNamespaceOrType (ec
, false);
8367 public FullNamedExpression
ResolveNamespaceOrType (EmitContext ec
, bool silent
)
8369 FullNamedExpression new_expr
= expr
.ResolveAsTypeStep (ec
);
8371 if (new_expr
== null)
8374 string lookup_id
= MemberName
.MakeName (Identifier
, args
);
8376 if (new_expr
is Namespace
) {
8377 Namespace ns
= (Namespace
) new_expr
;
8378 FullNamedExpression retval
= ns
.Lookup (ec
.DeclSpace
, lookup_id
, loc
);
8379 if ((retval
!= null) && (args
!= null))
8380 retval
= new ConstructedType (retval
, args
, loc
).ResolveAsTypeStep (ec
);
8381 if (!silent
&& retval
== null)
8382 Report
.Error (234, loc
, "The type or namespace name `{0}' could not be found in namespace `{1}'", Identifier
, ns
.FullName
);
8386 TypeExpr tnew_expr
= new_expr
.ResolveAsTypeTerminal (ec
);
8387 if (tnew_expr
== null)
8390 Type expr_type
= tnew_expr
.Type
;
8392 if (expr_type
.IsPointer
){
8393 Error (23, "The `.' operator can not be applied to pointer operands (" +
8394 TypeManager
.CSharpName (expr_type
) + ")");
8398 Expression member_lookup
;
8399 member_lookup
= MemberLookupFinal (ec
, expr_type
, expr_type
, lookup_id
, loc
);
8400 if (!silent
&& member_lookup
== null) {
8401 Report
.Error (234, loc
, "The type name `{0}' could not be found in type `{1}'",
8402 Identifier
, new_expr
.FullName
);
8406 if (!(member_lookup
is TypeExpr
)) {
8407 Report
.Error (118, loc
, "'{0}.{1}' denotes a '{2}', where a type was expected",
8408 new_expr
.FullName
, Identifier
, member_lookup
.ExprClassName ());
8412 TypeExpr texpr
= member_lookup
.ResolveAsTypeTerminal (ec
);
8416 TypeArguments the_args
= args
;
8417 if (TypeManager
.HasGenericArguments (expr_type
)) {
8418 Type
[] decl_args
= TypeManager
.GetTypeArguments (expr_type
);
8420 TypeArguments new_args
= new TypeArguments (loc
);
8421 foreach (Type decl
in decl_args
)
8422 new_args
.Add (new TypeExpression (decl
, loc
));
8425 new_args
.Add (args
);
8427 the_args
= new_args
;
8430 if (the_args
!= null) {
8431 ConstructedType ctype
= new ConstructedType (texpr
.Type
, the_args
, loc
);
8432 return ctype
.ResolveAsTypeStep (ec
);
8438 public override void Emit (EmitContext ec
)
8440 throw new Exception ("Should not happen");
8443 public override string ToString ()
8445 return expr
+ "." + MemberName
.MakeName (Identifier
, args
);
8450 /// Implements checked expressions
8452 public class CheckedExpr
: Expression
{
8454 public Expression Expr
;
8456 public CheckedExpr (Expression e
, Location l
)
8462 public override Expression
DoResolve (EmitContext ec
)
8464 bool last_check
= ec
.CheckState
;
8465 bool last_const_check
= ec
.ConstantCheckState
;
8467 ec
.CheckState
= true;
8468 ec
.ConstantCheckState
= true;
8469 Expr
= Expr
.Resolve (ec
);
8470 ec
.CheckState
= last_check
;
8471 ec
.ConstantCheckState
= last_const_check
;
8476 if (Expr
is Constant
)
8479 eclass
= Expr
.eclass
;
8484 public override void Emit (EmitContext ec
)
8486 bool last_check
= ec
.CheckState
;
8487 bool last_const_check
= ec
.ConstantCheckState
;
8489 ec
.CheckState
= true;
8490 ec
.ConstantCheckState
= true;
8492 ec
.CheckState
= last_check
;
8493 ec
.ConstantCheckState
= last_const_check
;
8499 /// Implements the unchecked expression
8501 public class UnCheckedExpr
: Expression
{
8503 public Expression Expr
;
8505 public UnCheckedExpr (Expression e
, Location l
)
8511 public override Expression
DoResolve (EmitContext ec
)
8513 bool last_check
= ec
.CheckState
;
8514 bool last_const_check
= ec
.ConstantCheckState
;
8516 ec
.CheckState
= false;
8517 ec
.ConstantCheckState
= false;
8518 Expr
= Expr
.Resolve (ec
);
8519 ec
.CheckState
= last_check
;
8520 ec
.ConstantCheckState
= last_const_check
;
8525 if (Expr
is Constant
)
8528 eclass
= Expr
.eclass
;
8533 public override void Emit (EmitContext ec
)
8535 bool last_check
= ec
.CheckState
;
8536 bool last_const_check
= ec
.ConstantCheckState
;
8538 ec
.CheckState
= false;
8539 ec
.ConstantCheckState
= false;
8541 ec
.CheckState
= last_check
;
8542 ec
.ConstantCheckState
= last_const_check
;
8548 /// An Element Access expression.
8550 /// During semantic analysis these are transformed into
8551 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
8553 public class ElementAccess
: Expression
{
8554 public ArrayList Arguments
;
8555 public Expression Expr
;
8557 public ElementAccess (Expression e
, ArrayList e_list
, Location l
)
8566 Arguments
= new ArrayList ();
8567 foreach (Expression tmp
in e_list
)
8568 Arguments
.Add (new Argument (tmp
, Argument
.AType
.Expression
));
8572 bool CommonResolve (EmitContext ec
)
8574 Expr
= Expr
.Resolve (ec
);
8579 if (Arguments
== null)
8582 foreach (Argument a
in Arguments
){
8583 if (!a
.Resolve (ec
, loc
))
8590 Expression
MakePointerAccess (EmitContext ec
)
8594 if (t
== TypeManager
.void_ptr_type
){
8595 Error (242, "The array index operation is not valid for void pointers");
8598 if (Arguments
.Count
!= 1){
8599 Error (196, "A pointer must be indexed by a single value");
8604 p
= new PointerArithmetic (true, Expr
, ((Argument
)Arguments
[0]).Expr
, t
, loc
).Resolve (ec
);
8607 return new Indirection (p
, loc
).Resolve (ec
);
8610 public override Expression
DoResolve (EmitContext ec
)
8612 if (!CommonResolve (ec
))
8616 // We perform some simple tests, and then to "split" the emit and store
8617 // code we create an instance of a different class, and return that.
8619 // I am experimenting with this pattern.
8623 if (t
== TypeManager
.array_type
){
8624 Report
.Error (21, loc
, "Cannot use indexer on System.Array");
8629 return (new ArrayAccess (this, loc
)).Resolve (ec
);
8630 else if (t
.IsPointer
)
8631 return MakePointerAccess (ec
);
8633 return (new IndexerAccess (this, loc
)).Resolve (ec
);
8636 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
8638 if (!CommonResolve (ec
))
8643 return (new ArrayAccess (this, loc
)).ResolveLValue (ec
, right_side
);
8644 else if (t
.IsPointer
)
8645 return MakePointerAccess (ec
);
8647 return (new IndexerAccess (this, loc
)).ResolveLValue (ec
, right_side
);
8650 public override void Emit (EmitContext ec
)
8652 throw new Exception ("Should never be reached");
8657 /// Implements array access
8659 public class ArrayAccess
: Expression
, IAssignMethod
, IMemoryLocation
{
8661 // Points to our "data" repository
8665 LocalTemporary temp
;
8668 public ArrayAccess (ElementAccess ea_data
, Location l
)
8671 eclass
= ExprClass
.Variable
;
8675 public override Expression
DoResolve (EmitContext ec
)
8678 ExprClass eclass
= ea
.Expr
.eclass
;
8680 // As long as the type is valid
8681 if (!(eclass
== ExprClass
.Variable
|| eclass
== ExprClass
.PropertyAccess
||
8682 eclass
== ExprClass
.Value
)) {
8683 ea
.Expr
.Error_UnexpectedKind ("variable or value");
8688 Type t
= ea
.Expr
.Type
;
8689 if (t
.GetArrayRank () != ea
.Arguments
.Count
){
8691 "Incorrect number of indexes for array " +
8692 " expected: " + t
.GetArrayRank () + " got: " +
8693 ea
.Arguments
.Count
);
8697 type
= TypeManager
.GetElementType (t
);
8698 if (type
.IsPointer
&& !ec
.InUnsafe
){
8699 UnsafeError (ea
.Location
);
8703 foreach (Argument a
in ea
.Arguments
){
8704 Type argtype
= a
.Type
;
8706 if (argtype
== TypeManager
.int32_type
||
8707 argtype
== TypeManager
.uint32_type
||
8708 argtype
== TypeManager
.int64_type
||
8709 argtype
== TypeManager
.uint64_type
) {
8710 Constant c
= a
.Expr
as Constant
;
8711 if (c
!= null && c
.IsNegative
) {
8712 Report
.Warning (251, 2, a
.Expr
.Location
, "Indexing an array with a negative index (array indices always start at zero)");
8718 // Mhm. This is strage, because the Argument.Type is not the same as
8719 // Argument.Expr.Type: the value changes depending on the ref/out setting.
8721 // Wonder if I will run into trouble for this.
8723 a
.Expr
= ExpressionToArrayArgument (ec
, a
.Expr
, ea
.Location
);
8728 eclass
= ExprClass
.Variable
;
8734 /// Emits the right opcode to load an object of Type `t'
8735 /// from an array of T
8737 static public void EmitLoadOpcode (ILGenerator ig
, Type type
)
8739 if (type
== TypeManager
.byte_type
|| type
== TypeManager
.bool_type
)
8740 ig
.Emit (OpCodes
.Ldelem_U1
);
8741 else if (type
== TypeManager
.sbyte_type
)
8742 ig
.Emit (OpCodes
.Ldelem_I1
);
8743 else if (type
== TypeManager
.short_type
)
8744 ig
.Emit (OpCodes
.Ldelem_I2
);
8745 else if (type
== TypeManager
.ushort_type
|| type
== TypeManager
.char_type
)
8746 ig
.Emit (OpCodes
.Ldelem_U2
);
8747 else if (type
== TypeManager
.int32_type
)
8748 ig
.Emit (OpCodes
.Ldelem_I4
);
8749 else if (type
== TypeManager
.uint32_type
)
8750 ig
.Emit (OpCodes
.Ldelem_U4
);
8751 else if (type
== TypeManager
.uint64_type
)
8752 ig
.Emit (OpCodes
.Ldelem_I8
);
8753 else if (type
== TypeManager
.int64_type
)
8754 ig
.Emit (OpCodes
.Ldelem_I8
);
8755 else if (type
== TypeManager
.float_type
)
8756 ig
.Emit (OpCodes
.Ldelem_R4
);
8757 else if (type
== TypeManager
.double_type
)
8758 ig
.Emit (OpCodes
.Ldelem_R8
);
8759 else if (type
== TypeManager
.intptr_type
)
8760 ig
.Emit (OpCodes
.Ldelem_I
);
8761 else if (TypeManager
.IsEnumType (type
)){
8762 EmitLoadOpcode (ig
, TypeManager
.EnumToUnderlying (type
));
8763 } else if (type
.IsValueType
){
8764 ig
.Emit (OpCodes
.Ldelema
, type
);
8765 ig
.Emit (OpCodes
.Ldobj
, type
);
8766 } else if (type
.IsGenericParameter
)
8767 ig
.Emit (OpCodes
.Ldelem_Any
, type
);
8769 ig
.Emit (OpCodes
.Ldelem_Ref
);
8773 /// Returns the right opcode to store an object of Type `t'
8774 /// from an array of T.
8776 static public OpCode
GetStoreOpcode (Type t
, out bool is_stobj
, out bool has_type_arg
)
8778 //Console.WriteLine (new System.Diagnostics.StackTrace ());
8779 has_type_arg
= false; is_stobj
= false;
8780 t
= TypeManager
.TypeToCoreType (t
);
8781 if (TypeManager
.IsEnumType (t
))
8782 t
= TypeManager
.EnumToUnderlying (t
);
8783 if (t
== TypeManager
.byte_type
|| t
== TypeManager
.sbyte_type
||
8784 t
== TypeManager
.bool_type
)
8785 return OpCodes
.Stelem_I1
;
8786 else if (t
== TypeManager
.short_type
|| t
== TypeManager
.ushort_type
||
8787 t
== TypeManager
.char_type
)
8788 return OpCodes
.Stelem_I2
;
8789 else if (t
== TypeManager
.int32_type
|| t
== TypeManager
.uint32_type
)
8790 return OpCodes
.Stelem_I4
;
8791 else if (t
== TypeManager
.int64_type
|| t
== TypeManager
.uint64_type
)
8792 return OpCodes
.Stelem_I8
;
8793 else if (t
== TypeManager
.float_type
)
8794 return OpCodes
.Stelem_R4
;
8795 else if (t
== TypeManager
.double_type
)
8796 return OpCodes
.Stelem_R8
;
8797 else if (t
== TypeManager
.intptr_type
) {
8798 has_type_arg
= true;
8800 return OpCodes
.Stobj
;
8801 } else if (t
.IsValueType
) {
8802 has_type_arg
= true;
8804 return OpCodes
.Stobj
;
8805 } else if (t
.IsGenericParameter
) {
8806 has_type_arg
= true;
8807 return OpCodes
.Stelem_Any
;
8809 return OpCodes
.Stelem_Ref
;
8812 MethodInfo
FetchGetMethod ()
8814 ModuleBuilder mb
= CodeGen
.Module
.Builder
;
8815 int arg_count
= ea
.Arguments
.Count
;
8816 Type
[] args
= new Type
[arg_count
];
8819 for (int i
= 0; i
< arg_count
; i
++){
8820 //args [i++] = a.Type;
8821 args
[i
] = TypeManager
.int32_type
;
8824 get = mb
.GetArrayMethod (
8825 ea
.Expr
.Type
, "Get",
8826 CallingConventions
.HasThis
|
8827 CallingConventions
.Standard
,
8833 MethodInfo
FetchAddressMethod ()
8835 ModuleBuilder mb
= CodeGen
.Module
.Builder
;
8836 int arg_count
= ea
.Arguments
.Count
;
8837 Type
[] args
= new Type
[arg_count
];
8841 ret_type
= TypeManager
.GetReferenceType (type
);
8843 for (int i
= 0; i
< arg_count
; i
++){
8844 //args [i++] = a.Type;
8845 args
[i
] = TypeManager
.int32_type
;
8848 address
= mb
.GetArrayMethod (
8849 ea
.Expr
.Type
, "Address",
8850 CallingConventions
.HasThis
|
8851 CallingConventions
.Standard
,
8858 // Load the array arguments into the stack.
8860 // If we have been requested to cache the values (cached_locations array
8861 // initialized), then load the arguments the first time and store them
8862 // in locals. otherwise load from local variables.
8864 void LoadArrayAndArguments (EmitContext ec
)
8866 ILGenerator ig
= ec
.ig
;
8869 foreach (Argument a
in ea
.Arguments
){
8870 Type argtype
= a
.Expr
.Type
;
8874 if (argtype
== TypeManager
.int64_type
)
8875 ig
.Emit (OpCodes
.Conv_Ovf_I
);
8876 else if (argtype
== TypeManager
.uint64_type
)
8877 ig
.Emit (OpCodes
.Conv_Ovf_I_Un
);
8881 public void Emit (EmitContext ec
, bool leave_copy
)
8883 int rank
= ea
.Expr
.Type
.GetArrayRank ();
8884 ILGenerator ig
= ec
.ig
;
8887 LoadArrayAndArguments (ec
);
8890 EmitLoadOpcode (ig
, type
);
8894 method
= FetchGetMethod ();
8895 ig
.Emit (OpCodes
.Call
, method
);
8898 LoadFromPtr (ec
.ig
, this.type
);
8901 ec
.ig
.Emit (OpCodes
.Dup
);
8902 temp
= new LocalTemporary (ec
, this.type
);
8907 public override void Emit (EmitContext ec
)
8912 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
8914 int rank
= ea
.Expr
.Type
.GetArrayRank ();
8915 ILGenerator ig
= ec
.ig
;
8916 Type t
= source
.Type
;
8917 prepared
= prepare_for_load
;
8919 if (prepare_for_load
) {
8920 AddressOf (ec
, AddressOp
.LoadStore
);
8921 ec
.ig
.Emit (OpCodes
.Dup
);
8924 ec
.ig
.Emit (OpCodes
.Dup
);
8925 temp
= new LocalTemporary (ec
, this.type
);
8928 StoreFromPtr (ec
.ig
, t
);
8936 LoadArrayAndArguments (ec
);
8939 bool is_stobj
, has_type_arg
;
8940 OpCode op
= GetStoreOpcode (t
, out is_stobj
, out has_type_arg
);
8943 // The stobj opcode used by value types will need
8944 // an address on the stack, not really an array/array
8948 ig
.Emit (OpCodes
.Ldelema
, t
);
8952 ec
.ig
.Emit (OpCodes
.Dup
);
8953 temp
= new LocalTemporary (ec
, this.type
);
8958 ig
.Emit (OpCodes
.Stobj
, t
);
8959 else if (has_type_arg
)
8964 ModuleBuilder mb
= CodeGen
.Module
.Builder
;
8965 int arg_count
= ea
.Arguments
.Count
;
8966 Type
[] args
= new Type
[arg_count
+ 1];
8971 ec
.ig
.Emit (OpCodes
.Dup
);
8972 temp
= new LocalTemporary (ec
, this.type
);
8976 for (int i
= 0; i
< arg_count
; i
++){
8977 //args [i++] = a.Type;
8978 args
[i
] = TypeManager
.int32_type
;
8981 args
[arg_count
] = type
;
8983 set = mb
.GetArrayMethod (
8984 ea
.Expr
.Type
, "Set",
8985 CallingConventions
.HasThis
|
8986 CallingConventions
.Standard
,
8987 TypeManager
.void_type
, args
);
8989 ig
.Emit (OpCodes
.Call
, set);
8996 public void AddressOf (EmitContext ec
, AddressOp mode
)
8998 int rank
= ea
.Expr
.Type
.GetArrayRank ();
8999 ILGenerator ig
= ec
.ig
;
9001 LoadArrayAndArguments (ec
);
9004 ig
.Emit (OpCodes
.Ldelema
, type
);
9006 MethodInfo address
= FetchAddressMethod ();
9007 ig
.Emit (OpCodes
.Call
, address
);
9014 public ArrayList Properties
;
9015 static Hashtable map
;
9017 public struct Indexer
{
9018 public readonly Type Type
;
9019 public readonly MethodInfo Getter
, Setter
;
9021 public Indexer (Type type
, MethodInfo
get, MethodInfo
set)
9031 map
= new Hashtable ();
9036 Properties
= new ArrayList ();
9039 void Append (MemberInfo
[] mi
)
9041 foreach (PropertyInfo property
in mi
){
9042 MethodInfo
get, set;
9044 get = property
.GetGetMethod (true);
9045 set = property
.GetSetMethod (true);
9046 Properties
.Add (new Indexer (property
.PropertyType
, get, set));
9050 static private MemberInfo
[] GetIndexersForTypeOrInterface (Type caller_type
, Type lookup_type
)
9052 string p_name
= TypeManager
.IndexerPropertyName (lookup_type
);
9054 MemberInfo
[] mi
= TypeManager
.MemberLookup (
9055 caller_type
, caller_type
, lookup_type
, MemberTypes
.Property
,
9056 BindingFlags
.Public
| BindingFlags
.Instance
|
9057 BindingFlags
.DeclaredOnly
, p_name
, null);
9059 if (mi
== null || mi
.Length
== 0)
9065 static public Indexers
GetIndexersForType (Type caller_type
, Type lookup_type
, Location loc
)
9067 Indexers ix
= (Indexers
) map
[lookup_type
];
9072 Type copy
= lookup_type
;
9073 while (copy
!= TypeManager
.object_type
&& copy
!= null){
9074 MemberInfo
[] mi
= GetIndexersForTypeOrInterface (caller_type
, copy
);
9078 ix
= new Indexers ();
9083 copy
= copy
.BaseType
;
9086 if (!lookup_type
.IsInterface
)
9089 Type
[] ifaces
= TypeManager
.GetInterfaces (lookup_type
);
9090 if (ifaces
!= null) {
9091 foreach (Type itype
in ifaces
) {
9092 MemberInfo
[] mi
= GetIndexersForTypeOrInterface (caller_type
, itype
);
9095 ix
= new Indexers ();
9107 /// Expressions that represent an indexer call.
9109 public class IndexerAccess
: Expression
, IAssignMethod
{
9111 // Points to our "data" repository
9113 MethodInfo
get, set;
9114 ArrayList set_arguments
;
9115 bool is_base_indexer
;
9117 protected Type indexer_type
;
9118 protected Type current_type
;
9119 protected Expression instance_expr
;
9120 protected ArrayList arguments
;
9122 public IndexerAccess (ElementAccess ea
, Location loc
)
9123 : this (ea
.Expr
, false, loc
)
9125 this.arguments
= ea
.Arguments
;
9128 protected IndexerAccess (Expression instance_expr
, bool is_base_indexer
,
9131 this.instance_expr
= instance_expr
;
9132 this.is_base_indexer
= is_base_indexer
;
9133 this.eclass
= ExprClass
.Value
;
9137 protected virtual bool CommonResolve (EmitContext ec
)
9139 indexer_type
= instance_expr
.Type
;
9140 current_type
= ec
.ContainerType
;
9145 public override Expression
DoResolve (EmitContext ec
)
9147 ArrayList AllGetters
= new ArrayList();
9148 if (!CommonResolve (ec
))
9152 // Step 1: Query for all `Item' *properties*. Notice
9153 // that the actual methods are pointed from here.
9155 // This is a group of properties, piles of them.
9157 bool found_any
= false, found_any_getters
= false;
9158 Type lookup_type
= indexer_type
;
9161 ilist
= Indexers
.GetIndexersForType (current_type
, lookup_type
, loc
);
9162 if (ilist
!= null) {
9164 if (ilist
.Properties
!= null) {
9165 foreach (Indexers
.Indexer ix
in ilist
.Properties
) {
9166 if (ix
.Getter
!= null)
9167 AllGetters
.Add(ix
.Getter
);
9172 if (AllGetters
.Count
> 0) {
9173 found_any_getters
= true;
9174 get = (MethodInfo
) Invocation
.OverloadResolve (
9175 ec
, new MethodGroupExpr (AllGetters
, loc
),
9176 arguments
, false, loc
);
9180 Report
.Error (21, loc
,
9181 "Type `" + TypeManager
.CSharpName (indexer_type
) +
9182 "' does not have any indexers defined");
9186 if (!found_any_getters
) {
9187 Error (154, "indexer can not be used in this context, because " +
9188 "it lacks a `get' accessor");
9193 Error (1501, "No Overload for method `this' takes `" +
9194 arguments
.Count
+ "' arguments");
9199 // Only base will allow this invocation to happen.
9201 if (get.IsAbstract
&& this is BaseIndexerAccess
){
9202 Report
.Error (205, loc
, "Cannot call an abstract base indexer: " + Invocation
.FullMethodDesc (get));
9206 type
= get.ReturnType
;
9207 if (type
.IsPointer
&& !ec
.InUnsafe
){
9212 instance_expr
.CheckMarshallByRefAccess (ec
.ContainerType
);
9214 eclass
= ExprClass
.IndexerAccess
;
9218 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
9220 ArrayList AllSetters
= new ArrayList();
9221 if (!CommonResolve (ec
))
9224 bool found_any
= false, found_any_setters
= false;
9226 Indexers ilist
= Indexers
.GetIndexersForType (current_type
, indexer_type
, loc
);
9227 if (ilist
!= null) {
9229 if (ilist
.Properties
!= null) {
9230 foreach (Indexers
.Indexer ix
in ilist
.Properties
) {
9231 if (ix
.Setter
!= null)
9232 AllSetters
.Add(ix
.Setter
);
9236 if (AllSetters
.Count
> 0) {
9237 found_any_setters
= true;
9238 set_arguments
= (ArrayList
) arguments
.Clone ();
9239 set_arguments
.Add (new Argument (right_side
, Argument
.AType
.Expression
));
9240 set = (MethodInfo
) Invocation
.OverloadResolve (
9241 ec
, new MethodGroupExpr (AllSetters
, loc
),
9242 set_arguments
, false, loc
);
9246 Report
.Error (21, loc
,
9247 "Type `" + TypeManager
.CSharpName (indexer_type
) +
9248 "' does not have any indexers defined");
9252 if (!found_any_setters
) {
9253 Error (154, "indexer can not be used in this context, because " +
9254 "it lacks a `set' accessor");
9259 Error (1501, "No Overload for method `this' takes `" +
9260 arguments
.Count
+ "' arguments");
9265 // Only base will allow this invocation to happen.
9267 if (set.IsAbstract
&& this is BaseIndexerAccess
){
9268 Report
.Error (205, loc
, "Cannot call an abstract base indexer: " + Invocation
.FullMethodDesc (set));
9273 // Now look for the actual match in the list of indexers to set our "return" type
9275 type
= TypeManager
.void_type
; // default value
9276 foreach (Indexers
.Indexer ix
in ilist
.Properties
){
9277 if (ix
.Setter
== set){
9283 instance_expr
.CheckMarshallByRefAccess (ec
.ContainerType
);
9285 eclass
= ExprClass
.IndexerAccess
;
9289 bool prepared
= false;
9290 LocalTemporary temp
;
9292 public void Emit (EmitContext ec
, bool leave_copy
)
9294 Invocation
.EmitCall (ec
, is_base_indexer
, false, instance_expr
, get, arguments
, loc
, prepared
, false);
9296 ec
.ig
.Emit (OpCodes
.Dup
);
9297 temp
= new LocalTemporary (ec
, Type
);
9303 // source is ignored, because we already have a copy of it from the
9304 // LValue resolution and we have already constructed a pre-cached
9305 // version of the arguments (ea.set_arguments);
9307 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
9309 prepared
= prepare_for_load
;
9310 Argument a
= (Argument
) set_arguments
[set_arguments
.Count
- 1];
9315 ec
.ig
.Emit (OpCodes
.Dup
);
9316 temp
= new LocalTemporary (ec
, Type
);
9319 } else if (leave_copy
) {
9320 temp
= new LocalTemporary (ec
, Type
);
9326 Invocation
.EmitCall (ec
, is_base_indexer
, false, instance_expr
, set, set_arguments
, loc
, false, prepared
);
9333 public override void Emit (EmitContext ec
)
9340 /// The base operator for method names
9342 public class BaseAccess
: Expression
{
9343 public string member
;
9345 public BaseAccess (string member
, Location l
)
9347 this.member
= member
;
9351 public override Expression
DoResolve (EmitContext ec
)
9353 Expression c
= CommonResolve (ec
);
9359 // MethodGroups use this opportunity to flag an error on lacking ()
9361 if (!(c
is MethodGroupExpr
))
9362 return c
.Resolve (ec
);
9366 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
9368 Expression c
= CommonResolve (ec
);
9374 // MethodGroups use this opportunity to flag an error on lacking ()
9376 if (! (c
is MethodGroupExpr
))
9377 return c
.DoResolveLValue (ec
, right_side
);
9382 Expression
CommonResolve (EmitContext ec
)
9384 Expression member_lookup
;
9385 Type current_type
= ec
.ContainerType
;
9386 Type base_type
= current_type
.BaseType
;
9390 Error (1511, "Keyword base is not allowed in static method");
9394 if (ec
.IsFieldInitializer
){
9395 Error (1512, "Keyword base is not available in the current context");
9399 member_lookup
= MemberLookup (ec
, ec
.ContainerType
, null, base_type
,
9400 member
, AllMemberTypes
, AllBindingFlags
,
9402 if (member_lookup
== null) {
9403 MemberLookupFailed (
9404 ec
, base_type
, base_type
, member
, null, loc
);
9411 left
= new TypeExpression (base_type
, loc
);
9413 left
= ec
.GetThis (loc
);
9415 e
= MemberAccess
.ResolveMemberAccess (ec
, member_lookup
, left
, loc
, null);
9417 if (e
is PropertyExpr
){
9418 PropertyExpr pe
= (PropertyExpr
) e
;
9423 if (e
is MethodGroupExpr
)
9424 ((MethodGroupExpr
) e
).IsBase
= true;
9429 public override void Emit (EmitContext ec
)
9431 throw new Exception ("Should never be called");
9436 /// The base indexer operator
9438 public class BaseIndexerAccess
: IndexerAccess
{
9439 public BaseIndexerAccess (ArrayList args
, Location loc
)
9440 : base (null, true, loc
)
9442 arguments
= new ArrayList ();
9443 foreach (Expression tmp
in args
)
9444 arguments
.Add (new Argument (tmp
, Argument
.AType
.Expression
));
9447 protected override bool CommonResolve (EmitContext ec
)
9449 instance_expr
= ec
.GetThis (loc
);
9451 current_type
= ec
.ContainerType
.BaseType
;
9452 indexer_type
= current_type
;
9454 foreach (Argument a
in arguments
){
9455 if (!a
.Resolve (ec
, loc
))
9464 /// This class exists solely to pass the Type around and to be a dummy
9465 /// that can be passed to the conversion functions (this is used by
9466 /// foreach implementation to typecast the object return value from
9467 /// get_Current into the proper type. All code has been generated and
9468 /// we only care about the side effect conversions to be performed
9470 /// This is also now used as a placeholder where a no-action expression
9471 /// is needed (the `New' class).
9473 public class EmptyExpression
: Expression
{
9474 public static readonly EmptyExpression Null
= new EmptyExpression ();
9476 // TODO: should be protected
9477 public EmptyExpression ()
9479 type
= TypeManager
.object_type
;
9480 eclass
= ExprClass
.Value
;
9481 loc
= Location
.Null
;
9484 public EmptyExpression (Type t
)
9487 eclass
= ExprClass
.Value
;
9488 loc
= Location
.Null
;
9491 public override Expression
DoResolve (EmitContext ec
)
9496 public override void Emit (EmitContext ec
)
9498 // nothing, as we only exist to not do anything.
9502 // This is just because we might want to reuse this bad boy
9503 // instead of creating gazillions of EmptyExpressions.
9504 // (CanImplicitConversion uses it)
9506 public void SetType (Type t
)
9512 public class UserCast
: Expression
{
9516 public UserCast (MethodInfo method
, Expression source
, Location l
)
9518 this.method
= method
;
9519 this.source
= source
;
9520 type
= method
.ReturnType
;
9521 eclass
= ExprClass
.Value
;
9525 public Expression Source
{
9531 public override Expression
DoResolve (EmitContext ec
)
9534 // We are born fully resolved
9539 public override void Emit (EmitContext ec
)
9541 ILGenerator ig
= ec
.ig
;
9545 if (method
is MethodInfo
)
9546 ig
.Emit (OpCodes
.Call
, (MethodInfo
) method
);
9548 ig
.Emit (OpCodes
.Call
, (ConstructorInfo
) method
);
9554 // This class is used to "construct" the type during a typecast
9555 // operation. Since the Type.GetType class in .NET can parse
9556 // the type specification, we just use this to construct the type
9557 // one bit at a time.
9559 public class ComposedCast
: TypeExpr
{
9563 public ComposedCast (Expression left
, string dim
, Location l
)
9570 protected override TypeExpr
DoResolveAsTypeStep (EmitContext ec
)
9572 TypeExpr lexpr
= left
.ResolveAsTypeTerminal (ec
);
9576 Type ltype
= lexpr
.Type
;
9578 if ((ltype
== TypeManager
.void_type
) && (dim
!= "*")) {
9579 Report
.Error (1547, Location
,
9580 "Keyword 'void' cannot be used in this context");
9584 if ((dim
.Length
> 0) && (dim
[0] == '?')) {
9585 TypeExpr nullable
= new NullableType (left
, loc
);
9587 nullable
= new ComposedCast (nullable
, dim
.Substring (1), loc
);
9588 return nullable
.ResolveAsTypeTerminal (ec
);
9592 while ((pos
< dim
.Length
) && (dim
[pos
] == '[')) {
9595 if (dim
[pos
] == ']') {
9596 ltype
= ltype
.MakeArrayType ();
9599 if (pos
< dim
.Length
)
9603 eclass
= ExprClass
.Type
;
9608 while (dim
[pos
] == ',') {
9612 if ((dim
[pos
] != ']') || (pos
!= dim
.Length
-1))
9615 type
= ltype
.MakeArrayType (rank
+ 1);
9616 eclass
= ExprClass
.Type
;
9622 // ltype.Fullname is already fully qualified, so we can skip
9623 // a lot of probes, and go directly to TypeManager.LookupType
9625 string fname
= ltype
.FullName
!= null ? ltype
.FullName
: ltype
.Name
;
9626 string cname
= fname
+ dim
;
9627 type
= TypeManager
.LookupTypeDirect (cname
);
9630 // For arrays of enumerations we are having a problem
9631 // with the direct lookup. Need to investigate.
9633 // For now, fall back to the full lookup in that case.
9635 FullNamedExpression e
= ec
.DeclSpace
.LookupType (cname
, false, loc
);
9637 type
= ((TypeExpr
) e
).ResolveType (ec
);
9645 if (!ec
.InUnsafe
&& type
.IsPointer
){
9650 if (type
.IsArray
&& (type
.GetElementType () == TypeManager
.arg_iterator_type
||
9651 type
.GetElementType () == TypeManager
.typed_reference_type
)) {
9652 Report
.Error (611, loc
, "Array elements cannot be of type '{0}'", TypeManager
.CSharpName (type
.GetElementType ()));
9656 eclass
= ExprClass
.Type
;
9660 public override string Name
{
9666 public override string FullName
{
9668 return type
.FullName
;
9674 // This class is used to represent the address of an array, used
9675 // only by the Fixed statement, this is like the C "&a [0]" construct.
9677 public class ArrayPtr
: Expression
{
9680 public ArrayPtr (Expression array
, Location l
)
9682 Type array_type
= TypeManager
.GetElementType (array
.Type
);
9686 type
= TypeManager
.GetPointerType (array_type
);
9687 eclass
= ExprClass
.Value
;
9691 public override void Emit (EmitContext ec
)
9693 ILGenerator ig
= ec
.ig
;
9696 IntLiteral
.EmitInt (ig
, 0);
9697 ig
.Emit (OpCodes
.Ldelema
, TypeManager
.GetElementType (array
.Type
));
9700 public override Expression
DoResolve (EmitContext ec
)
9703 // We are born fully resolved
9710 // Used by the fixed statement
9712 public class StringPtr
: Expression
{
9715 public StringPtr (LocalBuilder b
, Location l
)
9718 eclass
= ExprClass
.Value
;
9719 type
= TypeManager
.char_ptr_type
;
9723 public override Expression
DoResolve (EmitContext ec
)
9725 // This should never be invoked, we are born in fully
9726 // initialized state.
9731 public override void Emit (EmitContext ec
)
9733 ILGenerator ig
= ec
.ig
;
9735 ig
.Emit (OpCodes
.Ldloc
, b
);
9736 ig
.Emit (OpCodes
.Conv_I
);
9737 ig
.Emit (OpCodes
.Call
, TypeManager
.int_get_offset_to_string_data
);
9738 ig
.Emit (OpCodes
.Add
);
9743 // Implements the `stackalloc' keyword
9745 public class StackAlloc
: Expression
{
9750 public StackAlloc (Expression type
, Expression count
, Location l
)
9757 public override Expression
DoResolve (EmitContext ec
)
9759 count
= count
.Resolve (ec
);
9763 if (count
.Type
!= TypeManager
.int32_type
){
9764 count
= Convert
.WideningConversionRequired (ec
, count
, TypeManager
.int32_type
, loc
);
9769 Constant c
= count
as Constant
;
9770 if (c
!= null && c
.IsNegative
) {
9771 Report
.Error (247, loc
, "Cannot use a negative size with stackalloc");
9775 if (ec
.CurrentBranching
.InCatch () ||
9776 ec
.CurrentBranching
.InFinally (true)) {
9778 "stackalloc can not be used in a catch or finally block");
9782 TypeExpr texpr
= t
.ResolveAsTypeTerminal (ec
);
9788 if (!TypeManager
.VerifyUnManaged (otype
, loc
))
9791 type
= TypeManager
.GetPointerType (otype
);
9792 eclass
= ExprClass
.Value
;
9797 public override void Emit (EmitContext ec
)
9799 int size
= GetTypeSize (otype
);
9800 ILGenerator ig
= ec
.ig
;
9803 ig
.Emit (OpCodes
.Sizeof
, otype
);
9805 IntConstant
.EmitInt (ig
, size
);
9807 ig
.Emit (OpCodes
.Mul
);
9808 ig
.Emit (OpCodes
.Localloc
);