2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001, 2002, 2003 Ximian, Inc.
11 namespace Mono
.CSharp
{
13 using System
.Collections
;
14 using System
.Diagnostics
;
15 using System
.Reflection
;
16 using System
.Reflection
.Emit
;
20 /// The ExprClass class contains the is used to pass the
21 /// classification of an expression (value, variable, namespace,
22 /// type, method group, property access, event access, indexer access,
25 public enum ExprClass
: byte {
40 /// This is used to tell Resolve in which types of expressions we're
44 public enum ResolveFlags
{
45 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
48 // Returns a type expression.
51 // Returns a method group.
54 // Allows SimpleNames to be returned.
55 // This is used by MemberAccess to construct long names that can not be
56 // partially resolved (namespace-qualified names for example).
59 // Mask of all the expression class flags.
62 // Disable control flow analysis while resolving the expression.
63 // This is used when resolving the instance expression of a field expression.
64 DisableFlowAnalysis
= 16
68 // This is just as a hint to AddressOf of what will be done with the
71 public enum AddressOp
{
78 /// This interface is implemented by variables
80 public interface IMemoryLocation
{
82 /// The AddressOf method should generate code that loads
83 /// the address of the object and leaves it on the stack.
85 /// The `mode' argument is used to notify the expression
86 /// of whether this will be used to read from the address or
87 /// write to the address.
89 /// This is just a hint that can be used to provide good error
90 /// reporting, and should have no other side effects.
92 void AddressOf (EmitContext ec
, AddressOp mode
);
96 /// This interface is implemented by variables
98 public interface IVariable
{
99 VariableInfo VariableInfo
{
103 bool VerifyFixed (bool is_expression
);
107 /// This interface denotes an expression which evaluates to a member
108 /// of a struct or a class.
110 public interface IMemberExpr
113 /// The name of this member.
120 /// Whether this is an instance member.
127 /// Whether this is a static member.
134 /// The type which declares this member.
141 /// The instance expression associated with this member, if it's a
142 /// non-static member.
144 Expression InstanceExpression
{
150 /// Base class for expressions
152 public abstract class Expression
{
153 public ExprClass eclass
;
155 protected Location loc
;
167 public Location Location
{
174 /// Utility wrapper routine for Error, just to beautify the code
176 public void Error (int error
, string s
)
178 if (!Location
.IsNull (loc
))
179 Report
.Error (error
, loc
, s
);
181 Report
.Error (error
, s
);
185 /// Utility wrapper routine for Warning, just to beautify the code
187 public void Warning (int warning
, string s
)
189 if (!Location
.IsNull (loc
))
190 Report
.Warning (warning
, loc
, s
);
192 Report
.Warning (warning
, s
);
196 /// Utility wrapper routine for Warning, only prints the warning if
197 /// warnings of level `level' are enabled.
199 public void Warning (int warning
, int level
, string s
)
201 if (level
<= RootContext
.WarningLevel
)
202 Warning (warning
, s
);
206 /// Performs semantic analysis on the Expression
210 /// The Resolve method is invoked to perform the semantic analysis
213 /// The return value is an expression (it can be the
214 /// same expression in some cases) or a new
215 /// expression that better represents this node.
217 /// For example, optimizations of Unary (LiteralInt)
218 /// would return a new LiteralInt with a negated
221 /// If there is an error during semantic analysis,
222 /// then an error should be reported (using Report)
223 /// and a null value should be returned.
225 /// There are two side effects expected from calling
226 /// Resolve(): the the field variable "eclass" should
227 /// be set to any value of the enumeration
228 /// `ExprClass' and the type variable should be set
229 /// to a valid type (this is the type of the
232 public abstract Expression
DoResolve (EmitContext ec
);
234 public virtual Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
236 return DoResolve (ec
);
240 // This is used if the expression should be resolved as a type.
241 // the default implementation fails. Use this method in
242 // those participants in the SimpleName chain system.
244 public virtual Expression
ResolveAsTypeStep (EmitContext ec
)
250 // This is used to resolve the expression as a type, a null
251 // value will be returned if the expression is not a type
254 public TypeExpr
ResolveAsTypeTerminal (EmitContext ec
)
256 return ResolveAsTypeStep (ec
) as TypeExpr
;
260 /// Resolves an expression and performs semantic analysis on it.
264 /// Currently Resolve wraps DoResolve to perform sanity
265 /// checking and assertion checking on what we expect from Resolve.
267 public Expression
Resolve (EmitContext ec
, ResolveFlags flags
)
269 if ((flags
& ResolveFlags
.MaskExprClass
) == ResolveFlags
.Type
)
270 return ResolveAsTypeStep (ec
);
272 bool old_do_flow_analysis
= ec
.DoFlowAnalysis
;
273 if ((flags
& ResolveFlags
.DisableFlowAnalysis
) != 0)
274 ec
.DoFlowAnalysis
= false;
277 if (this is SimpleName
)
278 e
= ((SimpleName
) this).DoResolveAllowStatic (ec
);
282 ec
.DoFlowAnalysis
= old_do_flow_analysis
;
287 if (e
is SimpleName
){
288 SimpleName s
= (SimpleName
) e
;
290 if ((flags
& ResolveFlags
.SimpleName
) == 0) {
291 MemberLookupFailed (ec
, null, ec
.ContainerType
, s
.Name
,
292 ec
.DeclSpace
.Name
, loc
);
299 if ((e
is TypeExpr
) || (e
is ComposedCast
)) {
300 if ((flags
& ResolveFlags
.Type
) == 0) {
301 e
.Error_UnexpectedKind (flags
);
310 if ((flags
& ResolveFlags
.VariableOrValue
) == 0) {
311 e
.Error_UnexpectedKind (flags
);
316 case ExprClass
.MethodGroup
:
317 if (!RootContext
.V2
){
318 if ((flags
& ResolveFlags
.MethodGroup
) == 0) {
319 ((MethodGroupExpr
) e
).ReportUsageError ();
325 case ExprClass
.Value
:
326 case ExprClass
.Variable
:
327 case ExprClass
.PropertyAccess
:
328 case ExprClass
.EventAccess
:
329 case ExprClass
.IndexerAccess
:
330 if ((flags
& ResolveFlags
.VariableOrValue
) == 0) {
331 Console
.WriteLine ("I got: {0} and {1}", e
.GetType (), e
);
332 Console
.WriteLine ("I am {0} and {1}", this.GetType (), this);
333 FieldInfo fi
= ((FieldExpr
) e
).FieldInfo
;
335 Console
.WriteLine ("{0} and {1}", fi
.DeclaringType
, fi
.Name
);
336 e
.Error_UnexpectedKind (flags
);
342 throw new Exception ("Expression " + e
.GetType () +
343 " ExprClass is Invalid after resolve");
347 throw new Exception (
348 "Expression " + e
.GetType () +
349 " did not set its type after Resolve\n" +
350 "called from: " + this.GetType ());
356 /// Resolves an expression and performs semantic analysis on it.
358 public Expression
Resolve (EmitContext ec
)
360 return Resolve (ec
, ResolveFlags
.VariableOrValue
);
364 /// Resolves an expression for LValue assignment
368 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
369 /// checking and assertion checking on what we expect from Resolve
371 public Expression
ResolveLValue (EmitContext ec
, Expression right_side
)
373 Expression e
= DoResolveLValue (ec
, right_side
);
376 if (e
is SimpleName
){
377 SimpleName s
= (SimpleName
) e
;
378 MemberLookupFailed (ec
, null, ec
.ContainerType
, s
.Name
,
379 ec
.DeclSpace
.Name
, loc
);
383 if (e
.eclass
== ExprClass
.Invalid
)
384 throw new Exception ("Expression " + e
+
385 " ExprClass is Invalid after resolve");
387 if (e
.eclass
== ExprClass
.MethodGroup
) {
388 ((MethodGroupExpr
) e
).ReportUsageError ();
393 throw new Exception ("Expression " + e
+
394 " did not set its type after Resolve");
401 /// Emits the code for the expression
405 /// The Emit method is invoked to generate the code
406 /// for the expression.
408 public abstract void Emit (EmitContext ec
);
410 public virtual void EmitBranchable (EmitContext ec
, Label target
, bool onTrue
)
413 ec
.ig
.Emit (onTrue
? OpCodes
.Brtrue
: OpCodes
.Brfalse
, target
);
417 /// Protected constructor. Only derivate types should
418 /// be able to be created
421 protected Expression ()
423 eclass
= ExprClass
.Invalid
;
428 /// Returns a literalized version of a literal FieldInfo
432 /// The possible return values are:
433 /// IntConstant, UIntConstant
434 /// LongLiteral, ULongConstant
435 /// FloatConstant, DoubleConstant
438 /// The value returned is already resolved.
440 public static Constant
Constantify (object v
, Type t
)
442 if (t
== TypeManager
.int32_type
)
443 return new IntConstant ((int) v
);
444 else if (t
== TypeManager
.uint32_type
)
445 return new UIntConstant ((uint) v
);
446 else if (t
== TypeManager
.int64_type
)
447 return new LongConstant ((long) v
);
448 else if (t
== TypeManager
.uint64_type
)
449 return new ULongConstant ((ulong) v
);
450 else if (t
== TypeManager
.float_type
)
451 return new FloatConstant ((float) v
);
452 else if (t
== TypeManager
.double_type
)
453 return new DoubleConstant ((double) v
);
454 else if (t
== TypeManager
.string_type
)
455 return new StringConstant ((string) v
);
456 else if (t
== TypeManager
.short_type
)
457 return new ShortConstant ((short)v
);
458 else if (t
== TypeManager
.ushort_type
)
459 return new UShortConstant ((ushort)v
);
460 else if (t
== TypeManager
.sbyte_type
)
461 return new SByteConstant (((sbyte)v
));
462 else if (t
== TypeManager
.byte_type
)
463 return new ByteConstant ((byte)v
);
464 else if (t
== TypeManager
.char_type
)
465 return new CharConstant ((char)v
);
466 else if (t
== TypeManager
.bool_type
)
467 return new BoolConstant ((bool) v
);
468 else if (TypeManager
.IsEnumType (t
)){
469 Constant e
= Constantify (v
, TypeManager
.TypeToCoreType (v
.GetType ()));
471 return new EnumConstant (e
, t
);
473 throw new Exception ("Unknown type for constant (" + t
+
478 /// Returns a fully formed expression after a MemberLookup
480 public static Expression
ExprClassFromMemberInfo (EmitContext ec
, MemberInfo mi
, Location loc
)
483 return new EventExpr ((EventInfo
) mi
, loc
);
484 else if (mi
is FieldInfo
)
485 return new FieldExpr ((FieldInfo
) mi
, loc
);
486 else if (mi
is PropertyInfo
)
487 return new PropertyExpr (ec
, (PropertyInfo
) mi
, loc
);
488 else if (mi
is Type
){
489 return new TypeExpression ((System
.Type
) mi
, loc
);
496 // FIXME: Probably implement a cache for (t,name,current_access_set)?
498 // This code could use some optimizations, but we need to do some
499 // measurements. For example, we could use a delegate to `flag' when
500 // something can not any longer be a method-group (because it is something
504 // If the return value is an Array, then it is an array of
507 // If the return value is an MemberInfo, it is anything, but a Method
511 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
512 // the arguments here and have MemberLookup return only the methods that
513 // match the argument count/type, unlike we are doing now (we delay this
516 // This is so we can catch correctly attempts to invoke instance methods
517 // from a static body (scan for error 120 in ResolveSimpleName).
520 // FIXME: Potential optimization, have a static ArrayList
523 public static Expression
MemberLookup (EmitContext ec
, Type queried_type
, string name
,
524 MemberTypes mt
, BindingFlags bf
, Location loc
)
526 return MemberLookup (ec
, ec
.ContainerType
, null, queried_type
, name
, mt
, bf
, loc
);
530 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
531 // `qualifier_type' or null to lookup members in the current class.
534 public static Expression
MemberLookup (EmitContext ec
, Type container_type
,
535 Type qualifier_type
, Type queried_type
,
536 string name
, MemberTypes mt
,
537 BindingFlags bf
, Location loc
)
539 MemberInfo
[] mi
= TypeManager
.MemberLookup (container_type
, qualifier_type
,
540 queried_type
, mt
, bf
, name
);
545 int count
= mi
.Length
;
547 if (mi
[0] is MethodBase
)
548 return new MethodGroupExpr (mi
, loc
);
553 return ExprClassFromMemberInfo (ec
, mi
[0], loc
);
556 public const MemberTypes AllMemberTypes
=
557 MemberTypes
.Constructor
|
561 MemberTypes
.NestedType
|
562 MemberTypes
.Property
;
564 public const BindingFlags AllBindingFlags
=
565 BindingFlags
.Public
|
566 BindingFlags
.Static
|
567 BindingFlags
.Instance
;
569 public static Expression
MemberLookup (EmitContext ec
, Type queried_type
,
570 string name
, Location loc
)
572 return MemberLookup (ec
, ec
.ContainerType
, null, queried_type
, name
,
573 AllMemberTypes
, AllBindingFlags
, loc
);
576 public static Expression
MemberLookup (EmitContext ec
, Type qualifier_type
,
577 Type queried_type
, string name
, Location loc
)
579 return MemberLookup (ec
, ec
.ContainerType
, qualifier_type
, queried_type
,
580 name
, AllMemberTypes
, AllBindingFlags
, loc
);
583 public static Expression
MethodLookup (EmitContext ec
, Type queried_type
,
584 string name
, Location loc
)
586 return MemberLookup (ec
, ec
.ContainerType
, null, queried_type
, name
,
587 MemberTypes
.Method
, AllBindingFlags
, loc
);
591 /// This is a wrapper for MemberLookup that is not used to "probe", but
592 /// to find a final definition. If the final definition is not found, we
593 /// look for private members and display a useful debugging message if we
596 public static Expression
MemberLookupFinal (EmitContext ec
, Type qualifier_type
,
597 Type queried_type
, string name
, Location loc
)
599 return MemberLookupFinal (ec
, qualifier_type
, queried_type
, name
,
600 AllMemberTypes
, AllBindingFlags
, loc
);
603 public static Expression
MemberLookupFinal (EmitContext ec
, Type qualifier_type
,
604 Type queried_type
, string name
,
605 MemberTypes mt
, BindingFlags bf
,
610 int errors
= Report
.Errors
;
612 e
= MemberLookup (ec
, ec
.ContainerType
, qualifier_type
, queried_type
,
618 // Error has already been reported.
619 if (errors
< Report
.Errors
)
622 MemberLookupFailed (ec
, qualifier_type
, queried_type
, name
, null, loc
);
626 public static void MemberLookupFailed (EmitContext ec
, Type qualifier_type
,
627 Type queried_type
, string name
,
628 string class_name
, Location loc
)
630 object lookup
= TypeManager
.MemberLookup (queried_type
, null, queried_type
,
631 AllMemberTypes
, AllBindingFlags
|
632 BindingFlags
.NonPublic
, name
);
634 if (lookup
== null) {
635 if (class_name
!= null)
636 Report
.Error (103, loc
, "The name `" + name
+ "' could not be " +
637 "found in `" + class_name
+ "'");
640 117, loc
, "`" + queried_type
+ "' does not contain a " +
641 "definition for `" + name
+ "'");
645 if ((qualifier_type
!= null) && (qualifier_type
!= ec
.ContainerType
) &&
646 ec
.ContainerType
.IsSubclassOf (qualifier_type
)) {
647 // Although a derived class can access protected members of
648 // its base class it cannot do so through an instance of the
649 // base class (CS1540). If the qualifier_type is a parent of the
650 // ec.ContainerType and the lookup succeeds with the latter one,
651 // then we are in this situation.
653 lookup
= TypeManager
.MemberLookup (
654 ec
.ContainerType
, ec
.ContainerType
, ec
.ContainerType
,
655 AllMemberTypes
, AllBindingFlags
, name
);
657 if (lookup
!= null) {
659 1540, loc
, "Cannot access protected member `" +
660 TypeManager
.CSharpName (qualifier_type
) + "." +
661 name
+ "' " + "via a qualifier of type `" +
662 TypeManager
.CSharpName (qualifier_type
) + "'; the " +
663 "qualifier must be of type `" +
664 TypeManager
.CSharpName (ec
.ContainerType
) + "' " +
665 "(or derived from it)");
670 if (qualifier_type
!= null)
672 122, loc
, "`" + TypeManager
.CSharpName (qualifier_type
) + "." +
673 name
+ "' is inaccessible due to its protection level");
674 else if (name
== ".ctor") {
675 Report
.Error (143, loc
, String
.Format ("The type {0} has no constructors defined",
676 TypeManager
.CSharpName (queried_type
)));
679 122, loc
, "`" + name
+ "' is inaccessible due to its " +
684 static public MemberInfo
GetFieldFromEvent (EventExpr event_expr
)
686 EventInfo ei
= event_expr
.EventInfo
;
688 return TypeManager
.GetPrivateFieldOfEvent (ei
);
692 /// Returns an expression that can be used to invoke operator true
693 /// on the expression if it exists.
695 static public StaticCallExpr
GetOperatorTrue (EmitContext ec
, Expression e
, Location loc
)
697 return GetOperatorTrueOrFalse (ec
, e
, true, loc
);
701 /// Returns an expression that can be used to invoke operator false
702 /// on the expression if it exists.
704 static public StaticCallExpr
GetOperatorFalse (EmitContext ec
, Expression e
, Location loc
)
706 return GetOperatorTrueOrFalse (ec
, e
, false, loc
);
709 static StaticCallExpr
GetOperatorTrueOrFalse (EmitContext ec
, Expression e
, bool is_true
, Location loc
)
712 Expression operator_group
;
714 operator_group
= MethodLookup (ec
, e
.Type
, is_true
? "op_True" : "op_False", loc
);
715 if (operator_group
== null)
718 ArrayList arguments
= new ArrayList ();
719 arguments
.Add (new Argument (e
, Argument
.AType
.Expression
));
720 method
= Invocation
.OverloadResolve (ec
, (MethodGroupExpr
) operator_group
, arguments
, loc
);
725 return new StaticCallExpr ((MethodInfo
) method
, arguments
, loc
);
729 /// Resolves the expression `e' into a boolean expression: either through
730 /// an implicit conversion, or through an `operator true' invocation
732 public static Expression
ResolveBoolean (EmitContext ec
, Expression e
, Location loc
)
738 Expression converted
= e
;
739 if (e
.Type
!= TypeManager
.bool_type
)
740 converted
= Convert
.ImplicitConversion (ec
, e
, TypeManager
.bool_type
, new Location (-1));
743 // If no implicit conversion to bool exists, try using `operator true'
745 if (converted
== null){
746 Expression operator_true
= Expression
.GetOperatorTrue (ec
, e
, loc
);
747 if (operator_true
== null){
749 31, loc
, "Can not convert the expression to a boolean");
759 static string ExprClassName (ExprClass c
)
762 case ExprClass
.Invalid
:
764 case ExprClass
.Value
:
766 case ExprClass
.Variable
:
768 case ExprClass
.Namespace
:
772 case ExprClass
.MethodGroup
:
773 return "method group";
774 case ExprClass
.PropertyAccess
:
775 return "property access";
776 case ExprClass
.EventAccess
:
777 return "event access";
778 case ExprClass
.IndexerAccess
:
779 return "indexer access";
780 case ExprClass
.Nothing
:
783 throw new Exception ("Should not happen");
787 /// Reports that we were expecting `expr' to be of class `expected'
789 public void Error_UnexpectedKind (string expected
)
791 string kind
= "Unknown";
793 kind
= ExprClassName (eclass
);
795 Error (118, "Expression denotes a `" + kind
+
796 "' where a `" + expected
+ "' was expected");
799 public void Error_UnexpectedKind (ResolveFlags flags
)
801 ArrayList valid
= new ArrayList (10);
803 if ((flags
& ResolveFlags
.VariableOrValue
) != 0) {
804 valid
.Add ("variable");
808 if ((flags
& ResolveFlags
.Type
) != 0)
811 if ((flags
& ResolveFlags
.MethodGroup
) != 0)
812 valid
.Add ("method group");
814 if ((flags
& ResolveFlags
.SimpleName
) != 0)
815 valid
.Add ("simple name");
817 if (valid
.Count
== 0)
818 valid
.Add ("unknown");
820 StringBuilder sb
= new StringBuilder ();
821 for (int i
= 0; i
< valid
.Count
; i
++) {
824 else if (i
== valid
.Count
)
826 sb
.Append (valid
[i
]);
829 string kind
= ExprClassName (eclass
);
831 Error (119, "Expression denotes a `" + kind
+ "' where " +
832 "a `" + sb
.ToString () + "' was expected");
835 static public void Error_ConstantValueCannotBeConverted (Location l
, string val
, Type t
)
837 Report
.Error (31, l
, "Constant value `" + val
+ "' cannot be converted to " +
838 TypeManager
.CSharpName (t
));
841 public static void UnsafeError (Location loc
)
843 Report
.Error (214, loc
, "Pointers may only be used in an unsafe context");
847 /// Converts the IntConstant, UIntConstant, LongConstant or
848 /// ULongConstant into the integral target_type. Notice
849 /// that we do not return an `Expression' we do return
850 /// a boxed integral type.
852 /// FIXME: Since I added the new constants, we need to
853 /// also support conversions from CharConstant, ByteConstant,
854 /// SByteConstant, UShortConstant, ShortConstant
856 /// This is used by the switch statement, so the domain
857 /// of work is restricted to the literals above, and the
858 /// targets are int32, uint32, char, byte, sbyte, ushort,
859 /// short, uint64 and int64
861 public static object ConvertIntLiteral (Constant c
, Type target_type
, Location loc
)
863 if (!Convert
.ImplicitStandardConversionExists (c
, target_type
)){
864 Convert
.Error_CannotImplicitConversion (loc
, c
.Type
, target_type
);
870 if (c
.Type
== target_type
)
871 return ((Constant
) c
).GetValue ();
874 // Make into one of the literals we handle, we dont really care
875 // about this value as we will just return a few limited types
877 if (c
is EnumConstant
)
878 c
= ((EnumConstant
)c
).WidenToCompilerConstant ();
880 if (c
is IntConstant
){
881 int v
= ((IntConstant
) c
).Value
;
883 if (target_type
== TypeManager
.uint32_type
){
886 } else if (target_type
== TypeManager
.char_type
){
887 if (v
>= Char
.MinValue
&& v
<= Char
.MaxValue
)
889 } else if (target_type
== TypeManager
.byte_type
){
890 if (v
>= Byte
.MinValue
&& v
<= Byte
.MaxValue
)
892 } else if (target_type
== TypeManager
.sbyte_type
){
893 if (v
>= SByte
.MinValue
&& v
<= SByte
.MaxValue
)
895 } else if (target_type
== TypeManager
.short_type
){
896 if (v
>= Int16
.MinValue
&& v
<= UInt16
.MaxValue
)
898 } else if (target_type
== TypeManager
.ushort_type
){
899 if (v
>= UInt16
.MinValue
&& v
<= UInt16
.MaxValue
)
901 } else if (target_type
== TypeManager
.int64_type
)
903 else if (target_type
== TypeManager
.uint64_type
){
909 } else if (c
is UIntConstant
){
910 uint v
= ((UIntConstant
) c
).Value
;
912 if (target_type
== TypeManager
.int32_type
){
913 if (v
<= Int32
.MaxValue
)
915 } else if (target_type
== TypeManager
.char_type
){
916 if (v
>= Char
.MinValue
&& v
<= Char
.MaxValue
)
918 } else if (target_type
== TypeManager
.byte_type
){
919 if (v
<= Byte
.MaxValue
)
921 } else if (target_type
== TypeManager
.sbyte_type
){
922 if (v
<= SByte
.MaxValue
)
924 } else if (target_type
== TypeManager
.short_type
){
925 if (v
<= UInt16
.MaxValue
)
927 } else if (target_type
== TypeManager
.ushort_type
){
928 if (v
<= UInt16
.MaxValue
)
930 } else if (target_type
== TypeManager
.int64_type
)
932 else if (target_type
== TypeManager
.uint64_type
)
935 } else if (c
is LongConstant
){
936 long v
= ((LongConstant
) c
).Value
;
938 if (target_type
== TypeManager
.int32_type
){
939 if (v
>= UInt32
.MinValue
&& v
<= UInt32
.MaxValue
)
941 } else if (target_type
== TypeManager
.uint32_type
){
942 if (v
>= 0 && v
<= UInt32
.MaxValue
)
944 } else if (target_type
== TypeManager
.char_type
){
945 if (v
>= Char
.MinValue
&& v
<= Char
.MaxValue
)
947 } else if (target_type
== TypeManager
.byte_type
){
948 if (v
>= Byte
.MinValue
&& v
<= Byte
.MaxValue
)
950 } else if (target_type
== TypeManager
.sbyte_type
){
951 if (v
>= SByte
.MinValue
&& v
<= SByte
.MaxValue
)
953 } else if (target_type
== TypeManager
.short_type
){
954 if (v
>= Int16
.MinValue
&& v
<= UInt16
.MaxValue
)
956 } else if (target_type
== TypeManager
.ushort_type
){
957 if (v
>= UInt16
.MinValue
&& v
<= UInt16
.MaxValue
)
959 } else if (target_type
== TypeManager
.uint64_type
){
964 } else if (c
is ULongConstant
){
965 ulong v
= ((ULongConstant
) c
).Value
;
967 if (target_type
== TypeManager
.int32_type
){
968 if (v
<= Int32
.MaxValue
)
970 } else if (target_type
== TypeManager
.uint32_type
){
971 if (v
<= UInt32
.MaxValue
)
973 } else if (target_type
== TypeManager
.char_type
){
974 if (v
>= Char
.MinValue
&& v
<= Char
.MaxValue
)
976 } else if (target_type
== TypeManager
.byte_type
){
977 if (v
>= Byte
.MinValue
&& v
<= Byte
.MaxValue
)
979 } else if (target_type
== TypeManager
.sbyte_type
){
980 if (v
<= (int) SByte
.MaxValue
)
982 } else if (target_type
== TypeManager
.short_type
){
983 if (v
<= UInt16
.MaxValue
)
985 } else if (target_type
== TypeManager
.ushort_type
){
986 if (v
<= UInt16
.MaxValue
)
988 } else if (target_type
== TypeManager
.int64_type
){
989 if (v
<= Int64
.MaxValue
)
993 } else if (c
is ByteConstant
){
994 byte v
= ((ByteConstant
) c
).Value
;
996 if (target_type
== TypeManager
.int32_type
)
998 else if (target_type
== TypeManager
.uint32_type
)
1000 else if (target_type
== TypeManager
.char_type
)
1002 else if (target_type
== TypeManager
.sbyte_type
){
1003 if (v
<= SByte
.MaxValue
)
1005 } else if (target_type
== TypeManager
.short_type
)
1007 else if (target_type
== TypeManager
.ushort_type
)
1009 else if (target_type
== TypeManager
.int64_type
)
1011 else if (target_type
== TypeManager
.uint64_type
)
1014 } else if (c
is SByteConstant
){
1015 sbyte v
= ((SByteConstant
) c
).Value
;
1017 if (target_type
== TypeManager
.int32_type
)
1019 else if (target_type
== TypeManager
.uint32_type
){
1022 } else if (target_type
== TypeManager
.char_type
){
1025 } else if (target_type
== TypeManager
.byte_type
){
1028 } else if (target_type
== TypeManager
.short_type
)
1030 else if (target_type
== TypeManager
.ushort_type
){
1033 } else if (target_type
== TypeManager
.int64_type
)
1035 else if (target_type
== TypeManager
.uint64_type
){
1040 } else if (c
is ShortConstant
){
1041 short v
= ((ShortConstant
) c
).Value
;
1043 if (target_type
== TypeManager
.int32_type
){
1045 } else if (target_type
== TypeManager
.uint32_type
){
1048 } else if (target_type
== TypeManager
.char_type
){
1051 } else if (target_type
== TypeManager
.byte_type
){
1052 if (v
>= Byte
.MinValue
&& v
<= Byte
.MaxValue
)
1054 } else if (target_type
== TypeManager
.sbyte_type
){
1055 if (v
>= SByte
.MinValue
&& v
<= SByte
.MaxValue
)
1057 } else if (target_type
== TypeManager
.ushort_type
){
1060 } else if (target_type
== TypeManager
.int64_type
)
1062 else if (target_type
== TypeManager
.uint64_type
)
1066 } else if (c
is UShortConstant
){
1067 ushort v
= ((UShortConstant
) c
).Value
;
1069 if (target_type
== TypeManager
.int32_type
)
1071 else if (target_type
== TypeManager
.uint32_type
)
1073 else if (target_type
== TypeManager
.char_type
){
1074 if (v
>= Char
.MinValue
&& v
<= Char
.MaxValue
)
1076 } else if (target_type
== TypeManager
.byte_type
){
1077 if (v
>= Byte
.MinValue
&& v
<= Byte
.MaxValue
)
1079 } else if (target_type
== TypeManager
.sbyte_type
){
1080 if (v
<= SByte
.MaxValue
)
1082 } else if (target_type
== TypeManager
.short_type
){
1083 if (v
<= Int16
.MaxValue
)
1085 } else if (target_type
== TypeManager
.int64_type
)
1087 else if (target_type
== TypeManager
.uint64_type
)
1091 } else if (c
is CharConstant
){
1092 char v
= ((CharConstant
) c
).Value
;
1094 if (target_type
== TypeManager
.int32_type
)
1096 else if (target_type
== TypeManager
.uint32_type
)
1098 else if (target_type
== TypeManager
.byte_type
){
1099 if (v
>= Byte
.MinValue
&& v
<= Byte
.MaxValue
)
1101 } else if (target_type
== TypeManager
.sbyte_type
){
1102 if (v
<= SByte
.MaxValue
)
1104 } else if (target_type
== TypeManager
.short_type
){
1105 if (v
<= Int16
.MaxValue
)
1107 } else if (target_type
== TypeManager
.ushort_type
)
1109 else if (target_type
== TypeManager
.int64_type
)
1111 else if (target_type
== TypeManager
.uint64_type
)
1116 Error_ConstantValueCannotBeConverted (loc
, s
, target_type
);
1121 // Load the object from the pointer.
1123 public static void LoadFromPtr (ILGenerator ig
, Type t
)
1125 if (t
== TypeManager
.int32_type
)
1126 ig
.Emit (OpCodes
.Ldind_I4
);
1127 else if (t
== TypeManager
.uint32_type
)
1128 ig
.Emit (OpCodes
.Ldind_U4
);
1129 else if (t
== TypeManager
.short_type
)
1130 ig
.Emit (OpCodes
.Ldind_I2
);
1131 else if (t
== TypeManager
.ushort_type
)
1132 ig
.Emit (OpCodes
.Ldind_U2
);
1133 else if (t
== TypeManager
.char_type
)
1134 ig
.Emit (OpCodes
.Ldind_U2
);
1135 else if (t
== TypeManager
.byte_type
)
1136 ig
.Emit (OpCodes
.Ldind_U1
);
1137 else if (t
== TypeManager
.sbyte_type
)
1138 ig
.Emit (OpCodes
.Ldind_I1
);
1139 else if (t
== TypeManager
.uint64_type
)
1140 ig
.Emit (OpCodes
.Ldind_I8
);
1141 else if (t
== TypeManager
.int64_type
)
1142 ig
.Emit (OpCodes
.Ldind_I8
);
1143 else if (t
== TypeManager
.float_type
)
1144 ig
.Emit (OpCodes
.Ldind_R4
);
1145 else if (t
== TypeManager
.double_type
)
1146 ig
.Emit (OpCodes
.Ldind_R8
);
1147 else if (t
== TypeManager
.bool_type
)
1148 ig
.Emit (OpCodes
.Ldind_I1
);
1149 else if (t
== TypeManager
.intptr_type
)
1150 ig
.Emit (OpCodes
.Ldind_I
);
1151 else if (TypeManager
.IsEnumType (t
)) {
1152 if (t
== TypeManager
.enum_type
)
1153 ig
.Emit (OpCodes
.Ldind_Ref
);
1155 LoadFromPtr (ig
, TypeManager
.EnumToUnderlying (t
));
1156 } else if (t
.IsValueType
)
1157 ig
.Emit (OpCodes
.Ldobj
, t
);
1158 else if (t
.IsPointer
)
1159 ig
.Emit (OpCodes
.Ldind_I
);
1161 ig
.Emit (OpCodes
.Ldind_Ref
);
1165 // The stack contains the pointer and the value of type `type'
1167 public static void StoreFromPtr (ILGenerator ig
, Type type
)
1169 if (TypeManager
.IsEnumType (type
))
1170 type
= TypeManager
.EnumToUnderlying (type
);
1171 if (type
== TypeManager
.int32_type
|| type
== TypeManager
.uint32_type
)
1172 ig
.Emit (OpCodes
.Stind_I4
);
1173 else if (type
== TypeManager
.int64_type
|| type
== TypeManager
.uint64_type
)
1174 ig
.Emit (OpCodes
.Stind_I8
);
1175 else if (type
== TypeManager
.char_type
|| type
== TypeManager
.short_type
||
1176 type
== TypeManager
.ushort_type
)
1177 ig
.Emit (OpCodes
.Stind_I2
);
1178 else if (type
== TypeManager
.float_type
)
1179 ig
.Emit (OpCodes
.Stind_R4
);
1180 else if (type
== TypeManager
.double_type
)
1181 ig
.Emit (OpCodes
.Stind_R8
);
1182 else if (type
== TypeManager
.byte_type
|| type
== TypeManager
.sbyte_type
||
1183 type
== TypeManager
.bool_type
)
1184 ig
.Emit (OpCodes
.Stind_I1
);
1185 else if (type
== TypeManager
.intptr_type
)
1186 ig
.Emit (OpCodes
.Stind_I
);
1187 else if (type
.IsValueType
)
1188 ig
.Emit (OpCodes
.Stobj
, type
);
1190 ig
.Emit (OpCodes
.Stind_Ref
);
1194 // Returns the size of type `t' if known, otherwise, 0
1196 public static int GetTypeSize (Type t
)
1198 t
= TypeManager
.TypeToCoreType (t
);
1199 if (t
== TypeManager
.int32_type
||
1200 t
== TypeManager
.uint32_type
||
1201 t
== TypeManager
.float_type
)
1203 else if (t
== TypeManager
.int64_type
||
1204 t
== TypeManager
.uint64_type
||
1205 t
== TypeManager
.double_type
)
1207 else if (t
== TypeManager
.byte_type
||
1208 t
== TypeManager
.sbyte_type
||
1209 t
== TypeManager
.bool_type
)
1211 else if (t
== TypeManager
.short_type
||
1212 t
== TypeManager
.char_type
||
1213 t
== TypeManager
.ushort_type
)
1215 else if (t
== TypeManager
.decimal_type
)
1222 // Default implementation of IAssignMethod.CacheTemporaries
1224 public void CacheTemporaries (EmitContext ec
)
1228 static void Error_NegativeArrayIndex (Location loc
)
1230 Report
.Error (284, loc
, "Can not create array with a negative size");
1234 // Converts `source' to an int, uint, long or ulong.
1236 public Expression
ExpressionToArrayArgument (EmitContext ec
, Expression source
, Location loc
)
1240 bool old_checked
= ec
.CheckState
;
1241 ec
.CheckState
= true;
1243 target
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.int32_type
, loc
);
1244 if (target
== null){
1245 target
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.uint32_type
, loc
);
1246 if (target
== null){
1247 target
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.int64_type
, loc
);
1248 if (target
== null){
1249 target
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.uint64_type
, loc
);
1251 Convert
.Error_CannotImplicitConversion (loc
, source
.Type
, TypeManager
.int32_type
);
1255 ec
.CheckState
= old_checked
;
1258 // Only positive constants are allowed at compile time
1260 if (target
is Constant
){
1261 if (target
is IntConstant
){
1262 if (((IntConstant
) target
).Value
< 0){
1263 Error_NegativeArrayIndex (loc
);
1268 if (target
is LongConstant
){
1269 if (((LongConstant
) target
).Value
< 0){
1270 Error_NegativeArrayIndex (loc
);
1283 /// This is just a base class for expressions that can
1284 /// appear on statements (invocations, object creation,
1285 /// assignments, post/pre increment and decrement). The idea
1286 /// being that they would support an extra Emition interface that
1287 /// does not leave a result on the stack.
1289 public abstract class ExpressionStatement
: Expression
{
1291 public virtual ExpressionStatement
ResolveStatement (EmitContext ec
)
1293 Expression e
= Resolve (ec
);
1297 ExpressionStatement es
= e
as ExpressionStatement
;
1299 Error (201, "Only assignment, call, increment, decrement and new object " +
1300 "expressions can be used as a statement");
1306 /// Requests the expression to be emitted in a `statement'
1307 /// context. This means that no new value is left on the
1308 /// stack after invoking this method (constrasted with
1309 /// Emit that will always leave a value on the stack).
1311 public abstract void EmitStatement (EmitContext ec
);
1315 /// This kind of cast is used to encapsulate the child
1316 /// whose type is child.Type into an expression that is
1317 /// reported to return "return_type". This is used to encapsulate
1318 /// expressions which have compatible types, but need to be dealt
1319 /// at higher levels with.
1321 /// For example, a "byte" expression could be encapsulated in one
1322 /// of these as an "unsigned int". The type for the expression
1323 /// would be "unsigned int".
1326 public class EmptyCast
: Expression
{
1327 protected Expression child
;
1329 public Expression Child
{
1335 public EmptyCast (Expression child
, Type return_type
)
1337 eclass
= child
.eclass
;
1342 public override Expression
DoResolve (EmitContext ec
)
1344 // This should never be invoked, we are born in fully
1345 // initialized state.
1350 public override void Emit (EmitContext ec
)
1357 // We need to special case this since an empty cast of
1358 // a NullLiteral is still a Constant
1360 public class NullCast
: Constant
{
1361 protected Expression child
;
1363 public NullCast (Expression child
, Type return_type
)
1365 eclass
= child
.eclass
;
1370 override public string AsString ()
1375 public override object GetValue ()
1380 public override Expression
DoResolve (EmitContext ec
)
1382 // This should never be invoked, we are born in fully
1383 // initialized state.
1388 public override void Emit (EmitContext ec
)
1396 /// This class is used to wrap literals which belong inside Enums
1398 public class EnumConstant
: Constant
{
1399 public Constant Child
;
1401 public EnumConstant (Constant child
, Type enum_type
)
1403 eclass
= child
.eclass
;
1408 public override Expression
DoResolve (EmitContext ec
)
1410 // This should never be invoked, we are born in fully
1411 // initialized state.
1416 public override void Emit (EmitContext ec
)
1421 public override object GetValue ()
1423 return Child
.GetValue ();
1427 // Converts from one of the valid underlying types for an enumeration
1428 // (int32, uint32, int64, uint64, short, ushort, byte, sbyte) to
1429 // one of the internal compiler literals: Int/UInt/Long/ULong Literals.
1431 public Constant
WidenToCompilerConstant ()
1433 Type t
= TypeManager
.EnumToUnderlying (Child
.Type
);
1434 object v
= ((Constant
) Child
).GetValue ();;
1436 if (t
== TypeManager
.int32_type
)
1437 return new IntConstant ((int) v
);
1438 if (t
== TypeManager
.uint32_type
)
1439 return new UIntConstant ((uint) v
);
1440 if (t
== TypeManager
.int64_type
)
1441 return new LongConstant ((long) v
);
1442 if (t
== TypeManager
.uint64_type
)
1443 return new ULongConstant ((ulong) v
);
1444 if (t
== TypeManager
.short_type
)
1445 return new ShortConstant ((short) v
);
1446 if (t
== TypeManager
.ushort_type
)
1447 return new UShortConstant ((ushort) v
);
1448 if (t
== TypeManager
.byte_type
)
1449 return new ByteConstant ((byte) v
);
1450 if (t
== TypeManager
.sbyte_type
)
1451 return new SByteConstant ((sbyte) v
);
1453 throw new Exception ("Invalid enumeration underlying type: " + t
);
1457 // Extracts the value in the enumeration on its native representation
1459 public object GetPlainValue ()
1461 Type t
= TypeManager
.EnumToUnderlying (Child
.Type
);
1462 object v
= ((Constant
) Child
).GetValue ();;
1464 if (t
== TypeManager
.int32_type
)
1466 if (t
== TypeManager
.uint32_type
)
1468 if (t
== TypeManager
.int64_type
)
1470 if (t
== TypeManager
.uint64_type
)
1472 if (t
== TypeManager
.short_type
)
1474 if (t
== TypeManager
.ushort_type
)
1476 if (t
== TypeManager
.byte_type
)
1478 if (t
== TypeManager
.sbyte_type
)
1484 public override string AsString ()
1486 return Child
.AsString ();
1489 public override DoubleConstant
ConvertToDouble ()
1491 return Child
.ConvertToDouble ();
1494 public override FloatConstant
ConvertToFloat ()
1496 return Child
.ConvertToFloat ();
1499 public override ULongConstant
ConvertToULong ()
1501 return Child
.ConvertToULong ();
1504 public override LongConstant
ConvertToLong ()
1506 return Child
.ConvertToLong ();
1509 public override UIntConstant
ConvertToUInt ()
1511 return Child
.ConvertToUInt ();
1514 public override IntConstant
ConvertToInt ()
1516 return Child
.ConvertToInt ();
1519 public override bool IsZeroInteger
{
1520 get { return Child.IsZeroInteger; }
1525 /// This kind of cast is used to encapsulate Value Types in objects.
1527 /// The effect of it is to box the value type emitted by the previous
1530 public class BoxedCast
: EmptyCast
{
1532 public BoxedCast (Expression expr
)
1533 : base (expr
, TypeManager
.object_type
)
1537 public BoxedCast (Expression expr
, Type target_type
)
1538 : base (expr
, target_type
)
1542 public override Expression
DoResolve (EmitContext ec
)
1544 // This should never be invoked, we are born in fully
1545 // initialized state.
1550 public override void Emit (EmitContext ec
)
1554 ec
.ig
.Emit (OpCodes
.Box
, child
.Type
);
1558 public class UnboxCast
: EmptyCast
{
1559 public UnboxCast (Expression expr
, Type return_type
)
1560 : base (expr
, return_type
)
1564 public override Expression
DoResolve (EmitContext ec
)
1566 // This should never be invoked, we are born in fully
1567 // initialized state.
1572 public override void Emit (EmitContext ec
)
1575 ILGenerator ig
= ec
.ig
;
1578 ig
.Emit (OpCodes
.Unbox
, t
);
1580 LoadFromPtr (ig
, t
);
1585 /// This is used to perform explicit numeric conversions.
1587 /// Explicit numeric conversions might trigger exceptions in a checked
1588 /// context, so they should generate the conv.ovf opcodes instead of
1591 public class ConvCast
: EmptyCast
{
1592 public enum Mode
: byte {
1593 I1_U1
, I1_U2
, I1_U4
, I1_U8
, I1_CH
,
1595 I2_I1
, I2_U1
, I2_U2
, I2_U4
, I2_U8
, I2_CH
,
1596 U2_I1
, U2_U1
, U2_I2
, U2_CH
,
1597 I4_I1
, I4_U1
, I4_I2
, I4_U2
, I4_U4
, I4_U8
, I4_CH
,
1598 U4_I1
, U4_U1
, U4_I2
, U4_U2
, U4_I4
, U4_CH
,
1599 I8_I1
, I8_U1
, I8_I2
, I8_U2
, I8_I4
, I8_U4
, I8_U8
, I8_CH
,
1600 U8_I1
, U8_U1
, U8_I2
, U8_U2
, U8_I4
, U8_U4
, U8_I8
, U8_CH
,
1601 CH_I1
, CH_U1
, CH_I2
,
1602 R4_I1
, R4_U1
, R4_I2
, R4_U2
, R4_I4
, R4_U4
, R4_I8
, R4_U8
, R4_CH
,
1603 R8_I1
, R8_U1
, R8_I2
, R8_U2
, R8_I4
, R8_U4
, R8_I8
, R8_U8
, R8_CH
, R8_R4
1609 public ConvCast (EmitContext ec
, Expression child
, Type return_type
, Mode m
)
1610 : base (child
, return_type
)
1612 checked_state
= ec
.CheckState
;
1616 public override Expression
DoResolve (EmitContext ec
)
1618 // This should never be invoked, we are born in fully
1619 // initialized state.
1624 public override string ToString ()
1626 return String
.Format ("ConvCast ({0}, {1})", mode
, child
);
1629 public override void Emit (EmitContext ec
)
1631 ILGenerator ig
= ec
.ig
;
1637 case Mode
.I1_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1638 case Mode
.I1_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1639 case Mode
.I1_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1640 case Mode
.I1_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1641 case Mode
.I1_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1643 case Mode
.U1_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1644 case Mode
.U1_CH
: /* nothing */ break;
1646 case Mode
.I2_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1647 case Mode
.I2_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1648 case Mode
.I2_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1649 case Mode
.I2_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1650 case Mode
.I2_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1651 case Mode
.I2_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1653 case Mode
.U2_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1654 case Mode
.U2_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1655 case Mode
.U2_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1656 case Mode
.U2_CH
: /* nothing */ break;
1658 case Mode
.I4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1659 case Mode
.I4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1660 case Mode
.I4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1661 case Mode
.I4_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1662 case Mode
.I4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1663 case Mode
.I4_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1664 case Mode
.I4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1666 case Mode
.U4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1667 case Mode
.U4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1668 case Mode
.U4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1669 case Mode
.U4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1670 case Mode
.U4_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4_Un
); break;
1671 case Mode
.U4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1673 case Mode
.I8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1674 case Mode
.I8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1675 case Mode
.I8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1676 case Mode
.I8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1677 case Mode
.I8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1678 case Mode
.I8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1679 case Mode
.I8_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1680 case Mode
.I8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1682 case Mode
.U8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1683 case Mode
.U8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1684 case Mode
.U8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1685 case Mode
.U8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1686 case Mode
.U8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4_Un
); break;
1687 case Mode
.U8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4_Un
); break;
1688 case Mode
.U8_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8_Un
); break;
1689 case Mode
.U8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1691 case Mode
.CH_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1692 case Mode
.CH_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1693 case Mode
.CH_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1695 case Mode
.R4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1696 case Mode
.R4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1697 case Mode
.R4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1698 case Mode
.R4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1699 case Mode
.R4_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1700 case Mode
.R4_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1701 case Mode
.R4_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8
); break;
1702 case Mode
.R4_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1703 case Mode
.R4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1705 case Mode
.R8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1706 case Mode
.R8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1707 case Mode
.R8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1708 case Mode
.R8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1709 case Mode
.R8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1710 case Mode
.R8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1711 case Mode
.R8_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8
); break;
1712 case Mode
.R8_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1713 case Mode
.R8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1714 case Mode
.R8_R4
: ig
.Emit (OpCodes
.Conv_R4
); break;
1718 case Mode
.I1_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1719 case Mode
.I1_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1720 case Mode
.I1_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1721 case Mode
.I1_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1722 case Mode
.I1_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1724 case Mode
.U1_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1725 case Mode
.U1_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1727 case Mode
.I2_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1728 case Mode
.I2_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1729 case Mode
.I2_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1730 case Mode
.I2_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1731 case Mode
.I2_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1732 case Mode
.I2_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1734 case Mode
.U2_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1735 case Mode
.U2_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1736 case Mode
.U2_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1737 case Mode
.U2_CH
: /* nothing */ break;
1739 case Mode
.I4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1740 case Mode
.I4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1741 case Mode
.I4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1742 case Mode
.I4_U4
: /* nothing */ break;
1743 case Mode
.I4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1744 case Mode
.I4_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1745 case Mode
.I4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1747 case Mode
.U4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1748 case Mode
.U4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1749 case Mode
.U4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1750 case Mode
.U4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1751 case Mode
.U4_I4
: /* nothing */ break;
1752 case Mode
.U4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1754 case Mode
.I8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1755 case Mode
.I8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1756 case Mode
.I8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1757 case Mode
.I8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1758 case Mode
.I8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
1759 case Mode
.I8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1760 case Mode
.I8_U8
: /* nothing */ break;
1761 case Mode
.I8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1763 case Mode
.U8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1764 case Mode
.U8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1765 case Mode
.U8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1766 case Mode
.U8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1767 case Mode
.U8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
1768 case Mode
.U8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1769 case Mode
.U8_I8
: /* nothing */ break;
1770 case Mode
.U8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1772 case Mode
.CH_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1773 case Mode
.CH_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1774 case Mode
.CH_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1776 case Mode
.R4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1777 case Mode
.R4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1778 case Mode
.R4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1779 case Mode
.R4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1780 case Mode
.R4_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
1781 case Mode
.R4_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1782 case Mode
.R4_I8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1783 case Mode
.R4_U8
: ig
.Emit (OpCodes
.Conv_U8
); break;
1784 case Mode
.R4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1786 case Mode
.R8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1787 case Mode
.R8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1788 case Mode
.R8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1789 case Mode
.R8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1790 case Mode
.R8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
1791 case Mode
.R8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1792 case Mode
.R8_I8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1793 case Mode
.R8_U8
: ig
.Emit (OpCodes
.Conv_U8
); break;
1794 case Mode
.R8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1795 case Mode
.R8_R4
: ig
.Emit (OpCodes
.Conv_R4
); break;
1801 public class OpcodeCast
: EmptyCast
{
1805 public OpcodeCast (Expression child
, Type return_type
, OpCode op
)
1806 : base (child
, return_type
)
1810 second_valid
= false;
1813 public OpcodeCast (Expression child
, Type return_type
, OpCode op
, OpCode op2
)
1814 : base (child
, return_type
)
1819 second_valid
= true;
1822 public override Expression
DoResolve (EmitContext ec
)
1824 // This should never be invoked, we are born in fully
1825 // initialized state.
1830 public override void Emit (EmitContext ec
)
1841 /// This kind of cast is used to encapsulate a child and cast it
1842 /// to the class requested
1844 public class ClassCast
: EmptyCast
{
1845 public ClassCast (Expression child
, Type return_type
)
1846 : base (child
, return_type
)
1851 public override Expression
DoResolve (EmitContext ec
)
1853 // This should never be invoked, we are born in fully
1854 // initialized state.
1859 public override void Emit (EmitContext ec
)
1863 ec
.ig
.Emit (OpCodes
.Castclass
, type
);
1869 /// SimpleName expressions are initially formed of a single
1870 /// word and it only happens at the beginning of the expression.
1874 /// The expression will try to be bound to a Field, a Method
1875 /// group or a Property. If those fail we pass the name to our
1876 /// caller and the SimpleName is compounded to perform a type
1877 /// lookup. The idea behind this process is that we want to avoid
1878 /// creating a namespace map from the assemblies, as that requires
1879 /// the GetExportedTypes function to be called and a hashtable to
1880 /// be constructed which reduces startup time. If later we find
1881 /// that this is slower, we should create a `NamespaceExpr' expression
1882 /// that fully participates in the resolution process.
1884 /// For example `System.Console.WriteLine' is decomposed into
1885 /// MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine")
1887 /// The first SimpleName wont produce a match on its own, so it will
1889 /// MemberAccess (SimpleName ("System.Console"), "WriteLine").
1891 /// System.Console will produce a TypeExpr match.
1893 /// The downside of this is that we might be hitting `LookupType' too many
1894 /// times with this scheme.
1896 public class SimpleName
: Expression
{
1900 // If true, then we are a simple name, not composed with a ".
1904 public SimpleName (string a
, string b
, Location l
)
1906 Name
= String
.Concat (a
, ".", b
);
1911 public SimpleName (string name
, Location l
)
1918 public static void Error_ObjectRefRequired (EmitContext ec
, Location l
, string name
)
1920 if (ec
.IsFieldInitializer
)
1923 "A field initializer cannot reference the non-static field, " +
1924 "method or property `"+name
+"'");
1928 "An object reference is required " +
1929 "for the non-static field `"+name
+"'");
1933 // Checks whether we are trying to access an instance
1934 // property, method or field from a static body.
1936 Expression
MemberStaticCheck (EmitContext ec
, Expression e
)
1938 if (e
is IMemberExpr
){
1939 IMemberExpr member
= (IMemberExpr
) e
;
1941 if (!member
.IsStatic
){
1942 Error_ObjectRefRequired (ec
, loc
, Name
);
1950 public override Expression
DoResolve (EmitContext ec
)
1952 return SimpleNameResolve (ec
, null, false);
1955 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
1957 return SimpleNameResolve (ec
, right_side
, false);
1961 public Expression
DoResolveAllowStatic (EmitContext ec
)
1963 return SimpleNameResolve (ec
, null, true);
1966 public override Expression
ResolveAsTypeStep (EmitContext ec
)
1968 DeclSpace ds
= ec
.DeclSpace
;
1969 NamespaceEntry ns
= ds
.NamespaceEntry
;
1974 // Since we are cheating: we only do the Alias lookup for
1975 // namespaces if the name does not include any dots in it
1977 if (ns
!= null && is_base
)
1978 alias_value
= ns
.LookupAlias (Name
);
1982 if (ec
.ResolvingTypeTree
){
1983 int errors
= Report
.Errors
;
1984 Type dt
= ds
.FindType (loc
, Name
);
1986 if (Report
.Errors
!= errors
)
1990 return new TypeExpression (dt
, loc
);
1992 if (alias_value
!= null){
1993 if ((t
= RootContext
.LookupType (ds
, alias_value
, true, loc
)) != null)
1994 return new TypeExpression (t
, loc
);
1999 // First, the using aliases
2001 if (alias_value
!= null){
2002 if ((t
= RootContext
.LookupType (ds
, alias_value
, true, loc
)) != null)
2003 return new TypeExpression (t
, loc
);
2005 // we have alias value, but it isn't Type, so try if it's namespace
2006 return new SimpleName (alias_value
, loc
);
2010 // Stage 2: Lookup up if we are an alias to a type
2014 if ((t
= RootContext
.LookupType (ds
, Name
, true, loc
)) != null)
2015 return new TypeExpression (t
, loc
);
2017 // No match, maybe our parent can compose us
2018 // into something meaningful.
2023 /// 7.5.2: Simple Names.
2025 /// Local Variables and Parameters are handled at
2026 /// parse time, so they never occur as SimpleNames.
2028 /// The `allow_static' flag is used by MemberAccess only
2029 /// and it is used to inform us that it is ok for us to
2030 /// avoid the static check, because MemberAccess might end
2031 /// up resolving the Name as a Type name and the access as
2032 /// a static type access.
2034 /// ie: Type Type; .... { Type.GetType (""); }
2036 /// Type is both an instance variable and a Type; Type.GetType
2037 /// is the static method not an instance method of type.
2039 Expression
SimpleNameResolve (EmitContext ec
, Expression right_side
, bool allow_static
)
2041 Expression e
= null;
2044 // Stage 1: Performed by the parser (binding to locals or parameters).
2046 Block current_block
= ec
.CurrentBlock
;
2047 if (current_block
!= null){
2048 LocalInfo vi
= current_block
.GetLocalInfo (Name
);
2052 var = new LocalVariableReference (ec
.CurrentBlock
, Name
, loc
);
2054 if (right_side
!= null)
2055 return var.ResolveLValue (ec
, right_side
);
2057 return var.Resolve (ec
);
2061 Parameter par
= null;
2062 Parameters pars
= current_block
.Parameters
;
2064 par
= pars
.GetParameterByName (Name
, out idx
);
2067 ParameterReference param
;
2069 param
= new ParameterReference (pars
, current_block
, idx
, Name
, loc
);
2071 if (right_side
!= null)
2072 return param
.ResolveLValue (ec
, right_side
);
2074 return param
.Resolve (ec
);
2079 // Stage 2: Lookup members
2082 DeclSpace lookup_ds
= ec
.DeclSpace
;
2084 if (lookup_ds
.TypeBuilder
== null)
2087 e
= MemberLookup (ec
, lookup_ds
.TypeBuilder
, Name
, loc
);
2091 lookup_ds
=lookup_ds
.Parent
;
2092 } while (lookup_ds
!= null);
2094 if (e
== null && ec
.ContainerType
!= null)
2095 e
= MemberLookup (ec
, ec
.ContainerType
, Name
, loc
);
2099 // Since we are cheating (is_base is our hint
2100 // that we are the beginning of the name): we
2101 // only do the Alias lookup for namespaces if
2102 // the name does not include any dots in it
2104 NamespaceEntry ns
= ec
.DeclSpace
.NamespaceEntry
;
2105 if (is_base
&& ns
!= null){
2106 string alias_value
= ns
.LookupAlias (Name
);
2107 if (alias_value
!= null){
2111 if ((t
= TypeManager
.LookupType (Name
)) != null)
2112 return new TypeExpression (t
, loc
);
2114 // No match, maybe our parent can compose us
2115 // into something meaningful.
2120 return ResolveAsTypeStep (ec
);
2126 if (e
is IMemberExpr
) {
2127 e
= MemberAccess
.ResolveMemberAccess (ec
, e
, null, loc
, this);
2131 IMemberExpr me
= e
as IMemberExpr
;
2135 // This fails if ResolveMemberAccess() was unable to decide whether
2136 // it's a field or a type of the same name.
2137 if (!me
.IsStatic
&& (me
.InstanceExpression
== null))
2141 TypeManager
.IsNestedChildOf (me
.InstanceExpression
.Type
, me
.DeclaringType
) &&
2142 !me
.InstanceExpression
.Type
.IsSubclassOf (me
.DeclaringType
)) {
2143 Error (38, "Cannot access nonstatic member `" + me
.Name
+ "' of " +
2144 "outer type `" + me
.DeclaringType
+ "' via nested type `" +
2145 me
.InstanceExpression
.Type
+ "'");
2149 if (right_side
!= null)
2150 e
= e
.DoResolveLValue (ec
, right_side
);
2152 e
= e
.DoResolve (ec
);
2157 if (ec
.IsStatic
|| ec
.IsFieldInitializer
){
2161 return MemberStaticCheck (ec
, e
);
2166 public override void Emit (EmitContext ec
)
2169 // If this is ever reached, then we failed to
2170 // find the name as a namespace
2173 Error (103, "The name `" + Name
+
2174 "' does not exist in the class `" +
2175 ec
.DeclSpace
.Name
+ "'");
2178 public override string ToString ()
2185 /// Fully resolved expression that evaluates to a type
2187 public abstract class TypeExpr
: Expression
{
2188 override public Expression
ResolveAsTypeStep (EmitContext ec
)
2190 TypeExpr t
= DoResolveAsTypeStep (ec
);
2194 eclass
= ExprClass
.Type
;
2198 override public Expression
DoResolve (EmitContext ec
)
2200 return ResolveAsTypeTerminal (ec
);
2203 override public void Emit (EmitContext ec
)
2205 throw new Exception ("Should never be called");
2208 public virtual bool CheckAccessLevel (DeclSpace ds
)
2210 return ds
.CheckAccessLevel (Type
);
2213 public virtual bool AsAccessible (DeclSpace ds
, int flags
)
2215 return ds
.AsAccessible (Type
, flags
);
2218 public virtual bool IsClass
{
2219 get { return Type.IsClass; }
2222 public virtual bool IsValueType
{
2223 get { return Type.IsValueType; }
2226 public virtual bool IsInterface
{
2227 get { return Type.IsInterface; }
2230 public virtual bool IsSealed
{
2231 get { return Type.IsSealed; }
2234 public virtual bool CanInheritFrom ()
2236 if (Type
== TypeManager
.enum_type
||
2237 (Type
== TypeManager
.value_type
&& RootContext
.StdLib
) ||
2238 Type
== TypeManager
.delegate_type
||
2239 Type
== TypeManager
.array_type
)
2245 public virtual bool IsAttribute
{
2247 return Type
== TypeManager
.attribute_type
||
2248 Type
.IsSubclassOf (TypeManager
.attribute_type
);
2252 public virtual TypeExpr
[] GetInterfaces ()
2254 return TypeManager
.GetInterfaces (Type
);
2257 public abstract TypeExpr
DoResolveAsTypeStep (EmitContext ec
);
2259 public virtual Type
ResolveType (EmitContext ec
)
2261 TypeExpr t
= ResolveAsTypeTerminal (ec
);
2268 public abstract string Name
{
2272 public override bool Equals (object obj
)
2274 TypeExpr tobj
= obj
as TypeExpr
;
2278 return Type
== tobj
.Type
;
2281 public override int GetHashCode ()
2283 return Type
.GetHashCode ();
2286 public override string ToString ()
2292 public class TypeExpression
: TypeExpr
{
2293 public TypeExpression (Type t
, Location l
)
2296 eclass
= ExprClass
.Type
;
2300 public override TypeExpr
DoResolveAsTypeStep (EmitContext ec
)
2305 public override string Name
{
2307 return Type
.ToString ();
2313 /// Used to create types from a fully qualified name. These are just used
2314 /// by the parser to setup the core types. A TypeLookupExpression is always
2315 /// classified as a type.
2317 public class TypeLookupExpression
: TypeExpr
{
2320 public TypeLookupExpression (string name
)
2325 public override TypeExpr
DoResolveAsTypeStep (EmitContext ec
)
2328 type
= RootContext
.LookupType (ec
.DeclSpace
, name
, false, Location
.Null
);
2332 public override string Name
{
2340 /// MethodGroup Expression.
2342 /// This is a fully resolved expression that evaluates to a type
2344 public class MethodGroupExpr
: Expression
, IMemberExpr
{
2345 public MethodBase
[] Methods
;
2346 Expression instance_expression
= null;
2347 bool is_explicit_impl
= false;
2349 public MethodGroupExpr (MemberInfo
[] mi
, Location l
)
2351 Methods
= new MethodBase
[mi
.Length
];
2352 mi
.CopyTo (Methods
, 0);
2353 eclass
= ExprClass
.MethodGroup
;
2354 type
= TypeManager
.object_type
;
2358 public MethodGroupExpr (ArrayList list
, Location l
)
2360 Methods
= new MethodBase
[list
.Count
];
2363 list
.CopyTo (Methods
, 0);
2365 foreach (MemberInfo m
in list
){
2366 if (!(m
is MethodBase
)){
2367 Console
.WriteLine ("Name " + m
.Name
);
2368 Console
.WriteLine ("Found a: " + m
.GetType ().FullName
);
2375 eclass
= ExprClass
.MethodGroup
;
2376 type
= TypeManager
.object_type
;
2379 public Type DeclaringType
{
2382 // The methods are arranged in this order:
2383 // derived type -> base type
2385 return Methods
[0].DeclaringType
;
2390 // `A method group may have associated an instance expression'
2392 public Expression InstanceExpression
{
2394 return instance_expression
;
2398 instance_expression
= value;
2402 public bool IsExplicitImpl
{
2404 return is_explicit_impl
;
2408 is_explicit_impl
= value;
2412 public string Name
{
2414 return Methods
[0].Name
;
2418 public bool IsInstance
{
2420 foreach (MethodBase mb
in Methods
)
2428 public bool IsStatic
{
2430 foreach (MethodBase mb
in Methods
)
2438 override public Expression
DoResolve (EmitContext ec
)
2441 instance_expression
= null;
2443 if (instance_expression
!= null) {
2444 instance_expression
= instance_expression
.DoResolve (ec
);
2445 if (instance_expression
== null)
2452 public void ReportUsageError ()
2454 Report
.Error (654, loc
, "Method `" + DeclaringType
+ "." +
2455 Name
+ "()' is referenced without parentheses");
2458 override public void Emit (EmitContext ec
)
2460 ReportUsageError ();
2463 bool RemoveMethods (bool keep_static
)
2465 ArrayList smethods
= new ArrayList ();
2467 foreach (MethodBase mb
in Methods
){
2468 if (mb
.IsStatic
== keep_static
)
2472 if (smethods
.Count
== 0)
2475 Methods
= new MethodBase
[smethods
.Count
];
2476 smethods
.CopyTo (Methods
, 0);
2482 /// Removes any instance methods from the MethodGroup, returns
2483 /// false if the resulting set is empty.
2485 public bool RemoveInstanceMethods ()
2487 return RemoveMethods (true);
2491 /// Removes any static methods from the MethodGroup, returns
2492 /// false if the resulting set is empty.
2494 public bool RemoveStaticMethods ()
2496 return RemoveMethods (false);
2501 /// Fully resolved expression that evaluates to a Field
2503 public class FieldExpr
: Expression
, IAssignMethod
, IMemoryLocation
, IMemberExpr
, IVariable
{
2504 public readonly FieldInfo FieldInfo
;
2505 Expression instance_expr
;
2506 VariableInfo variable_info
;
2508 public FieldExpr (FieldInfo fi
, Location l
)
2511 eclass
= ExprClass
.Variable
;
2512 type
= fi
.FieldType
;
2516 public string Name
{
2518 return FieldInfo
.Name
;
2522 public bool IsInstance
{
2524 return !FieldInfo
.IsStatic
;
2528 public bool IsStatic
{
2530 return FieldInfo
.IsStatic
;
2534 public Type DeclaringType
{
2536 return FieldInfo
.DeclaringType
;
2540 public Expression InstanceExpression
{
2542 return instance_expr
;
2546 instance_expr
= value;
2550 public VariableInfo VariableInfo
{
2552 return variable_info
;
2556 override public Expression
DoResolve (EmitContext ec
)
2558 if (!FieldInfo
.IsStatic
){
2559 if (instance_expr
== null){
2561 // This can happen when referencing an instance field using
2562 // a fully qualified type expression: TypeName.InstanceField = xxx
2564 SimpleName
.Error_ObjectRefRequired (ec
, loc
, FieldInfo
.Name
);
2568 // Resolve the field's instance expression while flow analysis is turned
2569 // off: when accessing a field "a.b", we must check whether the field
2570 // "a.b" is initialized, not whether the whole struct "a" is initialized.
2571 instance_expr
= instance_expr
.Resolve (ec
, ResolveFlags
.VariableOrValue
|
2572 ResolveFlags
.DisableFlowAnalysis
);
2573 if (instance_expr
== null)
2577 // If the instance expression is a local variable or parameter.
2578 IVariable
var = instance_expr
as IVariable
;
2579 if ((var == null) || (var.VariableInfo
== null))
2582 VariableInfo vi
= var.VariableInfo
;
2583 if (!vi
.IsFieldAssigned (ec
, FieldInfo
.Name
, loc
))
2586 variable_info
= vi
.GetSubStruct (FieldInfo
.Name
);
2590 void Report_AssignToReadonly (bool is_instance
)
2595 msg
= "Readonly field can not be assigned outside " +
2596 "of constructor or variable initializer";
2598 msg
= "A static readonly field can only be assigned in " +
2599 "a static constructor";
2601 Report
.Error (is_instance
? 191 : 198, loc
, msg
);
2604 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
2606 IVariable
var = instance_expr
as IVariable
;
2607 if ((var != null) && (var.VariableInfo
!= null))
2608 var.VariableInfo
.SetFieldAssigned (ec
, FieldInfo
.Name
);
2610 Expression e
= DoResolve (ec
);
2615 if (!FieldInfo
.IsStatic
&& (instance_expr
.Type
.IsValueType
&& !(instance_expr
is IMemoryLocation
))) {
2616 // FIXME: Provide better error reporting.
2617 Error (1612, "Cannot modify expression because it is not a variable.");
2621 if (!FieldInfo
.IsInitOnly
)
2624 FieldBase fb
= TypeManager
.GetField (FieldInfo
);
2629 // InitOnly fields can only be assigned in constructors
2632 if (ec
.IsConstructor
){
2633 if (IsStatic
&& !ec
.IsStatic
)
2634 Report_AssignToReadonly (false);
2636 if (ec
.ContainerType
== FieldInfo
.DeclaringType
)
2640 Report_AssignToReadonly (true);
2645 public bool VerifyFixed (bool is_expression
)
2647 IVariable variable
= instance_expr
as IVariable
;
2648 if ((variable
== null) || !variable
.VerifyFixed (true))
2654 override public void Emit (EmitContext ec
)
2656 ILGenerator ig
= ec
.ig
;
2657 bool is_volatile
= false;
2659 if (FieldInfo
is FieldBuilder
){
2660 FieldBase f
= TypeManager
.GetField (FieldInfo
);
2662 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0)
2665 f
.status
|= Field
.Status
.USED
;
2669 if (FieldInfo
.IsStatic
){
2671 ig
.Emit (OpCodes
.Volatile
);
2673 ig
.Emit (OpCodes
.Ldsfld
, FieldInfo
);
2677 if (instance_expr
.Type
.IsValueType
){
2679 LocalTemporary tempo
= null;
2681 if (!(instance_expr
is IMemoryLocation
)){
2682 tempo
= new LocalTemporary (ec
, instance_expr
.Type
);
2684 if (ec
.RemapToProxy
)
2687 InstanceExpression
.Emit (ec
);
2691 ml
= (IMemoryLocation
) instance_expr
;
2693 ml
.AddressOf (ec
, AddressOp
.Load
);
2695 if (ec
.RemapToProxy
)
2698 instance_expr
.Emit (ec
);
2701 ig
.Emit (OpCodes
.Volatile
);
2703 ig
.Emit (OpCodes
.Ldfld
, FieldInfo
);
2706 public void EmitAssign (EmitContext ec
, Expression source
)
2708 FieldAttributes fa
= FieldInfo
.Attributes
;
2709 bool is_static
= (fa
& FieldAttributes
.Static
) != 0;
2710 bool is_readonly
= (fa
& FieldAttributes
.InitOnly
) != 0;
2711 ILGenerator ig
= ec
.ig
;
2713 if (is_readonly
&& !ec
.IsConstructor
){
2714 Report_AssignToReadonly (!is_static
);
2719 Expression instance
= instance_expr
;
2721 if (instance
.Type
.IsValueType
){
2722 IMemoryLocation ml
= (IMemoryLocation
) instance
;
2724 ml
.AddressOf (ec
, AddressOp
.Store
);
2726 if (ec
.RemapToProxy
)
2735 if (FieldInfo
is FieldBuilder
){
2736 FieldBase f
= TypeManager
.GetField (FieldInfo
);
2738 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0)
2739 ig
.Emit (OpCodes
.Volatile
);
2741 f
.status
|= Field
.Status
.ASSIGNED
;
2746 ig
.Emit (OpCodes
.Stsfld
, FieldInfo
);
2748 ig
.Emit (OpCodes
.Stfld
, FieldInfo
);
2751 public void AddressOf (EmitContext ec
, AddressOp mode
)
2753 ILGenerator ig
= ec
.ig
;
2755 if (FieldInfo
is FieldBuilder
){
2756 FieldBase f
= TypeManager
.GetField (FieldInfo
);
2758 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0){
2759 Error (676, "volatile variable: can not take its address, or pass as ref/out parameter");
2763 if ((mode
& AddressOp
.Store
) != 0)
2764 f
.status
|= Field
.Status
.ASSIGNED
;
2765 if ((mode
& AddressOp
.Load
) != 0)
2766 f
.status
|= Field
.Status
.USED
;
2771 // Handle initonly fields specially: make a copy and then
2772 // get the address of the copy.
2775 if (FieldInfo
.IsInitOnly
){
2777 if (ec
.IsConstructor
){
2778 if (FieldInfo
.IsStatic
){
2790 local
= ig
.DeclareLocal (type
);
2791 ig
.Emit (OpCodes
.Stloc
, local
);
2792 ig
.Emit (OpCodes
.Ldloca
, local
);
2797 if (FieldInfo
.IsStatic
){
2798 ig
.Emit (OpCodes
.Ldsflda
, FieldInfo
);
2801 // In the case of `This', we call the AddressOf method, which will
2802 // only load the pointer, and not perform an Ldobj immediately after
2803 // the value has been loaded into the stack.
2805 if (instance_expr
is This
)
2806 ((This
)instance_expr
).AddressOf (ec
, AddressOp
.LoadStore
);
2807 else if (instance_expr
.Type
.IsValueType
&& instance_expr
is IMemoryLocation
){
2808 IMemoryLocation ml
= (IMemoryLocation
) instance_expr
;
2810 ml
.AddressOf (ec
, AddressOp
.LoadStore
);
2812 instance_expr
.Emit (ec
);
2813 ig
.Emit (OpCodes
.Ldflda
, FieldInfo
);
2819 // A FieldExpr whose address can not be taken
2821 public class FieldExprNoAddress
: FieldExpr
, IMemoryLocation
{
2822 public FieldExprNoAddress (FieldInfo fi
, Location loc
) : base (fi
, loc
)
2826 public new void AddressOf (EmitContext ec
, AddressOp mode
)
2828 Report
.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
2833 /// Expression that evaluates to a Property. The Assign class
2834 /// might set the `Value' expression if we are in an assignment.
2836 /// This is not an LValue because we need to re-write the expression, we
2837 /// can not take data from the stack and store it.
2839 public class PropertyExpr
: ExpressionStatement
, IAssignMethod
, IMemberExpr
{
2840 public readonly PropertyInfo PropertyInfo
;
2843 // This is set externally by the `BaseAccess' class
2846 MethodInfo getter
, setter
;
2848 bool must_do_cs1540_check
;
2850 Expression instance_expr
;
2852 public PropertyExpr (EmitContext ec
, PropertyInfo pi
, Location l
)
2855 eclass
= ExprClass
.PropertyAccess
;
2859 type
= TypeManager
.TypeToCoreType (pi
.PropertyType
);
2861 ResolveAccessors (ec
);
2864 public string Name
{
2866 return PropertyInfo
.Name
;
2870 public bool IsInstance
{
2876 public bool IsStatic
{
2882 public Type DeclaringType
{
2884 return PropertyInfo
.DeclaringType
;
2889 // The instance expression associated with this expression
2891 public Expression InstanceExpression
{
2893 instance_expr
= value;
2897 return instance_expr
;
2901 public bool VerifyAssignable ()
2903 if (setter
== null) {
2904 Report
.Error (200, loc
,
2905 "The property `" + PropertyInfo
.Name
+
2906 "' can not be assigned to, as it has not set accessor");
2913 MethodInfo
GetAccessor (Type invocation_type
, string accessor_name
)
2915 BindingFlags flags
= BindingFlags
.Public
| BindingFlags
.NonPublic
|
2916 BindingFlags
.Static
| BindingFlags
.Instance
;
2919 group = TypeManager
.MemberLookup (
2920 invocation_type
, invocation_type
, PropertyInfo
.DeclaringType
,
2921 MemberTypes
.Method
, flags
, accessor_name
+ "_" + PropertyInfo
.Name
);
2924 // The first method is the closest to us
2929 foreach (MethodInfo mi
in group) {
2930 MethodAttributes ma
= mi
.Attributes
& MethodAttributes
.MemberAccessMask
;
2933 // If only accessible to the current class or children
2935 if (ma
== MethodAttributes
.Private
) {
2936 Type declaring_type
= mi
.DeclaringType
;
2938 if (invocation_type
!= declaring_type
){
2939 if (TypeManager
.IsSubclassOrNestedChildOf (invocation_type
, mi
.DeclaringType
))
2947 // FamAndAssem requires that we not only derivate, but we are on the
2950 if (ma
== MethodAttributes
.FamANDAssem
){
2951 if (mi
.DeclaringType
.Assembly
!= invocation_type
.Assembly
)
2957 // Assembly and FamORAssem succeed if we're in the same assembly.
2958 if ((ma
== MethodAttributes
.Assembly
) || (ma
== MethodAttributes
.FamORAssem
)){
2959 if (mi
.DeclaringType
.Assembly
== invocation_type
.Assembly
)
2963 // We already know that we aren't in the same assembly.
2964 if (ma
== MethodAttributes
.Assembly
)
2967 // Family and FamANDAssem require that we derive.
2968 if ((ma
== MethodAttributes
.Family
) || (ma
== MethodAttributes
.FamANDAssem
) || (ma
== MethodAttributes
.FamORAssem
)){
2969 if (!TypeManager
.IsSubclassOrNestedChildOf (invocation_type
, mi
.DeclaringType
))
2972 must_do_cs1540_check
= true;
2985 // We also perform the permission checking here, as the PropertyInfo does not
2986 // hold the information for the accessibility of its setter/getter
2988 void ResolveAccessors (EmitContext ec
)
2990 getter
= GetAccessor (ec
.ContainerType
, "get");
2991 if ((getter
!= null) && getter
.IsStatic
)
2994 setter
= GetAccessor (ec
.ContainerType
, "set");
2995 if ((setter
!= null) && setter
.IsStatic
)
2998 if (setter
== null && getter
== null){
2999 Error (122, "`" + PropertyInfo
.Name
+ "' " +
3000 "is inaccessible because of its protection level");
3005 bool InstanceResolve (EmitContext ec
)
3007 if ((instance_expr
== null) && ec
.IsStatic
&& !is_static
) {
3008 SimpleName
.Error_ObjectRefRequired (ec
, loc
, PropertyInfo
.Name
);
3012 if (instance_expr
!= null) {
3013 instance_expr
= instance_expr
.DoResolve (ec
);
3014 if (instance_expr
== null)
3018 if (must_do_cs1540_check
&& (instance_expr
!= null)) {
3019 if ((instance_expr
.Type
!= ec
.ContainerType
) &&
3020 ec
.ContainerType
.IsSubclassOf (instance_expr
.Type
)) {
3021 Report
.Error (1540, loc
, "Cannot access protected member `" +
3022 PropertyInfo
.DeclaringType
+ "." + PropertyInfo
.Name
+
3023 "' via a qualifier of type `" +
3024 TypeManager
.CSharpName (instance_expr
.Type
) +
3025 "'; the qualifier must be of type `" +
3026 TypeManager
.CSharpName (ec
.ContainerType
) +
3027 "' (or derived from it)");
3035 override public Expression
DoResolve (EmitContext ec
)
3037 if (getter
== null){
3039 // The following condition happens if the PropertyExpr was
3040 // created, but is invalid (ie, the property is inaccessible),
3041 // and we did not want to embed the knowledge about this in
3042 // the caller routine. This only avoids double error reporting.
3047 Report
.Error (154, loc
,
3048 "The property `" + PropertyInfo
.Name
+
3049 "' can not be used in " +
3050 "this context because it lacks a get accessor");
3054 if (!InstanceResolve (ec
))
3058 // Only base will allow this invocation to happen.
3060 if (IsBase
&& getter
.IsAbstract
){
3061 Report
.Error (205, loc
, "Cannot call an abstract base property: " +
3062 PropertyInfo
.DeclaringType
+ "." +PropertyInfo
.Name
);
3069 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
3071 if (setter
== null){
3073 // The following condition happens if the PropertyExpr was
3074 // created, but is invalid (ie, the property is inaccessible),
3075 // and we did not want to embed the knowledge about this in
3076 // the caller routine. This only avoids double error reporting.
3081 Report
.Error (154, loc
,
3082 "The property `" + PropertyInfo
.Name
+
3083 "' can not be used in " +
3084 "this context because it lacks a set accessor");
3088 if (!InstanceResolve (ec
))
3092 // Only base will allow this invocation to happen.
3094 if (IsBase
&& setter
.IsAbstract
){
3095 Report
.Error (205, loc
, "Cannot call an abstract base property: " +
3096 PropertyInfo
.DeclaringType
+ "." +PropertyInfo
.Name
);
3102 override public void Emit (EmitContext ec
)
3105 // Special case: length of single dimension array property is turned into ldlen
3107 if ((getter
== TypeManager
.system_int_array_get_length
) ||
3108 (getter
== TypeManager
.int_array_get_length
)){
3109 Type iet
= instance_expr
.Type
;
3112 // System.Array.Length can be called, but the Type does not
3113 // support invoking GetArrayRank, so test for that case first
3115 if (iet
!= TypeManager
.array_type
&& (iet
.GetArrayRank () == 1)){
3116 instance_expr
.Emit (ec
);
3117 ec
.ig
.Emit (OpCodes
.Ldlen
);
3118 ec
.ig
.Emit (OpCodes
.Conv_I4
);
3123 Invocation
.EmitCall (ec
, IsBase
, IsStatic
, instance_expr
, getter
, null, loc
);
3128 // Implements the IAssignMethod interface for assignments
3130 public void EmitAssign (EmitContext ec
, Expression source
)
3132 Argument arg
= new Argument (source
, Argument
.AType
.Expression
);
3133 ArrayList args
= new ArrayList ();
3136 Invocation
.EmitCall (ec
, IsBase
, IsStatic
, instance_expr
, setter
, args
, loc
);
3139 override public void EmitStatement (EmitContext ec
)
3142 ec
.ig
.Emit (OpCodes
.Pop
);
3147 /// Fully resolved expression that evaluates to an Event
3149 public class EventExpr
: Expression
, IMemberExpr
{
3150 public readonly EventInfo EventInfo
;
3151 public Expression instance_expr
;
3154 MethodInfo add_accessor
, remove_accessor
;
3156 public EventExpr (EventInfo ei
, Location loc
)
3160 eclass
= ExprClass
.EventAccess
;
3162 add_accessor
= TypeManager
.GetAddMethod (ei
);
3163 remove_accessor
= TypeManager
.GetRemoveMethod (ei
);
3165 if (add_accessor
.IsStatic
|| remove_accessor
.IsStatic
)
3168 if (EventInfo
is MyEventBuilder
){
3169 MyEventBuilder eb
= (MyEventBuilder
) EventInfo
;
3170 type
= eb
.EventType
;
3173 type
= EventInfo
.EventHandlerType
;
3176 public string Name
{
3178 return EventInfo
.Name
;
3182 public bool IsInstance
{
3188 public bool IsStatic
{
3194 public Type DeclaringType
{
3196 return EventInfo
.DeclaringType
;
3200 public Expression InstanceExpression
{
3202 return instance_expr
;
3206 instance_expr
= value;
3210 public override Expression
DoResolve (EmitContext ec
)
3212 if (instance_expr
!= null) {
3213 instance_expr
= instance_expr
.DoResolve (ec
);
3214 if (instance_expr
== null)
3222 public override void Emit (EmitContext ec
)
3224 Report
.Error (70, loc
, "The event `" + Name
+ "' can only appear on the left hand side of += or -= (except on the defining type)");
3227 public void EmitAddOrRemove (EmitContext ec
, Expression source
)
3229 BinaryDelegate source_del
= (BinaryDelegate
) source
;
3230 Expression handler
= source_del
.Right
;
3232 Argument arg
= new Argument (handler
, Argument
.AType
.Expression
);
3233 ArrayList args
= new ArrayList ();
3237 if (source_del
.IsAddition
)
3238 Invocation
.EmitCall (
3239 ec
, false, IsStatic
, instance_expr
, add_accessor
, args
, loc
);
3241 Invocation
.EmitCall (
3242 ec
, false, IsStatic
, instance_expr
, remove_accessor
, args
, loc
);