2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
12 namespace Mono
.CSharp
{
14 using System
.Collections
;
15 using System
.Diagnostics
;
16 using System
.Reflection
;
17 using System
.Reflection
.Emit
;
21 /// The ExprClass class contains the is used to pass the
22 /// classification of an expression (value, variable, namespace,
23 /// type, method group, property access, event access, indexer access,
26 public enum ExprClass
: byte {
41 /// This is used to tell Resolve in which types of expressions we're
45 public enum ResolveFlags
{
46 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 // Returns a type expression.
52 // Returns a method group.
55 // Mask of all the expression class flags.
58 // Disable control flow analysis while resolving the expression.
59 // This is used when resolving the instance expression of a field expression.
60 DisableFlowAnalysis
= 8,
62 // Set if this is resolving the first part of a MemberAccess.
65 // Disable control flow analysis _of struct_ while resolving the expression.
66 // This is used when resolving the instance expression of a field expression.
67 DisableStructFlowAnalysis
= 32,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp
{
82 /// This interface is implemented by variables
84 public interface IMemoryLocation
{
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec
, AddressOp mode
);
100 /// This interface is implemented by variables
102 public interface IVariable
{
103 VariableInfo VariableInfo
{
111 /// Base class for expressions
113 public abstract class Expression
{
114 public ExprClass eclass
;
116 protected Location loc
;
120 set { type = value; }
123 public virtual Location Location
{
128 /// Utility wrapper routine for Error, just to beautify the code
130 public void Error (int error
, string s
)
132 Report
.Error (error
, loc
, s
);
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess ()
140 public virtual bool GetAttributableValue (Type valueType
, out object value)
142 Attribute
.Error_AttributeArgumentNotValid (loc
);
147 public virtual string GetSignatureForError ()
149 return TypeManager
.CSharpName (type
);
152 public static bool IsAccessorAccessible (Type invocation_type
, MethodInfo mi
, out bool must_do_cs1540_check
)
154 MethodAttributes ma
= mi
.Attributes
& MethodAttributes
.MemberAccessMask
;
156 must_do_cs1540_check
= false; // by default we do not check for this
159 // If only accessible to the current class or children
161 if (ma
== MethodAttributes
.Private
)
162 return invocation_type
== mi
.DeclaringType
||
163 TypeManager
.IsNestedChildOf (invocation_type
, mi
.DeclaringType
);
165 if (mi
.DeclaringType
.Assembly
== invocation_type
.Assembly
) {
166 if (ma
== MethodAttributes
.Assembly
|| ma
== MethodAttributes
.FamORAssem
)
169 if (ma
== MethodAttributes
.Assembly
|| ma
== MethodAttributes
.FamANDAssem
)
173 // Family and FamANDAssem require that we derive.
174 // FamORAssem requires that we derive if in different assemblies.
175 if (ma
== MethodAttributes
.Family
||
176 ma
== MethodAttributes
.FamANDAssem
||
177 ma
== MethodAttributes
.FamORAssem
) {
178 if (!TypeManager
.IsNestedFamilyAccessible (invocation_type
, mi
.DeclaringType
))
181 if (!TypeManager
.IsNestedChildOf (invocation_type
, mi
.DeclaringType
))
182 must_do_cs1540_check
= true;
191 /// Performs semantic analysis on the Expression
195 /// The Resolve method is invoked to perform the semantic analysis
198 /// The return value is an expression (it can be the
199 /// same expression in some cases) or a new
200 /// expression that better represents this node.
202 /// For example, optimizations of Unary (LiteralInt)
203 /// would return a new LiteralInt with a negated
206 /// If there is an error during semantic analysis,
207 /// then an error should be reported (using Report)
208 /// and a null value should be returned.
210 /// There are two side effects expected from calling
211 /// Resolve(): the the field variable "eclass" should
212 /// be set to any value of the enumeration
213 /// `ExprClass' and the type variable should be set
214 /// to a valid type (this is the type of the
217 public abstract Expression
DoResolve (EmitContext ec
);
219 public virtual Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
225 // This is used if the expression should be resolved as a type or namespace name.
226 // the default implementation fails.
228 public virtual FullNamedExpression
ResolveAsTypeStep (IResolveContext ec
, bool silent
)
234 // This is used to resolve the expression as a type, a null
235 // value will be returned if the expression is not a type
238 public virtual TypeExpr
ResolveAsTypeTerminal (IResolveContext ec
, bool silent
)
240 TypeExpr te
= ResolveAsBaseTerminal (ec
, silent
);
244 ObsoleteAttribute obsolete_attr
= AttributeTester
.GetObsoleteAttribute (te
.Type
);
245 if (obsolete_attr
!= null && !ec
.IsInObsoleteScope
) {
246 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, GetSignatureForError (), Location
);
251 public TypeExpr
ResolveAsBaseTerminal (IResolveContext ec
, bool silent
)
253 int errors
= Report
.Errors
;
255 FullNamedExpression fne
= ResolveAsTypeStep (ec
, silent
);
258 if (!silent
&& errors
== Report
.Errors
)
259 Report
.Error (118, loc
, "Expecting a type.");
263 if (fne
.eclass
!= ExprClass
.Type
) {
264 if (!silent
&& errors
== Report
.Errors
)
265 fne
.Error_UnexpectedKind (null, "type", loc
);
269 TypeExpr te
= fne
as TypeExpr
;
271 if (!te
.CheckAccessLevel (ec
.DeclContainer
)) {
272 ErrorIsInaccesible (loc
, TypeManager
.CSharpName (te
.Type
));
280 public static void ErrorIsInaccesible (Location loc
, string name
)
282 Report
.Error (122, loc
, "`{0}' is inaccessible due to its protection level", name
);
285 protected static void Error_CannotAccessProtected (Location loc
, MemberInfo m
, Type qualifier
, Type container
)
287 Report
.Error (1540, loc
, "Cannot access protected member `{0}' via a qualifier of type `{1}';"
288 + " the qualifier must be of type `{2}' (or derived from it)",
289 TypeManager
.GetFullNameSignature (m
),
290 TypeManager
.CSharpName (qualifier
),
291 TypeManager
.CSharpName (container
));
295 public virtual void Error_ValueCannotBeConverted (Location loc
, Type target
, bool expl
)
297 if (Type
.Name
== target
.Name
){
298 Report
.ExtraInformation (loc
,
300 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
301 Type
.Name
, Type
.Assembly
.FullName
, target
.Assembly
.FullName
));
306 Report
.Error (30, loc
, "Cannot convert type `{0}' to `{1}'",
307 GetSignatureForError (), TypeManager
.CSharpName (target
));
311 Expression e
= (this is EnumConstant
) ? ((EnumConstant
)this).Child
: this;
312 bool b
= Convert
.ExplicitNumericConversion (e
, target
) != null;
314 if (b
|| Convert
.ExplicitReferenceConversionExists (Type
, target
) || Convert
.ExplicitUnsafe (e
, target
) != null) {
315 Report
.Error (266, loc
, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
316 TypeManager
.CSharpName (Type
), TypeManager
.CSharpName (target
));
320 if (Type
!= TypeManager
.string_type
&& this is Constant
&& !(this is NullCast
)) {
321 Report
.Error (31, loc
, "Constant value `{0}' cannot be converted to a `{1}'",
322 GetSignatureForError (), TypeManager
.CSharpName (target
));
326 Report
.Error (29, loc
, "Cannot implicitly convert type {0} to `{1}'",
327 Type
== TypeManager
.anonymous_method_type
?
328 "anonymous method" : "`" + GetSignatureForError () + "'",
329 TypeManager
.CSharpName (target
));
332 protected static void Error_TypeDoesNotContainDefinition (Location loc
, Type type
, string name
)
334 Report
.Error (117, loc
, "`{0}' does not contain a definition for `{1}'",
335 TypeManager
.CSharpName (type
), name
);
338 ResolveFlags ExprClassToResolveFlags
343 case ExprClass
.Namespace
:
344 return ResolveFlags
.Type
;
346 case ExprClass
.MethodGroup
:
347 return ResolveFlags
.MethodGroup
;
349 case ExprClass
.Value
:
350 case ExprClass
.Variable
:
351 case ExprClass
.PropertyAccess
:
352 case ExprClass
.EventAccess
:
353 case ExprClass
.IndexerAccess
:
354 return ResolveFlags
.VariableOrValue
;
357 throw new Exception ("Expression " + GetType () +
358 " ExprClass is Invalid after resolve");
364 /// Resolves an expression and performs semantic analysis on it.
368 /// Currently Resolve wraps DoResolve to perform sanity
369 /// checking and assertion checking on what we expect from Resolve.
371 public Expression
Resolve (EmitContext ec
, ResolveFlags flags
)
373 if ((flags
& ResolveFlags
.MaskExprClass
) == ResolveFlags
.Type
)
374 return ResolveAsTypeStep (ec
, false);
376 bool old_do_flow_analysis
= ec
.DoFlowAnalysis
;
377 bool old_omit_struct_analysis
= ec
.OmitStructFlowAnalysis
;
378 if ((flags
& ResolveFlags
.DisableFlowAnalysis
) != 0)
379 ec
.DoFlowAnalysis
= false;
380 if ((flags
& ResolveFlags
.DisableStructFlowAnalysis
) != 0)
381 ec
.OmitStructFlowAnalysis
= true;
384 if (this is SimpleName
) {
385 bool intermediate
= (flags
& ResolveFlags
.Intermediate
) == ResolveFlags
.Intermediate
;
386 e
= ((SimpleName
) this).DoResolve (ec
, intermediate
);
391 ec
.DoFlowAnalysis
= old_do_flow_analysis
;
392 ec
.OmitStructFlowAnalysis
= old_omit_struct_analysis
;
397 if ((flags
& e
.ExprClassToResolveFlags
) == 0) {
398 e
.Error_UnexpectedKind (flags
, loc
);
402 if (e
.type
== null && !(e
is Namespace
)) {
403 throw new Exception (
404 "Expression " + e
.GetType () +
405 " did not set its type after Resolve\n" +
406 "called from: " + this.GetType ());
413 /// Resolves an expression and performs semantic analysis on it.
415 public Expression
Resolve (EmitContext ec
)
417 Expression e
= Resolve (ec
, ResolveFlags
.VariableOrValue
| ResolveFlags
.MethodGroup
);
419 if (e
!= null && e
.eclass
== ExprClass
.MethodGroup
&& RootContext
.Version
== LanguageVersion
.ISO_1
) {
420 ((MethodGroupExpr
) e
).ReportUsageError ();
426 public Constant
ResolveAsConstant (EmitContext ec
, MemberCore mc
)
428 Expression e
= Resolve (ec
);
432 Constant c
= e
as Constant
;
436 Const
.Error_ExpressionMustBeConstant (loc
, mc
.GetSignatureForError ());
441 /// Resolves an expression for LValue assignment
445 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
446 /// checking and assertion checking on what we expect from Resolve
448 public Expression
ResolveLValue (EmitContext ec
, Expression right_side
, Location loc
)
450 int errors
= Report
.Errors
;
451 bool out_access
= right_side
== EmptyExpression
.OutAccess
;
453 Expression e
= DoResolveLValue (ec
, right_side
);
455 if (e
!= null && out_access
&& !(e
is IMemoryLocation
)) {
456 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
457 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
459 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
460 // e.GetType () + " " + e.GetSignatureForError ());
465 if (errors
== Report
.Errors
) {
467 Report
.Error (1510, loc
, "A ref or out argument must be an assignable variable");
469 Report
.Error (131, loc
, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
474 if (e
.eclass
== ExprClass
.Invalid
)
475 throw new Exception ("Expression " + e
+ " ExprClass is Invalid after resolve");
477 if (e
.eclass
== ExprClass
.MethodGroup
) {
478 ((MethodGroupExpr
) e
).ReportUsageError ();
483 throw new Exception ("Expression " + e
+ " did not set its type after Resolve");
489 /// Emits the code for the expression
493 /// The Emit method is invoked to generate the code
494 /// for the expression.
496 public abstract void Emit (EmitContext ec
);
498 public virtual void EmitBranchable (EmitContext ec
, Label target
, bool onTrue
)
501 ec
.ig
.Emit (onTrue
? OpCodes
.Brtrue
: OpCodes
.Brfalse
, target
);
505 /// Protected constructor. Only derivate types should
506 /// be able to be created
509 protected Expression ()
511 eclass
= ExprClass
.Invalid
;
516 /// Returns a literalized version of a literal FieldInfo
520 /// The possible return values are:
521 /// IntConstant, UIntConstant
522 /// LongLiteral, ULongConstant
523 /// FloatConstant, DoubleConstant
526 /// The value returned is already resolved.
528 public static Constant
Constantify (object v
, Type t
)
530 if (t
== TypeManager
.int32_type
)
531 return new IntConstant ((int) v
, Location
.Null
);
532 else if (t
== TypeManager
.uint32_type
)
533 return new UIntConstant ((uint) v
, Location
.Null
);
534 else if (t
== TypeManager
.int64_type
)
535 return new LongConstant ((long) v
, Location
.Null
);
536 else if (t
== TypeManager
.uint64_type
)
537 return new ULongConstant ((ulong) v
, Location
.Null
);
538 else if (t
== TypeManager
.float_type
)
539 return new FloatConstant ((float) v
, Location
.Null
);
540 else if (t
== TypeManager
.double_type
)
541 return new DoubleConstant ((double) v
, Location
.Null
);
542 else if (t
== TypeManager
.string_type
)
543 return new StringConstant ((string) v
, Location
.Null
);
544 else if (t
== TypeManager
.short_type
)
545 return new ShortConstant ((short)v
, Location
.Null
);
546 else if (t
== TypeManager
.ushort_type
)
547 return new UShortConstant ((ushort)v
, Location
.Null
);
548 else if (t
== TypeManager
.sbyte_type
)
549 return new SByteConstant ((sbyte)v
, Location
.Null
);
550 else if (t
== TypeManager
.byte_type
)
551 return new ByteConstant ((byte)v
, Location
.Null
);
552 else if (t
== TypeManager
.char_type
)
553 return new CharConstant ((char)v
, Location
.Null
);
554 else if (t
== TypeManager
.bool_type
)
555 return new BoolConstant ((bool) v
, Location
.Null
);
556 else if (t
== TypeManager
.decimal_type
)
557 return new DecimalConstant ((decimal) v
, Location
.Null
);
558 else if (TypeManager
.IsEnumType (t
)){
559 Type real_type
= TypeManager
.TypeToCoreType (v
.GetType ());
561 real_type
= System
.Enum
.GetUnderlyingType (real_type
);
563 Constant e
= Constantify (v
, real_type
);
565 return new EnumConstant (e
, t
);
566 } else if (v
== null && !TypeManager
.IsValueType (t
))
567 return new NullLiteral (Location
.Null
);
569 throw new Exception ("Unknown type for constant (" + t
+
574 /// Returns a fully formed expression after a MemberLookup
577 public static Expression
ExprClassFromMemberInfo (Type containerType
, MemberInfo mi
, Location loc
)
580 return new EventExpr ((EventInfo
) mi
, loc
);
581 else if (mi
is FieldInfo
)
582 return new FieldExpr ((FieldInfo
) mi
, loc
);
583 else if (mi
is PropertyInfo
)
584 return new PropertyExpr (containerType
, (PropertyInfo
) mi
, loc
);
585 else if (mi
is Type
){
586 return new TypeExpression ((System
.Type
) mi
, loc
);
592 protected static ArrayList almostMatchedMembers
= new ArrayList (4);
595 // FIXME: Probably implement a cache for (t,name,current_access_set)?
597 // This code could use some optimizations, but we need to do some
598 // measurements. For example, we could use a delegate to `flag' when
599 // something can not any longer be a method-group (because it is something
603 // If the return value is an Array, then it is an array of
606 // If the return value is an MemberInfo, it is anything, but a Method
610 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
611 // the arguments here and have MemberLookup return only the methods that
612 // match the argument count/type, unlike we are doing now (we delay this
615 // This is so we can catch correctly attempts to invoke instance methods
616 // from a static body (scan for error 120 in ResolveSimpleName).
619 // FIXME: Potential optimization, have a static ArrayList
622 public static Expression
MemberLookup (Type container_type
, Type queried_type
, string name
,
623 MemberTypes mt
, BindingFlags bf
, Location loc
)
625 return MemberLookup (container_type
, null, queried_type
, name
, mt
, bf
, loc
);
629 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
630 // `qualifier_type' or null to lookup members in the current class.
633 public static Expression
MemberLookup (Type container_type
,
634 Type qualifier_type
, Type queried_type
,
635 string name
, MemberTypes mt
,
636 BindingFlags bf
, Location loc
)
638 almostMatchedMembers
.Clear ();
640 MemberInfo
[] mi
= TypeManager
.MemberLookup (container_type
, qualifier_type
,
641 queried_type
, mt
, bf
, name
, almostMatchedMembers
);
646 int count
= mi
.Length
;
648 if (mi
[0] is MethodBase
)
649 return new MethodGroupExpr (mi
, loc
);
654 return ExprClassFromMemberInfo (container_type
, mi
[0], loc
);
657 public const MemberTypes AllMemberTypes
=
658 MemberTypes
.Constructor
|
662 MemberTypes
.NestedType
|
663 MemberTypes
.Property
;
665 public const BindingFlags AllBindingFlags
=
666 BindingFlags
.Public
|
667 BindingFlags
.Static
|
668 BindingFlags
.Instance
;
670 public static Expression
MemberLookup (Type container_type
, Type queried_type
,
671 string name
, Location loc
)
673 return MemberLookup (container_type
, null, queried_type
, name
,
674 AllMemberTypes
, AllBindingFlags
, loc
);
677 public static Expression
MemberLookup (Type container_type
, Type qualifier_type
,
678 Type queried_type
, string name
, Location loc
)
680 return MemberLookup (container_type
, qualifier_type
, queried_type
,
681 name
, AllMemberTypes
, AllBindingFlags
, loc
);
684 public static Expression
MethodLookup (EmitContext ec
, Type queried_type
,
685 string name
, Location loc
)
687 return MemberLookup (ec
.ContainerType
, null, queried_type
, name
,
688 MemberTypes
.Method
, AllBindingFlags
, loc
);
692 /// This is a wrapper for MemberLookup that is not used to "probe", but
693 /// to find a final definition. If the final definition is not found, we
694 /// look for private members and display a useful debugging message if we
697 public static Expression
MemberLookupFinal (EmitContext ec
, Type qualifier_type
,
698 Type queried_type
, string name
, Location loc
)
700 return MemberLookupFinal (ec
, qualifier_type
, queried_type
, name
,
701 AllMemberTypes
, AllBindingFlags
, loc
);
704 public static Expression
MemberLookupFinal (EmitContext ec
, Type qualifier_type
,
705 Type queried_type
, string name
,
706 MemberTypes mt
, BindingFlags bf
,
711 int errors
= Report
.Errors
;
713 e
= MemberLookup (ec
.ContainerType
, qualifier_type
, queried_type
, name
, mt
, bf
, loc
);
715 if (e
== null && errors
== Report
.Errors
)
716 // No errors were reported by MemberLookup, but there was an error.
717 MemberLookupFailed (ec
.ContainerType
, qualifier_type
, queried_type
, name
, null, true, loc
);
722 public static void MemberLookupFailed (Type container_type
, Type qualifier_type
,
723 Type queried_type
, string name
,
724 string class_name
, bool complain_if_none_found
,
727 if (almostMatchedMembers
.Count
!= 0) {
728 for (int i
= 0; i
< almostMatchedMembers
.Count
; ++i
) {
729 MemberInfo m
= (MemberInfo
) almostMatchedMembers
[i
];
730 for (int j
= 0; j
< i
; ++j
) {
731 if (m
== almostMatchedMembers
[j
]) {
739 Type declaring_type
= m
.DeclaringType
;
741 Report
.SymbolRelatedToPreviousError (m
);
742 if (qualifier_type
== null) {
743 Report
.Error (38, loc
, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
744 TypeManager
.CSharpName (m
.DeclaringType
),
745 TypeManager
.CSharpName (container_type
));
747 } else if (qualifier_type
!= container_type
&&
748 TypeManager
.IsNestedFamilyAccessible (container_type
, declaring_type
)) {
749 // Although a derived class can access protected members of
750 // its base class it cannot do so through an instance of the
751 // base class (CS1540). If the qualifier_type is a base of the
752 // ec.ContainerType and the lookup succeeds with the latter one,
753 // then we are in this situation.
754 Error_CannotAccessProtected (loc
, m
, qualifier_type
, container_type
);
756 ErrorIsInaccesible (loc
, TypeManager
.GetFullNameSignature (m
));
759 almostMatchedMembers
.Clear ();
763 MemberInfo
[] lookup
= TypeManager
.MemberLookup (queried_type
, null, queried_type
,
764 AllMemberTypes
, AllBindingFlags
|
765 BindingFlags
.NonPublic
, name
, null);
767 if (lookup
== null) {
768 if (!complain_if_none_found
)
771 if (class_name
!= null)
772 Report
.Error (103, loc
, "The name `{0}' does not exist in the context of `{1}'",
775 Error_TypeDoesNotContainDefinition (loc
, queried_type
, name
);
779 MemberList ml
= TypeManager
.FindMembers (queried_type
, MemberTypes
.Constructor
,
780 BindingFlags
.Static
| BindingFlags
.Instance
| BindingFlags
.Public
| BindingFlags
.DeclaredOnly
, null, null);
781 if (name
== ".ctor" && ml
.Count
== 0)
783 Report
.Error (143, loc
, "The type `{0}' has no constructors defined", TypeManager
.CSharpName (queried_type
));
787 ErrorIsInaccesible (loc
, TypeManager
.GetFullNameSignature (lookup
[0]));
791 /// Returns an expression that can be used to invoke operator true
792 /// on the expression if it exists.
794 static public StaticCallExpr
GetOperatorTrue (EmitContext ec
, Expression e
, Location loc
)
796 return GetOperatorTrueOrFalse (ec
, e
, true, loc
);
800 /// Returns an expression that can be used to invoke operator false
801 /// on the expression if it exists.
803 static public StaticCallExpr
GetOperatorFalse (EmitContext ec
, Expression e
, Location loc
)
805 return GetOperatorTrueOrFalse (ec
, e
, false, loc
);
808 static StaticCallExpr
GetOperatorTrueOrFalse (EmitContext ec
, Expression e
, bool is_true
, Location loc
)
811 Expression operator_group
;
813 operator_group
= MethodLookup (ec
, e
.Type
, is_true
? "op_True" : "op_False", loc
);
814 if (operator_group
== null)
817 ArrayList arguments
= new ArrayList ();
818 arguments
.Add (new Argument (e
, Argument
.AType
.Expression
));
819 method
= Invocation
.OverloadResolve (
820 ec
, (MethodGroupExpr
) operator_group
, arguments
, false, loc
);
825 return new StaticCallExpr ((MethodInfo
) method
, arguments
, loc
);
829 /// Resolves the expression `e' into a boolean expression: either through
830 /// an implicit conversion, or through an `operator true' invocation
832 public static Expression
ResolveBoolean (EmitContext ec
, Expression e
, Location loc
)
838 if (e
.Type
== TypeManager
.bool_type
)
841 Expression converted
= Convert
.ImplicitConversion (ec
, e
, TypeManager
.bool_type
, Location
.Null
);
843 if (converted
!= null)
847 // If no implicit conversion to bool exists, try using `operator true'
849 converted
= Expression
.GetOperatorTrue (ec
, e
, loc
);
850 if (converted
== null){
851 e
.Error_ValueCannotBeConverted (loc
, TypeManager
.bool_type
, false);
857 public virtual string ExprClassName
861 case ExprClass
.Invalid
:
863 case ExprClass
.Value
:
865 case ExprClass
.Variable
:
867 case ExprClass
.Namespace
:
871 case ExprClass
.MethodGroup
:
872 return "method group";
873 case ExprClass
.PropertyAccess
:
874 return "property access";
875 case ExprClass
.EventAccess
:
876 return "event access";
877 case ExprClass
.IndexerAccess
:
878 return "indexer access";
879 case ExprClass
.Nothing
:
882 throw new Exception ("Should not happen");
887 /// Reports that we were expecting `expr' to be of class `expected'
889 public void Error_UnexpectedKind (DeclSpace ds
, string expected
, Location loc
)
891 Error_UnexpectedKind (ds
, expected
, ExprClassName
, loc
);
894 public void Error_UnexpectedKind (DeclSpace ds
, string expected
, string was
, Location loc
)
896 string name
= GetSignatureForError ();
898 name
= ds
.GetSignatureForError () + '.' + name
;
900 Report
.Error (118, loc
, "`{0}' is a `{1}' but a `{2}' was expected",
901 name
, was
, expected
);
904 public void Error_UnexpectedKind (ResolveFlags flags
, Location loc
)
906 string [] valid
= new string [4];
909 if ((flags
& ResolveFlags
.VariableOrValue
) != 0) {
910 valid
[count
++] = "variable";
911 valid
[count
++] = "value";
914 if ((flags
& ResolveFlags
.Type
) != 0)
915 valid
[count
++] = "type";
917 if ((flags
& ResolveFlags
.MethodGroup
) != 0)
918 valid
[count
++] = "method group";
921 valid
[count
++] = "unknown";
923 StringBuilder sb
= new StringBuilder (valid
[0]);
924 for (int i
= 1; i
< count
- 1; i
++) {
926 sb
.Append (valid
[i
]);
929 sb
.Append ("' or `");
930 sb
.Append (valid
[count
- 1]);
933 Report
.Error (119, loc
,
934 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName
, sb
.ToString ());
937 public static void UnsafeError (Location loc
)
939 Report
.Error (214, loc
, "Pointers and fixed size buffers may only be used in an unsafe context");
943 // Load the object from the pointer.
945 public static void LoadFromPtr (ILGenerator ig
, Type t
)
947 if (t
== TypeManager
.int32_type
)
948 ig
.Emit (OpCodes
.Ldind_I4
);
949 else if (t
== TypeManager
.uint32_type
)
950 ig
.Emit (OpCodes
.Ldind_U4
);
951 else if (t
== TypeManager
.short_type
)
952 ig
.Emit (OpCodes
.Ldind_I2
);
953 else if (t
== TypeManager
.ushort_type
)
954 ig
.Emit (OpCodes
.Ldind_U2
);
955 else if (t
== TypeManager
.char_type
)
956 ig
.Emit (OpCodes
.Ldind_U2
);
957 else if (t
== TypeManager
.byte_type
)
958 ig
.Emit (OpCodes
.Ldind_U1
);
959 else if (t
== TypeManager
.sbyte_type
)
960 ig
.Emit (OpCodes
.Ldind_I1
);
961 else if (t
== TypeManager
.uint64_type
)
962 ig
.Emit (OpCodes
.Ldind_I8
);
963 else if (t
== TypeManager
.int64_type
)
964 ig
.Emit (OpCodes
.Ldind_I8
);
965 else if (t
== TypeManager
.float_type
)
966 ig
.Emit (OpCodes
.Ldind_R4
);
967 else if (t
== TypeManager
.double_type
)
968 ig
.Emit (OpCodes
.Ldind_R8
);
969 else if (t
== TypeManager
.bool_type
)
970 ig
.Emit (OpCodes
.Ldind_I1
);
971 else if (t
== TypeManager
.intptr_type
)
972 ig
.Emit (OpCodes
.Ldind_I
);
973 else if (TypeManager
.IsEnumType (t
)) {
974 if (t
== TypeManager
.enum_type
)
975 ig
.Emit (OpCodes
.Ldind_Ref
);
977 LoadFromPtr (ig
, TypeManager
.EnumToUnderlying (t
));
978 } else if (t
.IsValueType
)
979 ig
.Emit (OpCodes
.Ldobj
, t
);
980 else if (t
.IsPointer
)
981 ig
.Emit (OpCodes
.Ldind_I
);
983 ig
.Emit (OpCodes
.Ldind_Ref
);
987 // The stack contains the pointer and the value of type `type'
989 public static void StoreFromPtr (ILGenerator ig
, Type type
)
991 if (TypeManager
.IsEnumType (type
))
992 type
= TypeManager
.EnumToUnderlying (type
);
993 if (type
== TypeManager
.int32_type
|| type
== TypeManager
.uint32_type
)
994 ig
.Emit (OpCodes
.Stind_I4
);
995 else if (type
== TypeManager
.int64_type
|| type
== TypeManager
.uint64_type
)
996 ig
.Emit (OpCodes
.Stind_I8
);
997 else if (type
== TypeManager
.char_type
|| type
== TypeManager
.short_type
||
998 type
== TypeManager
.ushort_type
)
999 ig
.Emit (OpCodes
.Stind_I2
);
1000 else if (type
== TypeManager
.float_type
)
1001 ig
.Emit (OpCodes
.Stind_R4
);
1002 else if (type
== TypeManager
.double_type
)
1003 ig
.Emit (OpCodes
.Stind_R8
);
1004 else if (type
== TypeManager
.byte_type
|| type
== TypeManager
.sbyte_type
||
1005 type
== TypeManager
.bool_type
)
1006 ig
.Emit (OpCodes
.Stind_I1
);
1007 else if (type
== TypeManager
.intptr_type
)
1008 ig
.Emit (OpCodes
.Stind_I
);
1009 else if (type
.IsValueType
)
1010 ig
.Emit (OpCodes
.Stobj
, type
);
1012 ig
.Emit (OpCodes
.Stind_Ref
);
1016 // Returns the size of type `t' if known, otherwise, 0
1018 public static int GetTypeSize (Type t
)
1020 t
= TypeManager
.TypeToCoreType (t
);
1021 if (t
== TypeManager
.int32_type
||
1022 t
== TypeManager
.uint32_type
||
1023 t
== TypeManager
.float_type
)
1025 else if (t
== TypeManager
.int64_type
||
1026 t
== TypeManager
.uint64_type
||
1027 t
== TypeManager
.double_type
)
1029 else if (t
== TypeManager
.byte_type
||
1030 t
== TypeManager
.sbyte_type
||
1031 t
== TypeManager
.bool_type
)
1033 else if (t
== TypeManager
.short_type
||
1034 t
== TypeManager
.char_type
||
1035 t
== TypeManager
.ushort_type
)
1037 else if (t
== TypeManager
.decimal_type
)
1043 public static void Error_NegativeArrayIndex (Location loc
)
1045 Report
.Error (248, loc
, "Cannot create an array with a negative size");
1048 protected void Error_CannotCallAbstractBase (string name
)
1050 Report
.Error (205, loc
, "Cannot call an abstract base member `{0}'", name
);
1054 // Converts `source' to an int, uint, long or ulong.
1056 public Expression
ExpressionToArrayArgument (EmitContext ec
, Expression source
, Location loc
)
1060 bool old_checked
= ec
.CheckState
;
1061 ec
.CheckState
= true;
1063 target
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.int32_type
, loc
);
1064 if (target
== null){
1065 target
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.uint32_type
, loc
);
1066 if (target
== null){
1067 target
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.int64_type
, loc
);
1068 if (target
== null){
1069 target
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.uint64_type
, loc
);
1071 source
.Error_ValueCannotBeConverted (loc
, TypeManager
.int32_type
, false);
1075 ec
.CheckState
= old_checked
;
1078 // Only positive constants are allowed at compile time
1080 if (target
is Constant
){
1081 if (target
is IntConstant
){
1082 if (((IntConstant
) target
).Value
< 0){
1083 Error_NegativeArrayIndex (loc
);
1088 if (target
is LongConstant
){
1089 if (((LongConstant
) target
).Value
< 0){
1090 Error_NegativeArrayIndex (loc
);
1103 /// This is just a base class for expressions that can
1104 /// appear on statements (invocations, object creation,
1105 /// assignments, post/pre increment and decrement). The idea
1106 /// being that they would support an extra Emition interface that
1107 /// does not leave a result on the stack.
1109 public abstract class ExpressionStatement
: Expression
{
1111 public virtual ExpressionStatement
ResolveStatement (EmitContext ec
)
1113 Expression e
= Resolve (ec
);
1117 ExpressionStatement es
= e
as ExpressionStatement
;
1119 Error (201, "Only assignment, call, increment, decrement and new object " +
1120 "expressions can be used as a statement");
1126 /// Requests the expression to be emitted in a `statement'
1127 /// context. This means that no new value is left on the
1128 /// stack after invoking this method (constrasted with
1129 /// Emit that will always leave a value on the stack).
1131 public abstract void EmitStatement (EmitContext ec
);
1135 /// This kind of cast is used to encapsulate the child
1136 /// whose type is child.Type into an expression that is
1137 /// reported to return "return_type". This is used to encapsulate
1138 /// expressions which have compatible types, but need to be dealt
1139 /// at higher levels with.
1141 /// For example, a "byte" expression could be encapsulated in one
1142 /// of these as an "unsigned int". The type for the expression
1143 /// would be "unsigned int".
1146 public class EmptyCast
: Expression
{
1147 protected readonly Expression child
;
1149 public EmptyCast (Expression child
, Type return_type
)
1151 eclass
= child
.eclass
;
1152 loc
= child
.Location
;
1157 public override Expression
DoResolve (EmitContext ec
)
1159 // This should never be invoked, we are born in fully
1160 // initialized state.
1165 public override void Emit (EmitContext ec
)
1170 public override bool GetAttributableValue (Type valueType
, out object value)
1172 return child
.GetAttributableValue (valueType
, out value);
1177 /// This is a numeric cast to a Decimal
1179 public class CastToDecimal
: EmptyCast
{
1181 MethodInfo conversion_operator
;
1183 public CastToDecimal (Expression child
)
1184 : this (child
, false)
1188 public CastToDecimal (Expression child
, bool find_explicit
)
1189 : base (child
, TypeManager
.decimal_type
)
1191 conversion_operator
= GetConversionOperator (find_explicit
);
1193 if (conversion_operator
== null)
1194 throw new InternalErrorException ("Outer conversion routine is out of sync");
1197 // Returns the implicit operator that converts from
1198 // 'child.Type' to System.Decimal.
1199 MethodInfo
GetConversionOperator (bool find_explicit
)
1201 string operator_name
= find_explicit
? "op_Explicit" : "op_Implicit";
1203 MemberInfo
[] mi
= TypeManager
.MemberLookup (type
, type
, type
, MemberTypes
.Method
,
1204 BindingFlags
.Static
| BindingFlags
.Public
, operator_name
, null);
1206 foreach (MethodInfo oper
in mi
) {
1207 ParameterData pd
= TypeManager
.GetParameterData (oper
);
1209 if (pd
.ParameterType (0) == child
.Type
&& oper
.ReturnType
== type
)
1215 public override void Emit (EmitContext ec
)
1217 ILGenerator ig
= ec
.ig
;
1220 ig
.Emit (OpCodes
.Call
, conversion_operator
);
1225 /// This is an explicit numeric cast from a Decimal
1227 public class CastFromDecimal
: EmptyCast
1229 static IDictionary operators
;
1231 public CastFromDecimal (Expression child
, Type return_type
)
1232 : base (child
, return_type
)
1234 if (child
.Type
!= TypeManager
.decimal_type
)
1235 throw new InternalErrorException (
1236 "The expected type is Decimal, instead it is " + child
.Type
.FullName
);
1239 // Returns the explicit operator that converts from an
1240 // express of type System.Decimal to 'type'.
1241 public Expression
Resolve ()
1243 if (operators
== null) {
1244 MemberInfo
[] all_oper
= TypeManager
.MemberLookup (TypeManager
.decimal_type
,
1245 TypeManager
.decimal_type
, TypeManager
.decimal_type
, MemberTypes
.Method
,
1246 BindingFlags
.Static
| BindingFlags
.Public
, "op_Explicit", null);
1248 operators
= new System
.Collections
.Specialized
.HybridDictionary ();
1249 foreach (MethodInfo oper
in all_oper
) {
1250 ParameterData pd
= TypeManager
.GetParameterData (oper
);
1251 if (pd
.ParameterType (0) == TypeManager
.decimal_type
)
1252 operators
.Add (oper
.ReturnType
, oper
);
1256 return operators
.Contains (type
) ? this : null;
1259 public override void Emit (EmitContext ec
)
1261 ILGenerator ig
= ec
.ig
;
1264 ig
.Emit (OpCodes
.Call
, (MethodInfo
)operators
[type
]);
1269 // We need to special case this since an empty cast of
1270 // a NullLiteral is still a Constant
1272 public class NullCast
: Constant
{
1273 public Constant child
;
1275 public NullCast (Constant child
, Type return_type
):
1276 base (Location
.Null
)
1278 eclass
= child
.eclass
;
1283 override public string AsString ()
1288 public override object GetValue ()
1293 public override Expression
DoResolve (EmitContext ec
)
1295 // This should never be invoked, we are born in fully
1296 // initialized state.
1301 public override void Emit (EmitContext ec
)
1306 public override Constant
Increment ()
1308 throw new NotSupportedException ();
1311 public override bool IsDefaultValue
{
1317 public override bool IsNegative
{
1323 public override Constant
Reduce (bool inCheckedContext
, Type target_type
)
1325 if (type
== target_type
)
1326 return child
.Reduce (inCheckedContext
, target_type
);
1335 /// This class is used to wrap literals which belong inside Enums
1337 public class EnumConstant
: Constant
{
1338 public Constant Child
;
1340 public EnumConstant (Constant child
, Type enum_type
):
1341 base (child
.Location
)
1343 eclass
= child
.eclass
;
1348 public override Expression
DoResolve (EmitContext ec
)
1350 // This should never be invoked, we are born in fully
1351 // initialized state.
1356 public override void Emit (EmitContext ec
)
1361 public override bool GetAttributableValue (Type valueType
, out object value)
1363 value = GetTypedValue ();
1367 public override string GetSignatureForError()
1369 return TypeManager
.CSharpName (Type
);
1372 public override object GetValue ()
1374 return Child
.GetValue ();
1377 public override object GetTypedValue ()
1379 // FIXME: runtime is not ready to work with just emited enums
1380 if (!RootContext
.StdLib
) {
1381 return Child
.GetValue ();
1384 return System
.Enum
.ToObject (type
, Child
.GetValue ());
1387 public override string AsString ()
1389 return Child
.AsString ();
1392 public override DoubleConstant
ConvertToDouble ()
1394 return Child
.ConvertToDouble ();
1397 public override FloatConstant
ConvertToFloat ()
1399 return Child
.ConvertToFloat ();
1402 public override ULongConstant
ConvertToULong ()
1404 return Child
.ConvertToULong ();
1407 public override LongConstant
ConvertToLong ()
1409 return Child
.ConvertToLong ();
1412 public override UIntConstant
ConvertToUInt ()
1414 return Child
.ConvertToUInt ();
1417 public override IntConstant
ConvertToInt ()
1419 return Child
.ConvertToInt ();
1422 public override Constant
Increment()
1424 return new EnumConstant (Child
.Increment (), type
);
1427 public override bool IsDefaultValue
{
1429 return Child
.IsDefaultValue
;
1433 public override bool IsZeroInteger
{
1434 get { return Child.IsZeroInteger; }
1437 public override bool IsNegative
{
1439 return Child
.IsNegative
;
1443 public override Constant
Reduce(bool inCheckedContext
, Type target_type
)
1445 if (Child
.Type
== target_type
)
1448 return Child
.Reduce (inCheckedContext
, target_type
);
1451 public override Constant
ToType (Type type
, Location loc
)
1454 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1455 if (TypeManager
.IsEnumType (type
.UnderlyingSystemType
))
1458 if (type
.UnderlyingSystemType
!= Child
.Type
)
1459 Child
= Child
.ToType (type
.UnderlyingSystemType
, loc
);
1463 if (!Convert
.ImplicitStandardConversionExists (this, type
)){
1464 Error_ValueCannotBeConverted (loc
, type
, false);
1468 return Child
.ToType (type
, loc
);
1474 /// This kind of cast is used to encapsulate Value Types in objects.
1476 /// The effect of it is to box the value type emitted by the previous
1479 public class BoxedCast
: EmptyCast
{
1481 public BoxedCast (Expression expr
, Type target_type
)
1482 : base (expr
, target_type
)
1484 eclass
= ExprClass
.Value
;
1487 public override Expression
DoResolve (EmitContext ec
)
1489 // This should never be invoked, we are born in fully
1490 // initialized state.
1495 public override void Emit (EmitContext ec
)
1499 ec
.ig
.Emit (OpCodes
.Box
, child
.Type
);
1503 public class UnboxCast
: EmptyCast
{
1504 public UnboxCast (Expression expr
, Type return_type
)
1505 : base (expr
, return_type
)
1509 public override Expression
DoResolve (EmitContext ec
)
1511 // This should never be invoked, we are born in fully
1512 // initialized state.
1517 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
1519 if (right_side
== EmptyExpression
.LValueMemberAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
)
1520 Report
.Error (445, loc
, "Cannot modify the result of an unboxing conversion");
1521 return base.DoResolveLValue (ec
, right_side
);
1524 public override void Emit (EmitContext ec
)
1527 ILGenerator ig
= ec
.ig
;
1530 ig
.Emit (OpCodes
.Unbox
, t
);
1532 LoadFromPtr (ig
, t
);
1537 /// This is used to perform explicit numeric conversions.
1539 /// Explicit numeric conversions might trigger exceptions in a checked
1540 /// context, so they should generate the conv.ovf opcodes instead of
1543 public class ConvCast
: EmptyCast
{
1544 public enum Mode
: byte {
1545 I1_U1
, I1_U2
, I1_U4
, I1_U8
, I1_CH
,
1547 I2_I1
, I2_U1
, I2_U2
, I2_U4
, I2_U8
, I2_CH
,
1548 U2_I1
, U2_U1
, U2_I2
, U2_CH
,
1549 I4_I1
, I4_U1
, I4_I2
, I4_U2
, I4_U4
, I4_U8
, I4_CH
,
1550 U4_I1
, U4_U1
, U4_I2
, U4_U2
, U4_I4
, U4_CH
,
1551 I8_I1
, I8_U1
, I8_I2
, I8_U2
, I8_I4
, I8_U4
, I8_U8
, I8_CH
,
1552 U8_I1
, U8_U1
, U8_I2
, U8_U2
, U8_I4
, U8_U4
, U8_I8
, U8_CH
,
1553 CH_I1
, CH_U1
, CH_I2
,
1554 R4_I1
, R4_U1
, R4_I2
, R4_U2
, R4_I4
, R4_U4
, R4_I8
, R4_U8
, R4_CH
,
1555 R8_I1
, R8_U1
, R8_I2
, R8_U2
, R8_I4
, R8_U4
, R8_I8
, R8_U8
, R8_CH
, R8_R4
1560 public ConvCast (Expression child
, Type return_type
, Mode m
)
1561 : base (child
, return_type
)
1566 public override Expression
DoResolve (EmitContext ec
)
1568 // This should never be invoked, we are born in fully
1569 // initialized state.
1574 public override string ToString ()
1576 return String
.Format ("ConvCast ({0}, {1})", mode
, child
);
1579 public override void Emit (EmitContext ec
)
1581 ILGenerator ig
= ec
.ig
;
1587 case Mode
.I1_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1588 case Mode
.I1_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1589 case Mode
.I1_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1590 case Mode
.I1_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1591 case Mode
.I1_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1593 case Mode
.U1_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1594 case Mode
.U1_CH
: /* nothing */ break;
1596 case Mode
.I2_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1597 case Mode
.I2_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1598 case Mode
.I2_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1599 case Mode
.I2_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1600 case Mode
.I2_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1601 case Mode
.I2_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1603 case Mode
.U2_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1604 case Mode
.U2_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1605 case Mode
.U2_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1606 case Mode
.U2_CH
: /* nothing */ break;
1608 case Mode
.I4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1609 case Mode
.I4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1610 case Mode
.I4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1611 case Mode
.I4_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1612 case Mode
.I4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1613 case Mode
.I4_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1614 case Mode
.I4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1616 case Mode
.U4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1617 case Mode
.U4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1618 case Mode
.U4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1619 case Mode
.U4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1620 case Mode
.U4_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4_Un
); break;
1621 case Mode
.U4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1623 case Mode
.I8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1624 case Mode
.I8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1625 case Mode
.I8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1626 case Mode
.I8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1627 case Mode
.I8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1628 case Mode
.I8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1629 case Mode
.I8_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1630 case Mode
.I8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1632 case Mode
.U8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1633 case Mode
.U8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1634 case Mode
.U8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1635 case Mode
.U8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1636 case Mode
.U8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4_Un
); break;
1637 case Mode
.U8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4_Un
); break;
1638 case Mode
.U8_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8_Un
); break;
1639 case Mode
.U8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1641 case Mode
.CH_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1642 case Mode
.CH_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1643 case Mode
.CH_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1645 case Mode
.R4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1646 case Mode
.R4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1647 case Mode
.R4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1648 case Mode
.R4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1649 case Mode
.R4_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1650 case Mode
.R4_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1651 case Mode
.R4_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8
); break;
1652 case Mode
.R4_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1653 case Mode
.R4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1655 case Mode
.R8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1656 case Mode
.R8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1657 case Mode
.R8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1658 case Mode
.R8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1659 case Mode
.R8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1660 case Mode
.R8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1661 case Mode
.R8_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8
); break;
1662 case Mode
.R8_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1663 case Mode
.R8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1664 case Mode
.R8_R4
: ig
.Emit (OpCodes
.Conv_R4
); break;
1668 case Mode
.I1_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1669 case Mode
.I1_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1670 case Mode
.I1_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1671 case Mode
.I1_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1672 case Mode
.I1_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1674 case Mode
.U1_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1675 case Mode
.U1_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1677 case Mode
.I2_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1678 case Mode
.I2_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1679 case Mode
.I2_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1680 case Mode
.I2_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1681 case Mode
.I2_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1682 case Mode
.I2_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1684 case Mode
.U2_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1685 case Mode
.U2_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1686 case Mode
.U2_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1687 case Mode
.U2_CH
: /* nothing */ break;
1689 case Mode
.I4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1690 case Mode
.I4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1691 case Mode
.I4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1692 case Mode
.I4_U4
: /* nothing */ break;
1693 case Mode
.I4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1694 case Mode
.I4_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1695 case Mode
.I4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1697 case Mode
.U4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1698 case Mode
.U4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1699 case Mode
.U4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1700 case Mode
.U4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1701 case Mode
.U4_I4
: /* nothing */ break;
1702 case Mode
.U4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1704 case Mode
.I8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1705 case Mode
.I8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1706 case Mode
.I8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1707 case Mode
.I8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1708 case Mode
.I8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
1709 case Mode
.I8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1710 case Mode
.I8_U8
: /* nothing */ break;
1711 case Mode
.I8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1713 case Mode
.U8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1714 case Mode
.U8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1715 case Mode
.U8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1716 case Mode
.U8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1717 case Mode
.U8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
1718 case Mode
.U8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1719 case Mode
.U8_I8
: /* nothing */ break;
1720 case Mode
.U8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1722 case Mode
.CH_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1723 case Mode
.CH_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1724 case Mode
.CH_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1726 case Mode
.R4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1727 case Mode
.R4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1728 case Mode
.R4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1729 case Mode
.R4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1730 case Mode
.R4_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
1731 case Mode
.R4_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1732 case Mode
.R4_I8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1733 case Mode
.R4_U8
: ig
.Emit (OpCodes
.Conv_U8
); break;
1734 case Mode
.R4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1736 case Mode
.R8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1737 case Mode
.R8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1738 case Mode
.R8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1739 case Mode
.R8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1740 case Mode
.R8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
1741 case Mode
.R8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1742 case Mode
.R8_I8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1743 case Mode
.R8_U8
: ig
.Emit (OpCodes
.Conv_U8
); break;
1744 case Mode
.R8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1745 case Mode
.R8_R4
: ig
.Emit (OpCodes
.Conv_R4
); break;
1751 public class OpcodeCast
: EmptyCast
{
1755 public OpcodeCast (Expression child
, Type return_type
, OpCode op
)
1756 : base (child
, return_type
)
1760 second_valid
= false;
1763 public OpcodeCast (Expression child
, Type return_type
, OpCode op
, OpCode op2
)
1764 : base (child
, return_type
)
1769 second_valid
= true;
1772 public override Expression
DoResolve (EmitContext ec
)
1774 // This should never be invoked, we are born in fully
1775 // initialized state.
1780 public override void Emit (EmitContext ec
)
1791 /// This kind of cast is used to encapsulate a child and cast it
1792 /// to the class requested
1794 public class ClassCast
: EmptyCast
{
1795 public ClassCast (Expression child
, Type return_type
)
1796 : base (child
, return_type
)
1801 public override Expression
DoResolve (EmitContext ec
)
1803 // This should never be invoked, we are born in fully
1804 // initialized state.
1809 public override void Emit (EmitContext ec
)
1813 ec
.ig
.Emit (OpCodes
.Castclass
, type
);
1819 /// SimpleName expressions are formed of a single word and only happen at the beginning
1820 /// of a dotted-name.
1822 public class SimpleName
: Expression
{
1826 public SimpleName (string name
, Location l
)
1832 public static void Error_ObjectRefRequired (EmitContext ec
, Location l
, string name
)
1834 if (ec
.IsFieldInitializer
)
1835 Report
.Error (236, l
,
1836 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1839 if (name
.LastIndexOf ('.') > 0)
1840 name
= name
.Substring (name
.LastIndexOf ('.') + 1);
1843 120, l
, "`{0}': An object reference is required for the nonstatic field, method or property",
1848 public bool IdenticalNameAndTypeName (EmitContext ec
, Expression resolved_to
, Location loc
)
1850 return resolved_to
!= null && resolved_to
.Type
!= null &&
1851 resolved_to
.Type
.Name
== Name
&&
1852 (ec
.DeclContainer
.LookupType (Name
, loc
, /* ignore_cs0104 = */ true) != null);
1855 public override Expression
DoResolve (EmitContext ec
)
1857 return SimpleNameResolve (ec
, null, false);
1860 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
1862 return SimpleNameResolve (ec
, right_side
, false);
1866 public Expression
DoResolve (EmitContext ec
, bool intermediate
)
1868 return SimpleNameResolve (ec
, null, intermediate
);
1871 public override FullNamedExpression
ResolveAsTypeStep (IResolveContext ec
, bool silent
)
1873 int errors
= Report
.Errors
;
1874 FullNamedExpression fne
= ec
.DeclContainer
.LookupType (Name
, loc
, /*ignore_cs0104=*/ false);
1878 if (silent
|| errors
!= Report
.Errors
)
1881 MemberCore mc
= ec
.DeclContainer
.GetDefinition (Name
);
1883 Error_UnexpectedKind (ec
.DeclContainer
, "type", GetMemberType (mc
), loc
);
1887 string ns
= ec
.DeclContainer
.NamespaceEntry
.NS
.Name
;
1888 string fullname
= (ns
.Length
> 0) ? ns
+ "." + Name
: Name
;
1889 foreach (Assembly a
in RootNamespace
.Global
.Assemblies
) {
1890 Type type
= a
.GetType (fullname
);
1892 Report
.SymbolRelatedToPreviousError (type
);
1893 Expression
.ErrorIsInaccesible (loc
, fullname
);
1898 NamespaceEntry
.Error_NamespaceNotFound (loc
, Name
);
1902 // TODO: I am still not convinced about this. If someone else will need it
1903 // implement this as virtual property in MemberCore hierarchy
1904 string GetMemberType (MemberCore mc
)
1906 if (mc
is PropertyBase
)
1910 if (mc
is FieldBase
)
1912 if (mc
is MethodCore
)
1914 if (mc
is EnumMember
)
1920 Expression
SimpleNameResolve (EmitContext ec
, Expression right_side
, bool intermediate
)
1926 Expression e
= DoSimpleNameResolve (ec
, right_side
, intermediate
);
1930 if (ec
.CurrentBlock
== null || ec
.CurrentBlock
.CheckInvariantMeaningInBlock (Name
, e
, Location
))
1937 /// 7.5.2: Simple Names.
1939 /// Local Variables and Parameters are handled at
1940 /// parse time, so they never occur as SimpleNames.
1942 /// The `intermediate' flag is used by MemberAccess only
1943 /// and it is used to inform us that it is ok for us to
1944 /// avoid the static check, because MemberAccess might end
1945 /// up resolving the Name as a Type name and the access as
1946 /// a static type access.
1948 /// ie: Type Type; .... { Type.GetType (""); }
1950 /// Type is both an instance variable and a Type; Type.GetType
1951 /// is the static method not an instance method of type.
1953 Expression
DoSimpleNameResolve (EmitContext ec
, Expression right_side
, bool intermediate
)
1955 Expression e
= null;
1958 // Stage 1: Performed by the parser (binding to locals or parameters).
1960 Block current_block
= ec
.CurrentBlock
;
1961 if (current_block
!= null){
1962 LocalInfo vi
= current_block
.GetLocalInfo (Name
);
1964 LocalVariableReference
var = new LocalVariableReference (ec
.CurrentBlock
, Name
, loc
);
1965 if (right_side
!= null) {
1966 return var.ResolveLValue (ec
, right_side
, loc
);
1968 ResolveFlags rf
= ResolveFlags
.VariableOrValue
;
1970 rf
|= ResolveFlags
.DisableFlowAnalysis
;
1971 return var.Resolve (ec
, rf
);
1975 ParameterReference pref
= current_block
.Toplevel
.GetParameterReference (Name
, loc
);
1977 if (right_side
!= null)
1978 return pref
.ResolveLValue (ec
, right_side
, loc
);
1980 return pref
.Resolve (ec
);
1985 // Stage 2: Lookup members
1988 DeclSpace lookup_ds
= ec
.DeclContainer
;
1989 Type almost_matched_type
= null;
1990 ArrayList almost_matched
= null;
1992 if (lookup_ds
.TypeBuilder
== null)
1995 e
= MemberLookup (ec
.ContainerType
, lookup_ds
.TypeBuilder
, Name
, loc
);
1999 if (almost_matched
== null && almostMatchedMembers
.Count
> 0) {
2000 almost_matched_type
= lookup_ds
.TypeBuilder
;
2001 almost_matched
= (ArrayList
) almostMatchedMembers
.Clone ();
2004 lookup_ds
=lookup_ds
.Parent
;
2005 } while (lookup_ds
!= null);
2007 if (e
== null && ec
.ContainerType
!= null)
2008 e
= MemberLookup (ec
.ContainerType
, ec
.ContainerType
, Name
, loc
);
2011 if (almost_matched
== null && almostMatchedMembers
.Count
> 0) {
2012 almost_matched_type
= ec
.ContainerType
;
2013 almost_matched
= (ArrayList
) almostMatchedMembers
.Clone ();
2015 e
= ResolveAsTypeStep (ec
, true);
2019 if (almost_matched
!= null)
2020 almostMatchedMembers
= almost_matched
;
2021 if (almost_matched_type
== null)
2022 almost_matched_type
= ec
.ContainerType
;
2023 MemberLookupFailed (ec
.ContainerType
, null, almost_matched_type
, ((SimpleName
) this).Name
, ec
.DeclContainer
.Name
, true, loc
);
2030 if (e
is MemberExpr
) {
2031 MemberExpr me
= (MemberExpr
) e
;
2034 if (me
.IsInstance
) {
2035 if (ec
.IsStatic
|| ec
.IsFieldInitializer
) {
2037 // Note that an MemberExpr can be both IsInstance and IsStatic.
2038 // An unresolved MethodGroupExpr can contain both kinds of methods
2039 // and each predicate is true if the MethodGroupExpr contains
2040 // at least one of that kind of method.
2044 (!intermediate
|| !IdenticalNameAndTypeName (ec
, me
, loc
))) {
2045 Error_ObjectRefRequired (ec
, loc
, me
.GetSignatureForError ());
2046 return EmptyExpression
.Null
;
2050 // Pass the buck to MemberAccess and Invocation.
2052 left
= EmptyExpression
.Null
;
2054 left
= ec
.GetThis (loc
);
2057 left
= new TypeExpression (ec
.ContainerType
, loc
);
2060 e
= me
.ResolveMemberAccess (ec
, left
, loc
, null);
2064 me
= e
as MemberExpr
;
2069 TypeManager
.IsNestedFamilyAccessible (me
.InstanceExpression
.Type
, me
.DeclaringType
) &&
2070 me
.InstanceExpression
.Type
!= me
.DeclaringType
&&
2071 !me
.InstanceExpression
.Type
.IsSubclassOf (me
.DeclaringType
) &&
2072 (!intermediate
|| !IdenticalNameAndTypeName (ec
, e
, loc
))) {
2073 Report
.Error (38, loc
, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2074 TypeManager
.CSharpName (me
.DeclaringType
), TypeManager
.CSharpName (me
.InstanceExpression
.Type
));
2078 return (right_side
!= null)
2079 ? me
.DoResolveLValue (ec
, right_side
)
2080 : me
.DoResolve (ec
);
2086 public override void Emit (EmitContext ec
)
2089 // If this is ever reached, then we failed to
2090 // find the name as a namespace
2093 Error (103, "The name `" + Name
+
2094 "' does not exist in the class `" +
2095 ec
.DeclContainer
.Name
+ "'");
2098 public override string ToString ()
2103 public override string GetSignatureForError ()
2110 /// Represents a namespace or a type. The name of the class was inspired by
2111 /// section 10.8.1 (Fully Qualified Names).
2113 public abstract class FullNamedExpression
: Expression
{
2114 public override FullNamedExpression
ResolveAsTypeStep (IResolveContext ec
, bool silent
)
2119 public abstract string FullName
{
2125 /// Expression that evaluates to a type
2127 public abstract class TypeExpr
: FullNamedExpression
{
2128 override public FullNamedExpression
ResolveAsTypeStep (IResolveContext ec
, bool silent
)
2130 TypeExpr t
= DoResolveAsTypeStep (ec
);
2134 eclass
= ExprClass
.Type
;
2138 override public Expression
DoResolve (EmitContext ec
)
2140 return ResolveAsTypeTerminal (ec
, false);
2143 override public void Emit (EmitContext ec
)
2145 throw new Exception ("Should never be called");
2148 public virtual bool CheckAccessLevel (DeclSpace ds
)
2150 return ds
.CheckAccessLevel (Type
);
2153 public virtual bool AsAccessible (DeclSpace ds
, int flags
)
2155 return ds
.AsAccessible (Type
, flags
);
2158 public virtual bool IsClass
{
2159 get { return Type.IsClass; }
2162 public virtual bool IsValueType
{
2163 get { return Type.IsValueType; }
2166 public virtual bool IsInterface
{
2167 get { return Type.IsInterface; }
2170 public virtual bool IsSealed
{
2171 get { return Type.IsSealed; }
2174 public virtual bool CanInheritFrom ()
2176 if (Type
== TypeManager
.enum_type
||
2177 (Type
== TypeManager
.value_type
&& RootContext
.StdLib
) ||
2178 Type
== TypeManager
.multicast_delegate_type
||
2179 Type
== TypeManager
.delegate_type
||
2180 Type
== TypeManager
.array_type
)
2186 protected abstract TypeExpr
DoResolveAsTypeStep (IResolveContext ec
);
2188 public abstract string Name
{
2192 public override bool Equals (object obj
)
2194 TypeExpr tobj
= obj
as TypeExpr
;
2198 return Type
== tobj
.Type
;
2201 public override int GetHashCode ()
2203 return Type
.GetHashCode ();
2206 public override string ToString ()
2213 /// Fully resolved Expression that already evaluated to a type
2215 public class TypeExpression
: TypeExpr
{
2216 public TypeExpression (Type t
, Location l
)
2219 eclass
= ExprClass
.Type
;
2223 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
2228 public override TypeExpr
ResolveAsTypeTerminal (IResolveContext ec
, bool silent
)
2233 public override string Name
{
2234 get { return Type.ToString (); }
2237 public override string FullName
{
2238 get { return Type.FullName; }
2243 /// Used to create types from a fully qualified name. These are just used
2244 /// by the parser to setup the core types. A TypeLookupExpression is always
2245 /// classified as a type.
2247 public sealed class TypeLookupExpression
: TypeExpr
{
2248 readonly string name
;
2250 public TypeLookupExpression (string name
)
2253 eclass
= ExprClass
.Type
;
2256 public override TypeExpr
ResolveAsTypeTerminal (IResolveContext ec
, bool silent
)
2258 // It's null for corlib compilation only
2260 return DoResolveAsTypeStep (ec
);
2265 static readonly char [] dot_array
= { '.' }
;
2266 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
2268 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2270 string lookup_name
= name
;
2271 int pos
= name
.IndexOf ('.');
2273 rest
= name
.Substring (pos
+ 1);
2274 lookup_name
= name
.Substring (0, pos
);
2277 FullNamedExpression resolved
= RootNamespace
.Global
.Lookup (ec
.DeclContainer
, lookup_name
, Location
.Null
);
2279 if (resolved
!= null && rest
!= null) {
2280 // Now handle the rest of the the name.
2281 string [] elements
= rest
.Split (dot_array
);
2283 int count
= elements
.Length
;
2285 while (i
< count
&& resolved
!= null && resolved
is Namespace
) {
2286 Namespace ns
= resolved
as Namespace
;
2287 element
= elements
[i
++];
2288 lookup_name
+= "." + element
;
2289 resolved
= ns
.Lookup (ec
.DeclContainer
, element
, Location
.Null
);
2292 if (resolved
!= null && resolved
is TypeExpr
) {
2293 Type t
= ((TypeExpr
) resolved
).Type
;
2295 if (!ec
.DeclContainer
.CheckAccessLevel (t
)) {
2297 lookup_name
= t
.FullName
;
2304 t
= TypeManager
.GetNestedType (t
, elements
[i
++]);
2309 if (resolved
== null) {
2310 NamespaceEntry
.Error_NamespaceNotFound (loc
, lookup_name
);
2314 if (!(resolved
is TypeExpr
)) {
2315 resolved
.Error_UnexpectedKind (ec
.DeclContainer
, "type", loc
);
2319 type
= resolved
.Type
;
2323 public override string Name
{
2324 get { return name; }
2327 public override string FullName
{
2328 get { return name; }
2332 public class TypeAliasExpression
: TypeExpr
{
2335 public TypeAliasExpression (TypeExpr texpr
, Location l
)
2338 loc
= texpr
.Location
;
2340 eclass
= ExprClass
.Type
;
2343 public override string Name
{
2344 get { return texpr.Name; }
2347 public override string FullName
{
2348 get { return texpr.FullName; }
2351 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
2356 public override bool CheckAccessLevel (DeclSpace ds
)
2358 return texpr
.CheckAccessLevel (ds
);
2361 public override bool AsAccessible (DeclSpace ds
, int flags
)
2363 return texpr
.AsAccessible (ds
, flags
);
2366 public override bool IsClass
{
2367 get { return texpr.IsClass; }
2370 public override bool IsValueType
{
2371 get { return texpr.IsValueType; }
2374 public override bool IsInterface
{
2375 get { return texpr.IsInterface; }
2378 public override bool IsSealed
{
2379 get { return texpr.IsSealed; }
2384 /// This class denotes an expression which evaluates to a member
2385 /// of a struct or a class.
2387 public abstract class MemberExpr
: Expression
2390 /// The name of this member.
2392 public abstract string Name
{
2397 /// Whether this is an instance member.
2399 public abstract bool IsInstance
{
2404 /// Whether this is a static member.
2406 public abstract bool IsStatic
{
2411 /// The type which declares this member.
2413 public abstract Type DeclaringType
{
2418 /// The instance expression associated with this member, if it's a
2419 /// non-static member.
2421 public Expression InstanceExpression
;
2423 public static void error176 (Location loc
, string name
)
2425 Report
.Error (176, loc
, "Static member `{0}' cannot be accessed " +
2426 "with an instance reference, qualify it with a type name instead", name
);
2429 // TODO: possible optimalization
2430 // Cache resolved constant result in FieldBuilder <-> expression map
2431 public virtual Expression
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
,
2432 SimpleName original
)
2436 // original == null || original.Resolve (...) ==> left
2439 if (left
is TypeExpr
) {
2441 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
2449 if (original
!= null && original
.IdenticalNameAndTypeName (ec
, left
, loc
))
2452 error176 (loc
, GetSignatureForError ());
2456 InstanceExpression
= left
;
2461 protected void EmitInstance (EmitContext ec
, bool prepare_for_load
)
2466 if (InstanceExpression
== EmptyExpression
.Null
) {
2467 SimpleName
.Error_ObjectRefRequired (ec
, loc
, Name
);
2471 if (InstanceExpression
.Type
.IsValueType
) {
2472 if (InstanceExpression
is IMemoryLocation
) {
2473 ((IMemoryLocation
) InstanceExpression
).AddressOf (ec
, AddressOp
.LoadStore
);
2475 LocalTemporary t
= new LocalTemporary (InstanceExpression
.Type
);
2476 InstanceExpression
.Emit (ec
);
2478 t
.AddressOf (ec
, AddressOp
.Store
);
2481 InstanceExpression
.Emit (ec
);
2483 if (prepare_for_load
)
2484 ec
.ig
.Emit (OpCodes
.Dup
);
2489 /// MethodGroup Expression.
2491 /// This is a fully resolved expression that evaluates to a type
2493 public class MethodGroupExpr
: MemberExpr
{
2494 public MethodBase
[] Methods
;
2495 bool identical_type_name
= false;
2498 public MethodGroupExpr (MemberInfo
[] mi
, Location l
)
2500 Methods
= new MethodBase
[mi
.Length
];
2501 mi
.CopyTo (Methods
, 0);
2502 eclass
= ExprClass
.MethodGroup
;
2503 type
= TypeManager
.object_type
;
2507 public MethodGroupExpr (ArrayList list
, Location l
)
2509 Methods
= new MethodBase
[list
.Count
];
2512 list
.CopyTo (Methods
, 0);
2514 foreach (MemberInfo m
in list
){
2515 if (!(m
is MethodBase
)){
2516 Console
.WriteLine ("Name " + m
.Name
);
2517 Console
.WriteLine ("Found a: " + m
.GetType ().FullName
);
2524 eclass
= ExprClass
.MethodGroup
;
2525 type
= TypeManager
.object_type
;
2528 public override Type DeclaringType
{
2531 // The methods are arranged in this order:
2532 // derived type -> base type
2534 return Methods
[0].DeclaringType
;
2538 public bool IdenticalTypeName
{
2540 return identical_type_name
;
2544 identical_type_name
= value;
2548 public bool IsBase
{
2557 public override string GetSignatureForError ()
2559 return TypeManager
.CSharpSignature (Methods
[0]);
2562 public override string Name
{
2564 return Methods
[0].Name
;
2568 public override bool IsInstance
{
2570 foreach (MethodBase mb
in Methods
)
2578 public override bool IsStatic
{
2580 foreach (MethodBase mb
in Methods
)
2588 public override Expression
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
,
2589 SimpleName original
)
2591 if (!(left
is TypeExpr
) &&
2592 original
!= null && original
.IdenticalNameAndTypeName (ec
, left
, loc
))
2593 IdenticalTypeName
= true;
2595 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
2598 override public Expression
DoResolve (EmitContext ec
)
2601 InstanceExpression
= null;
2603 if (InstanceExpression
!= null) {
2604 InstanceExpression
= InstanceExpression
.DoResolve (ec
);
2605 if (InstanceExpression
== null)
2612 public void ReportUsageError ()
2614 Report
.Error (654, loc
, "Method `" + DeclaringType
+ "." +
2615 Name
+ "()' is referenced without parentheses");
2618 override public void Emit (EmitContext ec
)
2620 ReportUsageError ();
2623 bool RemoveMethods (bool keep_static
)
2625 ArrayList smethods
= new ArrayList ();
2627 foreach (MethodBase mb
in Methods
){
2628 if (mb
.IsStatic
== keep_static
)
2632 if (smethods
.Count
== 0)
2635 Methods
= new MethodBase
[smethods
.Count
];
2636 smethods
.CopyTo (Methods
, 0);
2642 /// Removes any instance methods from the MethodGroup, returns
2643 /// false if the resulting set is empty.
2645 public bool RemoveInstanceMethods ()
2647 return RemoveMethods (true);
2651 /// Removes any static methods from the MethodGroup, returns
2652 /// false if the resulting set is empty.
2654 public bool RemoveStaticMethods ()
2656 return RemoveMethods (false);
2661 /// Fully resolved expression that evaluates to a Field
2663 public class FieldExpr
: MemberExpr
, IAssignMethod
, IMemoryLocation
, IVariable
{
2664 public readonly FieldInfo FieldInfo
;
2665 VariableInfo variable_info
;
2667 LocalTemporary temp
;
2669 bool in_initializer
;
2671 public FieldExpr (FieldInfo fi
, Location l
, bool in_initializer
):
2674 this.in_initializer
= in_initializer
;
2677 public FieldExpr (FieldInfo fi
, Location l
)
2680 eclass
= ExprClass
.Variable
;
2681 type
= fi
.FieldType
;
2685 public override string Name
{
2687 return FieldInfo
.Name
;
2691 public override bool IsInstance
{
2693 return !FieldInfo
.IsStatic
;
2697 public override bool IsStatic
{
2699 return FieldInfo
.IsStatic
;
2703 public override Type DeclaringType
{
2705 return FieldInfo
.DeclaringType
;
2709 public override string GetSignatureForError ()
2711 return TypeManager
.GetFullNameSignature (FieldInfo
);
2714 public VariableInfo VariableInfo
{
2716 return variable_info
;
2720 public override Expression
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
,
2721 SimpleName original
)
2723 Type t
= FieldInfo
.FieldType
;
2725 if (FieldInfo
.IsLiteral
|| (FieldInfo
.IsInitOnly
&& t
== TypeManager
.decimal_type
)) {
2726 IConstant ic
= TypeManager
.GetConstant (FieldInfo
);
2728 if (FieldInfo
.IsLiteral
) {
2729 ic
= new ExternalConstant (FieldInfo
);
2731 ic
= ExternalConstant
.CreateDecimal (FieldInfo
);
2733 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
2736 TypeManager
.RegisterConstant (FieldInfo
, ic
);
2739 bool left_is_type
= left
is TypeExpr
;
2740 if (!left_is_type
&& (original
== null || !original
.IdenticalNameAndTypeName (ec
, left
, loc
))) {
2741 Report
.SymbolRelatedToPreviousError (FieldInfo
);
2742 error176 (loc
, TypeManager
.GetFullNameSignature (FieldInfo
));
2746 if (ic
.ResolveValue ()) {
2747 if (!ec
.IsInObsoleteScope
)
2748 ic
.CheckObsoleteness (loc
);
2754 if (t
.IsPointer
&& !ec
.InUnsafe
) {
2759 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
2762 override public Expression
DoResolve (EmitContext ec
)
2764 return DoResolve (ec
, false, false);
2767 Expression
DoResolve (EmitContext ec
, bool lvalue_instance
, bool out_access
)
2769 if (!FieldInfo
.IsStatic
){
2770 if (InstanceExpression
== null){
2772 // This can happen when referencing an instance field using
2773 // a fully qualified type expression: TypeName.InstanceField = xxx
2775 SimpleName
.Error_ObjectRefRequired (ec
, loc
, FieldInfo
.Name
);
2779 // Resolve the field's instance expression while flow analysis is turned
2780 // off: when accessing a field "a.b", we must check whether the field
2781 // "a.b" is initialized, not whether the whole struct "a" is initialized.
2783 if (lvalue_instance
) {
2784 bool old_do_flow_analysis
= ec
.DoFlowAnalysis
;
2785 ec
.DoFlowAnalysis
= false;
2786 Expression right_side
=
2787 out_access
? EmptyExpression
.LValueMemberOutAccess
: EmptyExpression
.LValueMemberAccess
;
2788 InstanceExpression
= InstanceExpression
.ResolveLValue (ec
, right_side
, loc
);
2789 ec
.DoFlowAnalysis
= old_do_flow_analysis
;
2791 ResolveFlags rf
= ResolveFlags
.VariableOrValue
| ResolveFlags
.DisableFlowAnalysis
;
2792 InstanceExpression
= InstanceExpression
.Resolve (ec
, rf
);
2795 if (InstanceExpression
== null)
2798 InstanceExpression
.CheckMarshalByRefAccess ();
2801 if (!in_initializer
&& !ec
.IsFieldInitializer
) {
2802 ObsoleteAttribute oa
;
2803 FieldBase f
= TypeManager
.GetField (FieldInfo
);
2805 if (!ec
.IsInObsoleteScope
)
2806 f
.CheckObsoleteness (loc
);
2808 // To be sure that type is external because we do not register generated fields
2809 } else if (!(FieldInfo
.DeclaringType
is TypeBuilder
)) {
2810 oa
= AttributeTester
.GetMemberObsoleteAttribute (FieldInfo
);
2812 AttributeTester
.Report_ObsoleteMessage (oa
, TypeManager
.GetFullNameSignature (FieldInfo
), loc
);
2816 AnonymousContainer am
= ec
.CurrentAnonymousMethod
;
2818 if (!FieldInfo
.IsStatic
){
2819 if (!am
.IsIterator
&& (ec
.TypeContainer
is Struct
)){
2820 Report
.Error (1673, loc
,
2821 "Anonymous methods inside structs cannot access instance members of `{0}'. Consider copying `{0}' to a local variable outside the anonymous method and using the local instead",
2825 if ((am
.ContainerAnonymousMethod
== null) && (InstanceExpression
is This
))
2826 ec
.CaptureField (this);
2830 // If the instance expression is a local variable or parameter.
2831 IVariable
var = InstanceExpression
as IVariable
;
2832 if ((var == null) || (var.VariableInfo
== null))
2835 VariableInfo vi
= var.VariableInfo
;
2836 if (!vi
.IsFieldAssigned (ec
, FieldInfo
.Name
, loc
))
2839 variable_info
= vi
.GetSubStruct (FieldInfo
.Name
);
2843 static readonly int [] codes
= {
2844 191, // instance, write access
2845 192, // instance, out access
2846 198, // static, write access
2847 199, // static, out access
2848 1648, // member of value instance, write access
2849 1649, // member of value instance, out access
2850 1650, // member of value static, write access
2851 1651 // member of value static, out access
2854 static readonly string [] msgs
= {
2855 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
2856 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
2857 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
2858 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
2859 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
2860 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
2861 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
2862 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
2865 // The return value is always null. Returning a value simplifies calling code.
2866 Expression
Report_AssignToReadonly (Expression right_side
)
2869 if (right_side
== EmptyExpression
.OutAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
)
2873 if (right_side
== EmptyExpression
.LValueMemberAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
)
2875 Report
.Error (codes
[i
], loc
, msgs
[i
], GetSignatureForError ());
2880 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
2882 IVariable
var = InstanceExpression
as IVariable
;
2883 if ((var != null) && (var.VariableInfo
!= null))
2884 var.VariableInfo
.SetFieldAssigned (ec
, FieldInfo
.Name
);
2886 bool lvalue_instance
= !FieldInfo
.IsStatic
&& FieldInfo
.DeclaringType
.IsValueType
;
2887 bool out_access
= right_side
== EmptyExpression
.OutAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
;
2889 Expression e
= DoResolve (ec
, lvalue_instance
, out_access
);
2894 FieldBase fb
= TypeManager
.GetField (FieldInfo
);
2898 if (FieldInfo
.IsInitOnly
) {
2899 // InitOnly fields can only be assigned in constructors or initializers
2900 if (!ec
.IsFieldInitializer
&& !ec
.IsConstructor
)
2901 return Report_AssignToReadonly (right_side
);
2903 if (ec
.IsConstructor
) {
2904 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
2905 if (ec
.ContainerType
!= FieldInfo
.DeclaringType
)
2906 return Report_AssignToReadonly (right_side
);
2907 // static InitOnly fields cannot be assigned-to in an instance constructor
2908 if (IsStatic
&& !ec
.IsStatic
)
2909 return Report_AssignToReadonly (right_side
);
2910 // instance constructors can't modify InitOnly fields of other instances of the same type
2911 if (!IsStatic
&& !(InstanceExpression
is This
))
2912 return Report_AssignToReadonly (right_side
);
2916 if (right_side
== EmptyExpression
.OutAccess
&&
2917 !IsStatic
&& !(InstanceExpression
is This
) && DeclaringType
.IsSubclassOf (TypeManager
.mbr_type
)) {
2918 Report
.SymbolRelatedToPreviousError (DeclaringType
);
2919 Report
.Warning (197, 1, loc
,
2920 "Passing `{0}' as ref or out or taking its address may cause a runtime exception because it is a field of a marshal-by-reference class",
2921 GetSignatureForError ());
2927 public override void CheckMarshalByRefAccess ()
2929 if (!IsStatic
&& Type
.IsValueType
&& !(InstanceExpression
is This
) && DeclaringType
.IsSubclassOf (TypeManager
.mbr_type
)) {
2930 Report
.SymbolRelatedToPreviousError (DeclaringType
);
2931 Report
.Warning (1690, 1, loc
, "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2932 GetSignatureForError ());
2936 public bool VerifyFixed ()
2938 IVariable variable
= InstanceExpression
as IVariable
;
2939 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
2940 // We defer the InstanceExpression check after the variable check to avoid a
2941 // separate null check on InstanceExpression.
2942 return variable
!= null && InstanceExpression
.Type
.IsValueType
&& variable
.VerifyFixed ();
2945 public override int GetHashCode ()
2947 return FieldInfo
.GetHashCode ();
2950 public override bool Equals (object obj
)
2952 FieldExpr fe
= obj
as FieldExpr
;
2956 if (FieldInfo
!= fe
.FieldInfo
)
2959 if (InstanceExpression
== null || fe
.InstanceExpression
== null)
2962 return InstanceExpression
.Equals (fe
.InstanceExpression
);
2965 public void Emit (EmitContext ec
, bool leave_copy
)
2967 ILGenerator ig
= ec
.ig
;
2968 bool is_volatile
= false;
2970 FieldBase f
= TypeManager
.GetField (FieldInfo
);
2972 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0)
2975 f
.SetMemberIsUsed ();
2978 if (FieldInfo
.IsStatic
){
2980 ig
.Emit (OpCodes
.Volatile
);
2982 ig
.Emit (OpCodes
.Ldsfld
, FieldInfo
);
2985 EmitInstance (ec
, false);
2988 ig
.Emit (OpCodes
.Volatile
);
2990 IFixedBuffer ff
= AttributeTester
.GetFixedBuffer (FieldInfo
);
2993 ig
.Emit (OpCodes
.Ldflda
, FieldInfo
);
2994 ig
.Emit (OpCodes
.Ldflda
, ff
.Element
);
2997 ig
.Emit (OpCodes
.Ldfld
, FieldInfo
);
3002 ec
.ig
.Emit (OpCodes
.Dup
);
3003 if (!FieldInfo
.IsStatic
) {
3004 temp
= new LocalTemporary (this.Type
);
3010 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
3012 FieldAttributes fa
= FieldInfo
.Attributes
;
3013 bool is_static
= (fa
& FieldAttributes
.Static
) != 0;
3014 bool is_readonly
= (fa
& FieldAttributes
.InitOnly
) != 0;
3015 ILGenerator ig
= ec
.ig
;
3016 prepared
= prepare_for_load
;
3018 if (is_readonly
&& !ec
.IsConstructor
){
3019 Report_AssignToReadonly (source
);
3023 EmitInstance (ec
, prepare_for_load
);
3027 ec
.ig
.Emit (OpCodes
.Dup
);
3028 if (!FieldInfo
.IsStatic
) {
3029 temp
= new LocalTemporary (this.Type
);
3034 if (FieldInfo
is FieldBuilder
){
3035 FieldBase f
= TypeManager
.GetField (FieldInfo
);
3037 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0)
3038 ig
.Emit (OpCodes
.Volatile
);
3045 ig
.Emit (OpCodes
.Stsfld
, FieldInfo
);
3047 ig
.Emit (OpCodes
.Stfld
, FieldInfo
);
3053 public override void Emit (EmitContext ec
)
3058 public void AddressOf (EmitContext ec
, AddressOp mode
)
3060 ILGenerator ig
= ec
.ig
;
3062 if (FieldInfo
is FieldBuilder
){
3063 FieldBase f
= TypeManager
.GetField (FieldInfo
);
3065 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0){
3066 Report
.Warning (420, 1, loc
, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3067 f
.GetSignatureForError ());
3071 if ((mode
& AddressOp
.Store
) != 0)
3073 if ((mode
& AddressOp
.Load
) != 0)
3074 f
.SetMemberIsUsed ();
3079 // Handle initonly fields specially: make a copy and then
3080 // get the address of the copy.
3083 if (FieldInfo
.IsInitOnly
){
3085 if (ec
.IsConstructor
){
3086 if (FieldInfo
.IsStatic
){
3098 local
= ig
.DeclareLocal (type
);
3099 ig
.Emit (OpCodes
.Stloc
, local
);
3100 ig
.Emit (OpCodes
.Ldloca
, local
);
3105 if (FieldInfo
.IsStatic
){
3106 ig
.Emit (OpCodes
.Ldsflda
, FieldInfo
);
3108 EmitInstance (ec
, false);
3109 ig
.Emit (OpCodes
.Ldflda
, FieldInfo
);
3115 // A FieldExpr whose address can not be taken
3117 public class FieldExprNoAddress
: FieldExpr
, IMemoryLocation
{
3118 public FieldExprNoAddress (FieldInfo fi
, Location loc
) : base (fi
, loc
)
3122 public new void AddressOf (EmitContext ec
, AddressOp mode
)
3124 Report
.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3129 /// Expression that evaluates to a Property. The Assign class
3130 /// might set the `Value' expression if we are in an assignment.
3132 /// This is not an LValue because we need to re-write the expression, we
3133 /// can not take data from the stack and store it.
3135 public class PropertyExpr
: MemberExpr
, IAssignMethod
{
3136 public readonly PropertyInfo PropertyInfo
;
3139 // This is set externally by the `BaseAccess' class
3142 MethodInfo getter
, setter
;
3147 LocalTemporary temp
;
3150 internal static PtrHashtable AccessorTable
= new PtrHashtable ();
3152 public PropertyExpr (Type containerType
, PropertyInfo pi
, Location l
)
3155 eclass
= ExprClass
.PropertyAccess
;
3159 type
= TypeManager
.TypeToCoreType (pi
.PropertyType
);
3161 ResolveAccessors (containerType
);
3164 public override string Name
{
3166 return PropertyInfo
.Name
;
3170 public override bool IsInstance
{
3176 public override bool IsStatic
{
3182 public override Type DeclaringType
{
3184 return PropertyInfo
.DeclaringType
;
3188 public override string GetSignatureForError ()
3190 return TypeManager
.GetFullNameSignature (PropertyInfo
);
3193 void FindAccessors (Type invocation_type
)
3195 const BindingFlags flags
= BindingFlags
.Public
| BindingFlags
.NonPublic
|
3196 BindingFlags
.Static
| BindingFlags
.Instance
|
3197 BindingFlags
.DeclaredOnly
;
3199 Type current
= PropertyInfo
.DeclaringType
;
3200 for (; current
!= null; current
= current
.BaseType
) {
3201 MemberInfo
[] group = TypeManager
.MemberLookup (
3202 invocation_type
, invocation_type
, current
,
3203 MemberTypes
.Property
, flags
, PropertyInfo
.Name
, null);
3208 if (group.Length
!= 1)
3209 // Oooops, can this ever happen ?
3212 PropertyInfo pi
= (PropertyInfo
) group [0];
3215 getter
= pi
.GetGetMethod (true);
3218 setter
= pi
.GetSetMethod (true);
3220 MethodInfo accessor
= getter
!= null ? getter
: setter
;
3222 if (!accessor
.IsVirtual
)
3228 // We also perform the permission checking here, as the PropertyInfo does not
3229 // hold the information for the accessibility of its setter/getter
3231 // TODO: can use TypeManager.GetProperty to boost performance
3232 void ResolveAccessors (Type containerType
)
3234 FindAccessors (containerType
);
3236 if (getter
!= null) {
3237 IMethodData md
= TypeManager
.GetMethod (getter
);
3239 md
.SetMemberIsUsed ();
3241 AccessorTable
[getter
] = PropertyInfo
;
3242 is_static
= getter
.IsStatic
;
3245 if (setter
!= null) {
3246 IMethodData md
= TypeManager
.GetMethod (setter
);
3248 md
.SetMemberIsUsed ();
3250 AccessorTable
[setter
] = PropertyInfo
;
3251 is_static
= setter
.IsStatic
;
3255 bool InstanceResolve (EmitContext ec
, bool lvalue_instance
, bool must_do_cs1540_check
)
3258 InstanceExpression
= null;
3262 if (InstanceExpression
== null) {
3263 SimpleName
.Error_ObjectRefRequired (ec
, loc
, PropertyInfo
.Name
);
3267 if (lvalue_instance
)
3268 InstanceExpression
= InstanceExpression
.ResolveLValue (ec
, EmptyExpression
.LValueMemberAccess
, loc
);
3270 InstanceExpression
= InstanceExpression
.DoResolve (ec
);
3271 if (InstanceExpression
== null)
3274 InstanceExpression
.CheckMarshalByRefAccess ();
3276 if (must_do_cs1540_check
&& InstanceExpression
!= EmptyExpression
.Null
&&
3277 InstanceExpression
.Type
!= ec
.ContainerType
&&
3278 ec
.ContainerType
.IsSubclassOf (PropertyInfo
.DeclaringType
) &&
3279 !InstanceExpression
.Type
.IsSubclassOf (ec
.ContainerType
)) {
3280 Error_CannotAccessProtected (loc
, PropertyInfo
, InstanceExpression
.Type
, ec
.ContainerType
);
3287 void Error_PropertyNotFound (MethodInfo mi
, bool getter
)
3289 // TODO: correctly we should compare arguments but it will lead to bigger changes
3290 if (mi
is MethodBuilder
) {
3291 Error_TypeDoesNotContainDefinition (loc
, PropertyInfo
.DeclaringType
, Name
);
3295 StringBuilder sig
= new StringBuilder (TypeManager
.CSharpName (mi
.DeclaringType
));
3297 ParameterData iparams
= TypeManager
.GetParameterData (mi
);
3298 sig
.Append (getter
? "get_" : "set_");
3300 sig
.Append (iparams
.GetSignatureForError ());
3302 Report
.SymbolRelatedToPreviousError (mi
);
3303 Report
.Error (1546, loc
, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3304 Name
, sig
.ToString ());
3307 override public Expression
DoResolve (EmitContext ec
)
3312 if (getter
!= null){
3313 if (TypeManager
.GetParameterData (getter
).Count
!= 0){
3314 Error_PropertyNotFound (getter
, true);
3319 if (getter
== null){
3321 // The following condition happens if the PropertyExpr was
3322 // created, but is invalid (ie, the property is inaccessible),
3323 // and we did not want to embed the knowledge about this in
3324 // the caller routine. This only avoids double error reporting.
3329 if (InstanceExpression
!= EmptyExpression
.Null
) {
3330 Report
.Error (154, loc
, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3331 TypeManager
.GetFullNameSignature (PropertyInfo
));
3336 bool must_do_cs1540_check
= false;
3337 if (getter
!= null &&
3338 !IsAccessorAccessible (ec
.ContainerType
, getter
, out must_do_cs1540_check
)) {
3339 PropertyBase
.PropertyMethod pm
= TypeManager
.GetMethod (getter
) as PropertyBase
.PropertyMethod
;
3340 if (pm
!= null && pm
.HasCustomAccessModifier
) {
3341 Report
.SymbolRelatedToPreviousError (pm
);
3342 Report
.Error (271, loc
, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3343 TypeManager
.CSharpSignature (getter
));
3346 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (getter
));
3350 if (!InstanceResolve (ec
, false, must_do_cs1540_check
))
3354 // Only base will allow this invocation to happen.
3356 if (IsBase
&& getter
.IsAbstract
) {
3357 Error_CannotCallAbstractBase (TypeManager
.GetFullNameSignature (PropertyInfo
));
3361 if (PropertyInfo
.PropertyType
.IsPointer
&& !ec
.InUnsafe
){
3371 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
3373 if (right_side
== EmptyExpression
.OutAccess
) {
3374 Report
.Error (206, loc
, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3375 GetSignatureForError ());
3379 if (right_side
== EmptyExpression
.LValueMemberAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
) {
3380 Report
.Error (1612, loc
, "Cannot modify the return value of `{0}' because it is not a variable",
3381 GetSignatureForError ());
3385 if (setter
== null){
3387 // The following condition happens if the PropertyExpr was
3388 // created, but is invalid (ie, the property is inaccessible),
3389 // and we did not want to embed the knowledge about this in
3390 // the caller routine. This only avoids double error reporting.
3394 Report
.Error (200, loc
, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3395 GetSignatureForError ());
3399 if (TypeManager
.GetParameterData (setter
).Count
!= 1){
3400 Error_PropertyNotFound (setter
, false);
3404 bool must_do_cs1540_check
;
3405 if (!IsAccessorAccessible (ec
.ContainerType
, setter
, out must_do_cs1540_check
)) {
3406 PropertyBase
.PropertyMethod pm
= TypeManager
.GetMethod (setter
) as PropertyBase
.PropertyMethod
;
3407 if (pm
!= null && pm
.HasCustomAccessModifier
) {
3408 Report
.SymbolRelatedToPreviousError (pm
);
3409 Report
.Error (272, loc
, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3410 TypeManager
.CSharpSignature (setter
));
3413 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (setter
));
3417 if (!InstanceResolve (ec
, PropertyInfo
.DeclaringType
.IsValueType
, must_do_cs1540_check
))
3421 // Only base will allow this invocation to happen.
3423 if (IsBase
&& setter
.IsAbstract
){
3424 Error_CannotCallAbstractBase (TypeManager
.GetFullNameSignature (PropertyInfo
));
3431 public override void Emit (EmitContext ec
)
3436 public void Emit (EmitContext ec
, bool leave_copy
)
3439 // Special case: length of single dimension array property is turned into ldlen
3441 if ((getter
== TypeManager
.system_int_array_get_length
) ||
3442 (getter
== TypeManager
.int_array_get_length
)){
3443 Type iet
= InstanceExpression
.Type
;
3446 // System.Array.Length can be called, but the Type does not
3447 // support invoking GetArrayRank, so test for that case first
3449 if (iet
!= TypeManager
.array_type
&& (iet
.GetArrayRank () == 1)) {
3451 EmitInstance (ec
, false);
3452 ec
.ig
.Emit (OpCodes
.Ldlen
);
3453 ec
.ig
.Emit (OpCodes
.Conv_I4
);
3458 Invocation
.EmitCall (ec
, IsBase
, IsStatic
, InstanceExpression
, getter
, null, loc
, prepared
, false);
3461 ec
.ig
.Emit (OpCodes
.Dup
);
3463 temp
= new LocalTemporary (this.Type
);
3470 // Implements the IAssignMethod interface for assignments
3472 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
3474 Expression my_source
= source
;
3476 prepared
= prepare_for_load
;
3481 ec
.ig
.Emit (OpCodes
.Dup
);
3483 temp
= new LocalTemporary (this.Type
);
3487 } else if (leave_copy
) {
3490 temp
= new LocalTemporary (this.Type
);
3496 ArrayList args
= new ArrayList (1);
3497 args
.Add (new Argument (my_source
, Argument
.AType
.Expression
));
3499 Invocation
.EmitCall (ec
, IsBase
, IsStatic
, InstanceExpression
, setter
, args
, loc
, false, prepared
);
3507 /// Fully resolved expression that evaluates to an Event
3509 public class EventExpr
: MemberExpr
{
3510 public readonly EventInfo EventInfo
;
3513 MethodInfo add_accessor
, remove_accessor
;
3515 public EventExpr (EventInfo ei
, Location loc
)
3519 eclass
= ExprClass
.EventAccess
;
3521 add_accessor
= TypeManager
.GetAddMethod (ei
);
3522 remove_accessor
= TypeManager
.GetRemoveMethod (ei
);
3524 if (add_accessor
.IsStatic
|| remove_accessor
.IsStatic
)
3527 if (EventInfo
is MyEventBuilder
){
3528 MyEventBuilder eb
= (MyEventBuilder
) EventInfo
;
3529 type
= eb
.EventType
;
3532 type
= EventInfo
.EventHandlerType
;
3535 public override string Name
{
3537 return EventInfo
.Name
;
3541 public override bool IsInstance
{
3547 public override bool IsStatic
{
3553 public override Type DeclaringType
{
3555 return EventInfo
.DeclaringType
;
3559 public override Expression
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
,
3560 SimpleName original
)
3563 // If the event is local to this class, we transform ourselves into a FieldExpr
3566 if (EventInfo
.DeclaringType
== ec
.ContainerType
||
3567 TypeManager
.IsNestedChildOf(ec
.ContainerType
, EventInfo
.DeclaringType
)) {
3568 MemberInfo mi
= TypeManager
.GetPrivateFieldOfEvent (EventInfo
);
3571 MemberExpr ml
= (MemberExpr
) ExprClassFromMemberInfo (ec
.ContainerType
, mi
, loc
);
3574 Report
.Error (-200, loc
, "Internal error!!");
3578 InstanceExpression
= null;
3580 return ml
.ResolveMemberAccess (ec
, left
, loc
, original
);
3584 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
3588 bool InstanceResolve (EmitContext ec
, bool must_do_cs1540_check
)
3591 InstanceExpression
= null;
3595 if (InstanceExpression
== null) {
3596 SimpleName
.Error_ObjectRefRequired (ec
, loc
, EventInfo
.Name
);
3600 InstanceExpression
= InstanceExpression
.DoResolve (ec
);
3601 if (InstanceExpression
== null)
3605 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3606 // However, in the Event case, we reported a CS0122 instead.
3608 if (must_do_cs1540_check
&& InstanceExpression
!= EmptyExpression
.Null
&&
3609 InstanceExpression
.Type
!= ec
.ContainerType
&&
3610 ec
.ContainerType
.IsSubclassOf (InstanceExpression
.Type
)) {
3611 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (EventInfo
));
3618 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
3620 return DoResolve (ec
);
3623 public override Expression
DoResolve (EmitContext ec
)
3625 bool must_do_cs1540_check
;
3626 if (!(IsAccessorAccessible (ec
.ContainerType
, add_accessor
, out must_do_cs1540_check
) &&
3627 IsAccessorAccessible (ec
.ContainerType
, remove_accessor
, out must_do_cs1540_check
))) {
3628 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (EventInfo
));
3632 if (!InstanceResolve (ec
, must_do_cs1540_check
))
3638 public override void Emit (EmitContext ec
)
3640 if (InstanceExpression
is This
)
3641 Report
.Error (79, loc
, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
3643 Report
.Error (70, loc
, "The event `{0}' can only appear on the left hand side of += or -= "+
3644 "(except on the defining type)", Name
);
3647 public override string GetSignatureForError ()
3649 return TypeManager
.CSharpSignature (EventInfo
);
3652 public void EmitAddOrRemove (EmitContext ec
, Expression source
)
3654 BinaryDelegate source_del
= (BinaryDelegate
) source
;
3655 Expression handler
= source_del
.Right
;
3657 Argument arg
= new Argument (handler
, Argument
.AType
.Expression
);
3658 ArrayList args
= new ArrayList ();
3662 if (source_del
.IsAddition
)
3663 Invocation
.EmitCall (
3664 ec
, false, IsStatic
, InstanceExpression
, add_accessor
, args
, loc
);
3666 Invocation
.EmitCall (
3667 ec
, false, IsStatic
, InstanceExpression
, remove_accessor
, args
, loc
);
3672 public class TemporaryVariable
: Expression
, IMemoryLocation
3676 public TemporaryVariable (Type type
, Location loc
)
3680 eclass
= ExprClass
.Value
;
3683 public override Expression
DoResolve (EmitContext ec
)
3688 TypeExpr te
= new TypeExpression (type
, loc
);
3689 li
= ec
.CurrentBlock
.AddTemporaryVariable (te
, loc
);
3690 if (!li
.Resolve (ec
))
3693 AnonymousContainer am
= ec
.CurrentAnonymousMethod
;
3694 if ((am
!= null) && am
.IsIterator
)
3695 ec
.CaptureVariable (li
);
3700 public override void Emit (EmitContext ec
)
3702 ILGenerator ig
= ec
.ig
;
3704 if (li
.FieldBuilder
!= null) {
3705 ig
.Emit (OpCodes
.Ldarg_0
);
3706 ig
.Emit (OpCodes
.Ldfld
, li
.FieldBuilder
);
3708 ig
.Emit (OpCodes
.Ldloc
, li
.LocalBuilder
);
3712 public void EmitLoadAddress (EmitContext ec
)
3714 ILGenerator ig
= ec
.ig
;
3716 if (li
.FieldBuilder
!= null) {
3717 ig
.Emit (OpCodes
.Ldarg_0
);
3718 ig
.Emit (OpCodes
.Ldflda
, li
.FieldBuilder
);
3720 ig
.Emit (OpCodes
.Ldloca
, li
.LocalBuilder
);
3724 public void Store (EmitContext ec
, Expression right_side
)
3726 if (li
.FieldBuilder
!= null)
3727 ec
.ig
.Emit (OpCodes
.Ldarg_0
);
3729 right_side
.Emit (ec
);
3730 if (li
.FieldBuilder
!= null) {
3731 ec
.ig
.Emit (OpCodes
.Stfld
, li
.FieldBuilder
);
3733 ec
.ig
.Emit (OpCodes
.Stloc
, li
.LocalBuilder
);
3737 public void EmitThis (EmitContext ec
)
3739 if (li
.FieldBuilder
!= null) {
3740 ec
.ig
.Emit (OpCodes
.Ldarg_0
);
3744 public void EmitStore (ILGenerator ig
)
3746 if (li
.FieldBuilder
!= null)
3747 ig
.Emit (OpCodes
.Stfld
, li
.FieldBuilder
);
3749 ig
.Emit (OpCodes
.Stloc
, li
.LocalBuilder
);
3752 public void AddressOf (EmitContext ec
, AddressOp mode
)
3754 EmitLoadAddress (ec
);